应使用 kubernetes go 客户端的 rollback 方法(而非 update/patch)调用 /rollback endpoint 回滚,传入含 name、revision 的 v1.rollbackconfig;revision 需从 ownerreferences 关联的 replicaset annotation 中提取;回滚后须轮询 conditions 判断实际状态。

直接调用 kubectl rollout undo 不适合自动化
生产环境里靠手动敲 kubectl rollout undo deployment/myapp --to-revision=12 回滚,既不可审计也不可靠。CI/CD 流水线或运维脚本里必须走 Kubernetes REST API,否则无法捕获状态、做条件判断、集成审批流。
Go 客户端真正该用的是 Rollback 方法(注意不是 Update 或 Patch),它对应的是 /apis/apps/v1/namespaces/{ns}/deployments/{name}/rollback 这个 endpoint,底层封装了 revision 校验和幂等性处理。
- 别用
Update去改Deployment.Spec.Replicas或Image字段来回滚——这会生成新 revision,不是 rollback - 别自己拼 URL 调
POST /rollback:客户端已封装好Rollback函数,传入v1.RollbackConfig即可 - revision 编号不是递增 ID,而是由
deployment.kubernetes.io/revisionannotation 记录,必须从历史ReplicaSet列表里查出来
clientset.AppsV1().Deployments(ns).Rollback() 的参数陷阱
这个函数签名看着简单,但 Rollback 第二个参数是 *v1.RollbackConfig,不是 Deployment 对象。常见错误是传错结构体,导致 422 报错:Invalid value: "xxx": rollbackConfig.name must match the name of the target resource。
关键字段只有三个,其他留空:
立即学习“go语言免费学习笔记(深入)”;
-
Name:必须和目标 Deployment 名字完全一致(不是 ReplicaSet 名) -
UpdatedAnnotations:一般设为map[string]string{},除非你真要覆盖 annotation -
Revision:int64 类型,填你想回退到的 revision 号(比如 15),不是字符串
示例片段:
rollback := &appsv1.RollbackConfig{
Name: "myapp",
Revision: 15,
}
_, err := clientset.AppsV1().Deployments("prod").Rollback(context.TODO(), "myapp", rollback, metav1.RollbackOptions{})
怎么安全拿到可用的 revision 列表
Kubernetes 不提供“列出所有 deployment revision”的 API,得自己从 ReplicaSet 入手。每个 RS 都带 deployment.kubernetes.io/revision annotation,且 ownerReferences 指向 Deployment。
漏掉这步就容易回滚到不存在的 revision,或者误选了被 GC 掉的旧 RS。
- 用
clientset.AppsV1().ReplicaSets(ns).List()查所有 RS - 过滤 ownerReferences 中
Kind=="Deployment"且Name=="myapp"的 - 从 annotation 提取
deployment.kubernetes.io/revision,转成 int64 - 按 revision 降序排,最新部署在前;注意 revision=0 表示初始部署(无 annotation 时默认值)
别依赖 deployment.status.conditions 或 status.observedGeneration——它们不记录历史。
回滚失败后如何判断是否真的卡住了
调用 Rollback() 成功只代表请求已提交,Deployment 控制器可能因镜像拉不到、资源不足、HPA 干扰等原因卡在 Progressing 状态。不能只看 HTTP 200 就认为回滚完成。
- 轮询
Deployment.Status.Conditions,重点盯Type=="Progressing"和Type=="Available" - 如果
Progressing.Status=="False"且Reason=="ProgressDeadlineExceeded",说明超时,得人工介入 - 检查当前
Deployment.Spec.Replicas和Status.AvailableReplicas是否相等,不等说明 Pod 没起来 - 别用
Get()后比对Spec.Template——RS 已切换,但 Deployment 对象本身不会立即更新 Spec
revision 变更其实发生在 RS 创建瞬间,Deployment 的 Spec 字段永远只反映“最后一次主动更新”的内容,不是当前运行态。










