reconcile函数需严格分离“观测”与“执行”:先用listers或client.list获取真实状态,抽离差异判断逻辑,写操作仅在判定后执行一次;务必设置控制器引用、实时更新status.conditions(含type/status/reason/lasttransitiontime),避免并发覆盖;检查deployment的updatedreplicas和availablereplicas双指标,并加超时重试。

直接用 client-go 写脚本做自动化运维,不是“能不能”,而是“怎么避免掉坑里”。多数失败案例不是 API 调不通,而是状态没对齐、写操作没节制、错误没分级。
Reconcile 函数里别混着读和写
常见错误是把 client.Get、client.List 和 client.Create 全塞进一个 if 分支里,结果 Deployment 创建失败后反复重试,又没判断是否已存在,导致报 AlreadyExists 错误却卡死不动。
- 先用
listers(快)或client.List(准)拿真实状态,比如当前 Pod 数、ConfigMap 的resourceVersion - 把差异判断抽成独立函数,例如
needsRollout()返回bool, string,方便日志里直接看到 “reason: image digest mismatch” - 所有写操作(
client.Create、client.Update、client.Patch)必须放在判断之后,且只执行一次 - 记得调
controllerutil.SetControllerReference(),否则 CR 删除时关联资源不会被 GC
status.conditions 必须实时更新,不能只在最后写一次
Operator 没填 status,等于运维黑盒。你看到 kubectl get myservice 显示 Ready,其实它刚在拉镜像失败,只是 status 还没来得及更新。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 每完成一个关键步骤就调一次
updateStatusCondition(),比如从ApplyingConfig→ConfigApplied→PodsReady -
status.conditions字段必须含type、status(只能是"True"/"False"/"Unknown")、lastTransitionTime和reason - 别用
client.Status().Update()整体覆盖,先client.Get()拿当前status,再 patch 字段,防并发覆盖
轮询 Deployment 状态不能靠 sleep + for
Deployment 更新后,K8s 是异步生效的。dep.Status.UpdatedReplicas == *dep.Spec.Replicas 为真,不代表所有 Pod 都 Ready;漏掉 AvailableReplicas 判断,可能流量切过去就 503。
- 检查两个字段:
dep.Status.UpdatedReplicas(已更新副本数)和dep.Status.AvailableReplicas(就绪副本数)都等于*dep.Spec.Replicas - 加超时控制,建议 300 秒内,重试间隔 2–5 秒
- 失败时返回明确 error,比如
fmt.Errorf("deployment %s not ready after timeout: %d/%d available", dep.Name, dep.Status.AvailableReplicas, *dep.Spec.Replicas),上层可据此触发回滚 - 可选监听事件:
clientset.CoreV1().Events(ns).Watch(),过滤Warning类型,提前捕获ImagePullBackOff
Labels 和 selector 写错会导致静默失效
Deployment 的 spec.selector 和 template.metadata.labels 不一致,K8s 不报错,但新 Pod 永远不会被纳入 Service 流量——这是最常被忽略的“配置正确但不生效”问题。
- 用
labels.Set{"app.kubernetes.io/name": "myapp"}构造 selector,比手拼字符串可靠 - key 中带
/是合法的(domain-prefixed),但整个 key 必须小写;labels.Set{"App": "myapp"}会被转成小写,但 server 端存的是原始大小写,所以最好一开始就写小写 - 检查点:用
kubectl get deploy -o yaml看spec.selector.matchLabels和spec.template.metadata.labels是否完全一致
真正难的不是写完第一个 Reconcile,而是让 Operator 在 CR 多次变更、跨命名空间资源变动、网络抖动、etcd 延迟等现实条件下依然稳定收敛——这要求你把“观测”和“执行”彻底切开,把“失败”当成常态来设计重试和降级路径。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










