Skip to content
返回部署

零停机回滚策略

版本保留、数据库可逆性与自动回滚触发,实现安全恢复。

CI/CD进阶

为什么

部署破坏生产时,每分钟停机损失收入和信任。预测试回滚路径 — 保留旧版本、数据库迁移可逆、触发自动化 — 秒级恢复服务而非数小时“向前修复”恐慌。回滚必须是一等部署操作,而非事后想法。

何时使用

任何有 SLA、频繁部署(>1/天)或有状态数据的生产系统实现正式回滚。静态站跳过,重部署瞬时且无状态。

如何做

1. 保留版本 — 注册表 + 集群保留最近 N(3-5)镜像标签/部署,不立即 GC 2. 可逆迁移 — 每个 up 有 down;用扩展/收缩使旧版本仍读新 schema 3. 特性开关 — 风险变更包在开关内,"回滚" = 关开关(无重部署,瞬时) 4. 自动触发 — 监控错误率/延迟,阈值突破自动回滚(见 canary-release) 5. 手动回滚 — 一条命令:kubectl rollout undo、vercel --prod --rollback、aws deploy rollback 6. staging 测回滚 — 定期练习回滚,路径在需要时已验证 7. 数据库回滚计划 — 不可逆迁移则部署前快照,回滚时恢复 8. 回滚后 — 告警 + 复盘,回滚非终点 — 下次部署前找根因

示例

# K8s — 保留修订历史 + 即时回滚 # deployment.yaml spec: revisionHistoryLimit: 5 # 保留最近 5 个 ReplicaSet 供回滚 # 回滚命令 kubectl rollout undo deployment/myapp # 到上一个 kubectl rollout undo deployment/myapp --to-revision=3 kubectl rollout status deployment/myapp # 观察进度 kubectl rollout history deployment/myapp # 列修订 # Vercel — 即时回滚到上一个生产部署 vercel --prod --rollback # CLI # 或经 API:POST /v13/deployments/{id}/rollback # 特性开关回滚(无重部署)— LaunchDarkly / Unleash import { LDClient } from "launchdarkly-node-server-sdk"; const client = await LDClient.init(process.env.LD_KEY); // "回滚" = 关开关,<1s 生效,无部署 await client.variation("new-checkout-flow", user, false); # 可逆数据库迁移(Knex)— 始终写 down() exports.up = function (knex) { return knex.schema.table("orders", (t) => t.string("status_v2").nullable()); // 扩展 }; exports.down = function (knex) { return knex.schema.table("orders", (t) => t.dropColumn("status_v2")); // 收缩 }; # 自动回滚触发(GitHub Actions 部署失败时) - name: Deploy run: npm run deploy - name: Verify run: npm run smoke-test - name: Rollback on failure if: failure() run: npm run deploy:rollback

常见问题

  • ⚠旧版本被 GC — 注册表保留太短,回滚目标消失,被迫向前修复
  • ⚠不可逆迁移 — 加了 NOT NULL 列,旧版本回滚崩溃,必须向前修复
  • ⚠回滚从未测试 — 理论可行,实际失败(配置漂移、缺环境变量)
  • ⚠向前修复文化 — 团队从不回滚,路径腐烂,恐慌修复耗时数小时

最佳实践

  • ✓设 revisionHistoryLimit: 5+ 且注册表保留 90 天 — 回滚目标始终可用
  • ✓优先特性开关而非重部署回滚 — 瞬时,无版本博弈,无数据库顾虑
  • ✓每月“回滚演练”— 部署 staging,破坏,回滚,验证路径可行
  • ✓每个迁移可逆 — 扩展/收缩,绝不在同一次部署中既改代码又破坏性改 schema

常见问题解答

回滚应该多快?

5 分钟内——更久则用户在调查时持续受影响。预烤上一镜像/版本使回滚为单命令(kubectl rollout undo)。事故中绝不从旧提交重新构建。

回滚和前向修复有什么区别?

回滚退到上一已知良好版本(快、安全)。前向修复部署修复 bug 的新版本(更慢但保持历史干净)。先回滚止血,再后续部署前向修复。

数据库变更如何回滚?

加性迁移(新列)可回滚。破坏性迁移(删列)不可——数据无法恢复。分两阶段应用破坏性变更:部署停止写入的代码,安全期后再删列。

为什么需要测试回滚?

未测回滚在最需要时失败。每次发布在 staging 跑回滚——捕获不兼容 DB 模式、缺镜像、仅新版本存在的配置等问题。回滚即部署;像部署一样测试。

如何在错误激增时自动回滚?

用 Flagger 或 Argo Rollouts 配指标提供者(Prometheus)。设:错误率超 1% 持续 2 分钟则自动回滚。秒级捕获问题 vs. on-call 工程师 10 分钟才注意并行动。