技术文章2026 年 8 月 6 日约 3 分钟

Kubernetes 滚动发布与回滚:保障 CI/CD 变更安全

滚动发布、暂停继续与回滚的标准动作,以及一次真实发布事故的完整复盘。

自动部署不等于自动成功。每次发布都要回答三个问题:怎么发、怎么确认发完了、发坏了怎么快速回来。这篇文章讲 Deployment 的 rollout 机制和我在一次真实事故里的处理过程。

#rollout 是什么:新版本怎么替换旧版本

Deployment 的 strategy.type: RollingUpdate 决定了替换节奏,两个参数:

  • maxUnavailable:更新过程中最多允许几个旧副本不可用。
  • maxSurge:最多允许超出期望副本数几个新副本。

maxUnavailable: 0, maxSurge: 1 是保守配置:先起一个新 Pod,readiness 通过后才摘一个旧 Pod,循环直到全部替换。它保证容量不降,代价是更新期间资源占用翻倍;追求快就用 maxUnavailable: 1, maxSurge: 1。

#发布的标准动作:打标记、更新、等 rollout

bash
# 1. 打 change-cause,历史里能看出每次改了什么
kubectl annotate deployment/demo-api \
  kubernetes.io/change-cause="release 1.2.0: fix order rounding"

# 2. 触发更新
kubectl set image deployment/demo-api api=ghcr.io/acme/demo-api:1.2.0

# 3. 等 rollout 完成(超时即失败)
kubectl rollout status deployment/demo-api --timeout=180s

kubectl rollout status 会一直等到新副本全部就绪或超时。超时返回非零退出码,在 CI 里等于发布失败,这是自动化发布里最重要的一个动作。别用「sleep 30 然后查 Pod」这种笨办法,rollout status 是标准答案。

发布过程用这个命令看实时状态:

bash
kubectl get pods -l app=demo-api -w
kubectl rollout history deployment/demo-api
# 输出里 revision 从 1 递增,CHANGE-CAUSE 显示每次的标记

#暂停和继续:灰度观察的时机

kubectl rollout pause 可以在发布中间停住,让一部分流量先跑一段时间:

bash
kubectl rollout pause deployment/demo-api
# 观察新版本 Pod 的错误率、延迟
kubectl rollout resume deployment/demo-api

但 pause 的语义是「暂停 Deployment 的控制器协调」,不是「只放 10% 流量」。真正按比例灰度是 Service 多版本加权(如 Flagger/Argo Rollouts 的 canary),rollout pause 只适合「先更新一半再手动继续」的粗粒度场景。别把两者混了。

#回滚:快速回到上一版

bash
# 回滚到上一个 revision
kubectl rollout undo deployment/demo-api
# 回滚到指定 revision(先 history 查编号)
kubectl rollout undo deployment/demo-api --to-revision=3
kubectl rollout status deployment/demo-api --timeout=180s

回滚后同样要 rollout status 确认恢复。我经历过的一次真实事故流程:

  1. 发布 1.2.0,readiness 探针配的是新接口路径,老路径被移除。
  2. 上线后新版本 Pod 全部不就绪,滚动卡住(maxUnavailable: 0 保住了旧版,线上暂时没挂)。
  3. kubectl rollout history 看到 revision 5 是 1.2.0,kubectl rollout undo --to-revision=4 秒回旧版。
  4. 之后排查:kubectl logs <旧Pod> --previous 看新版本为什么没起来——原来是配置里引用了不存在的配置项。

回滚救急,但根因必须继续查。只 undo 不修根因,下次发布同一个坑还会炸。回滚后要做的事:保留当时的 Pod 日志(--previous)、记录 revision、开问题单。

#更稳妥的防线:发布前多一道校验

  • Deployment 里配 progressDeadlineSeconds(默认 600s),滚动超过这个时间没完成,rollout status 会报 progress deadline exceeded,便于自动化捕获卡死。
  • 生产环境用 GitHub Environments 审批 + 手动确认,别让「merge 即发布」直接进 prod。
  • 发布窗口留足 terminationGracePeriodSeconds 和 preStop,旧 Pod 优雅退出,连接不中断。

#经验

发布能力是「回滚能力」决定的。每次发布前我都会确认三件事:change-cause 打了、rollout status 有超时、undo 命令在非生产演练过。等真出事的时候,你不想第一次用 kubectl rollout undo。

写于 2026 年 8 月 6 日

栏目
技术文章
约
3 分钟
字数
2.2K
阅读
222

本文为原创记录,转载请注明出处。如果这篇替你省了时间,欢迎留言说说你踩到的坑。

同题 · related

留言 · remarks

00 条

还没有留言,来说点什么吧。

Kubernetes 滚动发布与回滚:保障 CI/CD 变更安全 · LXH·BLOG