可靠发布的目标不是“永不失败”,而是在变更失败时尽早发现、限制影响并快速恢复。生产发布应由统一平台执行,使用经过测试的不可变产物,配合渐进式流量、健康门禁和可验证的回滚方案。
## 1. 建立统一但不过度僵化的规范
建议统一以下基础能力:
1. 通过一个受控发布系统操作生产环境。
2. 使用经过审批的基础镜像、部署身份和权限模型。
3. 统一实例目录、配置目录、数据目录和日志规范。
4. 为不同语言提供标准启动、停止、健康检查和优雅终止模板。
5. 禁止手工上传软件包并直接替换生产文件。
6. 生产发布前必须通过预发或等价验证环境。
7. 禁止一次性让所有线上实例同时失去服务能力。
统一的目的是可重复、可审计和可恢复,而不是强迫所有应用使用完全相同的框架。
## 2. 每次发布必须回答的问题
- 发布的产物摘要和版本是什么?
- 它来自哪个提交、评审和流水线?
- 有哪些功能、配置、数据库和基础设施变更?
- 哪些自动测试与安全检查已通过?
- 影响哪些用户、区域、实例和依赖?
- 使用滚动、蓝绿还是金丝雀?
- 用什么指标判断成功或失败?
- 回滚需要多久,数据变更是否兼容?
- 谁负责观察、决策和事件升级?
信息缺失时应暂停,而不是依赖“先发了再看”。
## 3. 生产前验证
预发环境不能完全复制生产,但至少要保持:
- 相同的构建产物和部署模板。
- 接近生产的依赖版本和配置结构。
- 可代表真实流量的关键业务路径。
- 数据库迁移、权限和网络策略验证。
- 性能、容量和资源限制的基本检查。
- 可观测性和告警规则已加载。
预发验证通过并不等于生产一定安全,所以仍需要渐进发布和生产指标守护。
## 4. 发布策略如何选择
### 滚动发布
逐批替换旧实例,资源成本较低。适合向后兼容、单批故障影响可控的服务。需要正确的 readiness、优雅终止和容量余量。
### 蓝绿发布
同时保留旧环境和新环境,通过路由切换流量。切换和回退速度快,但资源成本较高,数据库兼容仍需单独处理。
### 金丝雀发布
先让少量实例或用户使用新版本,观察一段时间后逐步扩大。适合用户规模大、风险较高且能按版本比较指标的服务。
### 功能开关
代码可以先部署,功能稍后按用户或流量启用。功能开关不能替代代码回滚,并且需要生命周期管理,避免长期堆积。
策略应匹配服务风险,不必所有系统都采用同一种方式。
## 5. 金丝雀阶段怎样判断健康
金丝雀不是“部署一台机器后等五分钟”。需要把新版本与控制组比较,并设置明确门槛:
- 请求成功率和错误率。
- P50、P95、P99 延迟。
- CPU、内存、连接池和队列积压。
- 进程重启、OOM 和实例健康。
- 下游依赖错误和超时。
- 订单、支付、登录等业务转化指标。
- 日志中的新异常类型。
采样窗口必须足够覆盖真实负载,低流量服务可使用合成请求或延长观察时间。指标恶化时自动暂停扩容,不要继续把故障推向全量。
## 6. 快速回滚的前提
真正的回滚不是现场重新编译旧代码,而是把流量或部署指向已经保存的稳定产物。必须提前具备:
- 上一个稳定版本仍在制品库,可通过摘要定位。
- 部署工具支持选择版本并自动验证。
- 配置变更有版本和兼容策略。
- 数据库迁移采用 expand/contract 等向前向后兼容方式。
- 回滚权限、负责人和触发条件明确。
- 定期在非生产环境演练。
如果新版本已经写入旧版本无法识别的数据,简单回滚应用可能扩大故障。数据库、消息格式和 API 兼容性必须进入发布设计。
## 7. Kubernetes 中的滚动与回滚示例
```bash
kubectl set image deployment/app \
app=registry.example.com/app@sha256:NEW_DIGEST
kubectl rollout status deployment/app --timeout=5m
kubectl rollout history deployment/app
kubectl rollout undo deployment/app
kubectl rollout status deployment/app --timeout=5m
```
命令成功不等于业务恢复,回滚后仍需验证错误率、延迟、依赖和关键用户路径。应保留足够的 revision history,并确保镜像不会被仓库清理策略提前删除。
## 8. 发布身份与权限
- 人员不应直接使用共享 root 账号发布。
- 流水线使用独立、最小权限的部署身份。
- 构建身份无权直接修改生产,部署身份不应修改源代码。
- 生产审批和执行需要留存审计记录。
- 凭证从专用 Secret 系统获取,定期轮换。
- 紧急权限有明确时限,使用后复核并回收。
统一发布平台的价值之一,就是把权限和策略放在工具中执行,而不是依赖操作人员记忆。
## 9. 禁止的生产操作
- 从个人电脑上传包覆盖生产文件。
- 在服务器上直接修改代码或配置而不回写版本库。
- 使用 latest 或其他可变标签部署。
- 没有健康检查就一次替换全部实例。
- 把所有区域、集群或租户同时发布。
- 未备份和验证就执行不可逆数据库变更。
- 告警失效或无人值守时进行高风险变更。
- 发布失败后反复重试,却不确认失败是否产生部分副作用。
## 10. 发布后与事故处理
发布完成后仍需持续观察,并自动生成发布记录。若触发异常:
1. 停止扩大流量和后续发布。
2. 判断回滚、关闭功能开关或修复前进哪种方式最快。
3. 保护日志、指标、追踪和变更证据。
4. 通知相关负责人,按事件等级处理。
5. 恢复后验证用户路径和数据一致性。
6. 复盘检测为何没有更早触发,并把改进项写入流水线。
发布成功率不能只按“Job 绿色”计算,应以用户服务没有出现需要干预的退化为准。
## 11. 发布检查清单
发布前:
- 产物、配置、迁移脚本和变更记录完整。
- 预发验证通过,回滚路径已确认。
- 容量、告警和负责人就绪。
- 当前没有会放大风险的重大事件。
发布中:
- 小批量开始,逐步扩大。
- 实时对比新旧版本技术与业务指标。
- 每个阶段有自动超时、暂停和失败门槛。
发布后:
- 全量实例运行预期摘要。
- 错误率、延迟、资源和业务指标稳定。
- 临时权限、路由和调试配置已清理。
- 发布记录可查询,后续观察责任明确。
## 参考资料
- https://sre.google/sre-book/release-engineering/
- https://sre.google/workbook/canarying-releases/
- https://kubernetes.io/docs/tasks/run-application/update-deployment-rolling/