滚动更新本质是更新Deployment的镜像字段并提交Update,由控制器创建新Pod、删除旧Pod;需显式配置RollingUpdate策略及合理的maxSurge/maxUnavailable,并确保readinessProbe真实反映服务就绪状态。

滚动更新不是改 Pod,而是换 Deployment 的镜像
你不能用 Go 直接“更新”一个正在运行的 Pod 的镜像——Kubernetes 不允许。Pod 是不可变的,所谓“滚动更新”,本质是让 Deployment 控制器创建一批新 Pod(带新镜像),再按策略删掉旧 Pod。Go SDK 要做的,就是触发这个控制器行为,而不是手动删 Pod 再建 Pod(那是“重新创建”,不是滚动)。
- 错误做法:
Delete旧Pod+Create新Pod:绕过 Deployment 控制器,丢失副本数保障、健康检查等待、批次控制等关键逻辑 - 正确路径:修改 Deployment 的
spec.template.spec.containers[0].image字段,然后Update整个 Deployment 对象 - 必须确保 Deployment 已启用滚动策略(默认就是,但别依赖“默认”,显式写出来更稳):
strategy.type: RollingUpdate
用 client-go 更新 Deployment 镜像的最小可靠写法
核心就三步:查 Deployment → 改镜像字段 → 提交 Update。别碰 ReplicaSet 或 Pod,全交给 Deployment 控制器。
- 先 Get 当前 Deployment:
clientset.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - 只改容器镜像(假设只有一个容器):
deployment.Spec.Template.Spec.Containers[0].Image = "myapp:v1.2.0" - 调用 Update:
clientset.AppsV1().Deployments(namespace).Update(ctx, deployment, metav1.UpdateOptions{}) - 注意:不要改
deployment.ResourceVersion,client-go 会自动处理;改了反而导致冲突错误409 Conflict
示例片段(省略 error 处理):
dep, _ := clientset.AppsV1().Deployments("default").Get(ctx, "myapp", metav1.GetOptions{})
dep.Spec.Template.Spec.Containers[0].Image = "myapp:v1.2.0"
_, _ = clientset.AppsV1().Deployments("default").Update(ctx, dep, metav1.UpdateOptions{})
为什么 maxSurge 和 maxUnavailable 必须设合理值?
这两个参数直接决定“逐个替换”是否真能逐个发生。它们不是可有可无的装饰字段,而是滚动更新节奏的刹车和油门。
立即学习“go语言免费学习笔记(深入)”;
-
maxSurge: 1:允许临时多跑 1 个 Pod(比如从 3→4),否则新 Pod 拉不起来就卡住 -
maxUnavailable: 1:保证任何时候至少有 2 个 Pod 在服务(3−1),避免流量断崖 - 设成
0?那更新会卡死:新 Pod 没 ready 前,旧 Pod 一个都不能删,而 readiness probe 不通过时,新 Pod 就不会 ready - 生产环境建议显式配置:
strategy.rollingUpdate.maxSurge: 25%和maxUnavailable: 25%,比固定数字更适配不同副本数
滚动中 Pod 老版本没退干净?先看 readiness probe 是否真生效
常见现象:新 Pod 已 Running,但旧 Pod 还挂着,Deployment 状态显示 Progressing 卡住。大概率不是代码或配置问题,而是探针没过。
- Kubernetes 默认只等
PodPhase == Running,但滚动更新实际依赖Ready == True(由 readiness probe 决定) - Go 服务务必暴露
/healthz或类似端点,并在 Deployment 中配好:readinessProbe.httpGet.path: "/healthz" - probe 失败日志藏在
kubectl describe pod <new-pod-name>的 Events 区域,不是kubectl logs - 本地调试时容易忽略 probe 超时设置:
initialDelaySeconds: 5太短,Go 服务启动慢(尤其加了 DB 连接池初始化),probe 就狂失败
滚动更新的“平滑”二字,一半靠控制器逻辑,另一半靠你的 probe 是否诚实反映服务真实就绪状态。这里出问题,其他所有配置都白搭。










