回滚必须基于镜像 digest而非 tag,因 kubectl rollout undo 依赖 revisionhistorylimit(默认10)且 revision 号会因非镜像变更跳变,也不记录 digest,易拉取被覆盖的同名 tag;应使用 kubectl set image + digest、ci 推送语义化标签并注入元数据、配合 readinessprobe 验证。

回滚必须基于镜像 digest,不是 tag
直接用 kubectl rollout undo 在生产环境大概率失效。它依赖 revisionHistoryLimit(默认 10),而 revision 号会因 configmap 更新、replicas 调整等非镜像变更跳变;更关键的是,它根本不记录镜像 digest——回滚后拉的可能是被覆盖过的同名 tag。
真正可信赖的回滚动作,必须锁定已构建、已验证的镜像 digest,例如 mysvc@sha256:abc123。CI 流水线每次成功构建后,必须推送带语义化标签的镜像(如 mysvc:v1.2.3),并用 --label 注入元数据:org.opencontainers.image.revision、dev.go.version、dev.build.date。
- 查当前运行镜像:
kubectl get deploy mysvc -o jsonpath='{.spec.template.spec.containers[0].image}' - 查历史 tag 对应的 digest:
docker pull myreg/mysvc:v1.1.0 && docker inspect myreg/mysvc:v1.1.0 | jq -r '.[0].RepoDigests[0]' - 强制切换镜像:
kubectl set image deploy/mysvc container-name=myreg/mysvc@sha256:abc123
用 clientset.AppsV1().Deployments().Rollback(),别碰 Update()
Go 客户端的 Rollback() 函数专为回滚设计,调用的是 /apis/apps/v1/namespaces/{ns}/deployments/{name}/rollback 这个 endpoint,底层做了 revision 校验和幂等性处理。误用 Update() 去改 Deployment.Spec.Image 会触发新 rollout,revision 号加一,旧版本可能被 GC 清理掉。
Rollback() 的第二个参数必须是 *appsv1.RollbackConfig,不是 *appsv1.Deployment。传错类型会报 422 错误:Invalid value: "xxx": rollbackConfig.name must match the name of the target resource。
-
RollbackConfig只需填三个字段:Name(Deployment 名)、Revision(int64类型,不是字符串)、UpdatedAnnotations(一般留空或设为map[string]string{}) - revision 编号不能硬写或递增推算,得从 ReplicaSet annotation 里查:
deployment.kubernetes.io/revision - 查询逻辑:先
clientset.AppsV1().ReplicaSets(ns).List()拿所有 RS,过滤ownerReferences匹配目标 Deployment 的那些,再遍历 annotations 提取 revision 并转成int64,按数值降序排
回滚后必须轮询 Deployment.Status.Conditions,不能只信 HTTP 200
Rollback() 调用返回成功,只代表请求已发给 apiserver,并不表示 Pod 已切回、就绪探针已通过、流量已恢复。常见错误是调完就认为完事,结果服务实际不可用。
必须轮询 Deployment.Status.Conditions,检查 Available 和 Progressing condition 的 Status 是否为 True,且 Reason 不是 ProgressDeadlineExceeded。同时确认 Deployment.Status.ObservedGeneration 等于当前 Generation。
- 轮询间隔建议 2–5 秒,超时设为 300 秒(5 分钟)足够覆盖大多数场景
- 不要只看
Deployment.Status.Replicas或ReadyReplicas,它们可能在探针失败前就更新了 - 如果 readinessProbe 配置不兼容(比如旧版没实现新字段
db_connected),回滚后 Pod 会卡在NotReady,必须提前验证探针路径和逻辑向后兼容
Golang 镜像必须静态编译 + 非 root 用户 + 监听 0.0.0.0
回滚失败的另一个隐蔽原因是镜像本身不可靠:动态链接、root 权限、监听地址写成 127.0.0.1,都会导致回滚后 Pod 启动但无法接收流量。
多阶段 Dockerfile 是底线:CGO_ENABLED=0 GOOS=linux go build 生成静态二进制,FROM scratch 或 alpine:latest 运行,用 USER 65532:65532 降权,EXPOSE 8080 并在 Go 代码中监听 0.0.0.0:8080。
- 忘了
EXPOSE或监听地址写错,Kubernetes Service 流量根本进不来,Pod 状态可能是 Running,但 readinessProbe 一直失败 - 没配
readinessProbe和livenessProbe,或者路径不存在(如只写了/却没暴露/readyz),回滚后 kubelet 无法判断健康状态,可能反复重启或持续转发故障流量 - Go 代码里要真实实现探针逻辑,比如
/readyz中检查 DB 连通性,且该逻辑在新旧版本间保持兼容
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











