滚动更新必须修改Deployment的image字段触发控制器创建新ReplicaSet,而非手动删Pod;回滚须用Rollback() API查annotation获取准确revision,配好maxSurge、maxUnavailable、readinessProbe及SIGTERM处理。

滚动更新必须改 Deployment 的 image 字段,不是删 Pod
你不能用 Go 代码直接 Delete 旧 Pod 再 Create 新 Pod——这绕过 Deployment 控制器,会丢掉副本保障、健康检查等待、批次控制等关键逻辑。真正的滚动更新,是让控制器自己创建新 ReplicaSet 并按策略替换 Pod。
用 client-go 实现的最小可靠路径只有三步:
-
clientset.AppsV1().Deployments(ns).Get()获取当前 Deployment 对象 - 只改
deployment.Spec.Template.Spec.Containers[0].Image(假设单容器),其他字段不动 -
clientset.AppsV1().Deployments(ns).Update()提交变更,别碰ResourceVersion,client-go 会自动处理
漏掉 strategy.type: RollingUpdate 字段?虽然默认就是,但显式写出来更稳。不设它,或设成 Recreate,就不是滚动更新了。
回滚必须用 Rollback() API,别信 kubectl rollout undo
kubectl rollout undo 在生产环境极不可靠:revision 编号会因 configmap 更新、replicas 调整等非镜像变更而跳变;更致命的是它不记录镜像 digest,回滚后拉到的可能是被覆盖过的同名 tag。
立即学习“go语言免费学习笔记(深入)”;
Go 客户端应调用专为回滚设计的 REST 接口:
- 用
clientset.AppsV1().Deployments(ns).Rollback(),传入*appsv1.RollbackConfig -
RollbackConfig.Revision必须是int64类型,且得从历史 ReplicaSet 的 annotation 里查:deployment.kubernetes.io/revision - 别硬写或递增推算 revision —— ReplicaSet 可能已被 GC 清理,传错就失败
回滚不是“倒带”,而是触发新一轮滚动更新:控制器把 spec.template.spec.containers[].image 改回旧值,再走一遍 maxSurge/maxUnavailable 流程。
maxSurge 和 maxUnavailable 设错,滚动就卡住或断流
这两个参数不是可选项,是滚动节奏的实际刹车和油门:
-
maxSurge: 1允许临时多跑 1 个 Pod;设成 0?新 Pod 根本起不来, rollout 卡死 -
maxUnavailable: 1保证至少有replicas - 1个 Pod 在服务;设成 0 更安全,但更新慢 -
minReadySeconds: 10必须设:新 Pod 启动后至少等 10 秒才视为 ready,防缓存/连接池没预热完就被切流
不配 readinessProbe 或 probe 只返回 200 不查 DB/下游?新 Pod 会被误标就绪,流量进来就 panic——90% 的滚动失败根源在此。
Go 代码里 SIGTERM 处理不对,滚动就丢请求
Kubernetes 终止 Pod 时发的是 SIGTERM,不是 SIGKILL。没监听它,进程立刻退出,所有 HTTP 连接硬断开。
- 用
server.Shutdown(),不是server.Close();前者拒新连、等旧 handler 返回,后者暴力关 -
context.WithTimeout()超时时间必须小于 K8s 的terminationGracePeriodSeconds(比如设 30s,K8s 配 45s) -
Shutdown()不等后台 goroutine——handler 里启动的长任务必须手动通知停止并等待完成 - DB 连接池、Redis 客户端、日志句柄、定时上报 goroutine……这些都得在
Shutdown()前手动 close 或 sync
revisionHistoryLimit 没设、--record 没加、镜像用 latest 标签、探针逻辑随版本漂移——这些配置层的疏漏,比 Go 代码里的 bug 更难排查,也更容易导致回滚失效。


















