用 Ansible 管理 Kubernetes 资源时,k8s 模块看起来只是把 YAML 丢给 API,实际行为却比 kubectl apply 保守得多。下面这份笔记整理几个自己排查时踩过的问题,重点是判断风险、操作动作和验证方式,供类似场景对照。
先确认 state 与 namespace 的作用范围
当需要判断一个现有Kubernetes资源是否符合预期状态时,k8s模块的state参数是关键。如果state设置为present,模块会对比集群中的实际资源定义与传入的kubeconfig或manifest定义,发现差异时触发更新。检查方式上,可以在任务后添加register变量,再通过assert或debug打印resource对象的status字段,但要注意资源类型不同,status结构差异很大。常见坑是未指定namespace,导致模块默认使用当前kubeconfig上下文中的namespace,而manifest里又写了namespace,两者不一致时容易误判。
所以要养成习惯,在任务里同时指定 namespace 和 kubeconfig 路径,不要指望 manifest 里的 metadata 能覆盖所有情况。尤其是有多个集群上下文时,漏掉 namespace 可能让变更落到完全不同的环境。
resource_definition 比 src 更可控,但要注意未知字段
用Ansible管理Kubernetes资源时,建议每个任务显式传入kubeconfig路径,避免依赖环境变量。对于资源清单,优先使用k8s模块的resource_definition参数直接传递YAML内容,而不是依赖src文件,因为src读取是相对路径,容易因role或playbook执行目录不同出错。执行变更前,可以先加一个任务用k8s_info获取当前资源版本,再对比期望定义,这样能减少不必要的update请求。注意,k8s模块默认不会删除未知字段,如果旧资源有多余字段,不会自动清理。
这一点特别容易在迭代中出现:你删掉了清单里的一个 label 或 annotation,模块并不会把集群里已有的字段删掉。要处理配置漂移,要么在 playbook 里加一步 k8s_info 拿当前资源,用 diff 结果人工判断;要么定期做资源导出,把集群里的完整 manifest 和期望文件对比。
删除资源前先跑一次 check_mode
一个常见坑是在循环中动态生成多个资源时,没有注意k8s模块的name和namespace参数与resource_definition里的metadata重复。如果两者冲突,模块会报错。另一个更隐蔽的问题是,当使用k8s模块删除资源时,如果设置state=absent,但resource_definition里没有指定namespace,模块会尝试从当前上下文中解析,而上下文可能是集群管理员,导致删除错误命名空间下的资源。建议在删除任务中总是显式传递namespace,并且加上check_mode支持,先在check模式下验证删除目标是否正确。
删除任务单独写成一个小 playbook,执行时加 --check --diff,先看模块报告的 diff 里列出的资源路径。循环场景下,name 和 namespace 不要同时出现在参数和 resource_definition 里,统一用 item 传入。
用 k8s_info 验证结果,别用 kubectl 输出
验证k8s模块执行效果,除了依赖模块返回值,更可靠的方法是结合k8s_info查询资源状态。比如,创建ConfigMap后,用k8s_info过滤相同namespace和name,检查返回的items列表长度是否为1。对于Deployment,可以查询对应的ReplicaSet和Pod,判断可用副本数是否达到期望值。注意不要直接解析kubectl输出,因为模块不提供原生命令包装。如果需要在playbook中做断言,建议用query过滤器配合length过滤器,但要注意当资源不存在时,k8s_info返回空列表,length计算要放在条件判断之后,避免报错。
- name: 查询 ConfigMap
k8s_info:
api_version: v1
kind: ConfigMap
name: app-config
namespace: default
register: cm_result
- name: 断言资源存在
assert:
that:
- cm_result.resources | length == 1注意有些版本返回字段可能不叫 resources,实际以 Debug 输出为准。你可以加一个 debug: var=cm_result,先看结构再写断言。
wait 参数与配置漂移:k8s 模块的边界
使用k8s模块管理资源时,要清楚它只是对Kubernetes API的封装,不做kubectl apply那样的三路合并。默认策略是强制更新,意味着如果模板中省略了某个原有字段,模块不会去删除它,而是保留旧值,这可能导致配置漂移。在某些场景下,比如管理Deployment的replicas,模块会自动把期望副本数与当前状态对比,但如果手动用kubectl scale改过,再跑Ansible就会重置为模板值。另外,wait参数默认是false,如果你想等Pod变成Ready再继续,必须显式设置wait=true,否则模块在创建完Deployment后立即返回,后续任务可能拿到过时的状态。
所以,在编排多资源依赖时,比如先创建 ConfigMap 再创建 Deployment,最好在 Deployment 任务上写明 wait: true、wait_timeout: 30,再通过 k8s_info 轮询可用副本。如果只是管理一次性的 Job,wait 的作用更明显。记住,k8s 模块不做三路合并,需要精确控制增删字段时,自己对比或在特定场景用 kubectl apply --server-side。