把发布流程当成产品来维护:一次 DevOps 值班后的复盘
把发布流程当成产品来维护:一次 DevOps 值班后的复盘
这两年我越来越认同一件事:DevOps 不是“把 CI/CD 配上就完了”,而是把交付链路本身当成产品来维护。很多团队线上故障并不是代码逻辑错得多离谱,而是发布流程靠人脑补、靠群消息提醒、靠某个同学“记得点一下”。这种流程平时看起来能跑,一到高峰期就容易出事。
我最近帮一个小团队整理过一条发布链路,问题非常典型:
- 镜像 tag 用
latest,回滚时根本不知道上一版是谁; - 数据库迁移和应用发布绑在一起,迁移失败会把整个部署卡死;
- 告警只盯 CPU 和内存,不盯错误率与发布事件;
- 发布成功的定义只有一句“页面能打开”。
后面我们没上什么“银弹平台”,只做了几件很朴素的事,效果反而很明显。
一、先给每次发布一个可追踪身份
第一步不是炫技,而是把构建产物命名规范化。镜像 tag 至少要带上提交 SHA:
docker build -t registry.example.com/order-api:${GIT_COMMIT} .
docker push registry.example.com/order-api:${GIT_COMMIT}
Kubernetes 部署时也不要继续写死 latest:
kubectl set image deployment/order-api \
order-api=registry.example.com/order-api:${GIT_COMMIT} \
-n production
这样做的价值在故障时最明显。你不需要猜“昨天晚上那版到底是谁发的”,直接看 deployment 当前镜像和 Git 提交就能对上。
二、把迁移和发布解耦
很多事故都出在数据库变更。我的经验是:迁移脚本可以自动执行,但不能和应用启动成功强绑定在一个黑盒步骤里。更稳妥的方式,是把迁移做成独立 Job,并且显式记录结果。
例如在流水线里拆成两个阶段:
./scripts/run-migration.sh
if [ $? -ne 0 ]; then
echo "migration failed" >&2
exit 1
fi
./scripts/deploy-app.sh
拆开之后,排障会轻松很多。你至少知道失败点在 schema 变更还是应用发布,而不是看到流水线红了以后从头翻日志。
三、观测里一定要带“发布上下文”
只看机器指标,很多时候你会误判。真正有用的是把“发布时间点”打到监控和日志里。比如每次部署后,主动写一条事件:
curl -X POST https://events.example.com/deploy \
-H 'Content-Type: application/json' \
-d '{"service":"order-api","version":"'"${GIT_COMMIT}"'","env":"prod"}'
一旦 5xx 错误率在 10:03 开始抬升,而 10:02 刚完成发布,排查方向立刻就收敛了。别再让值班同学靠直觉猜“是不是刚才那次上线影响的”。
四、发布成功,不等于 Pod Ready
很多团队把 kubectl rollout status 通过,当成发布结束:
kubectl rollout status deployment/order-api -n production --timeout=120s
这一步当然要有,但还不够。Pod Ready 只能说明容器起来了,不代表业务真的可用。更靠谱的办法是加一层发布后验收,比如健康检查、关键接口冒烟,甚至一条只读 SQL。
我现在更喜欢把“发布成功”定义成三件事同时满足:
- 新版本实例全部 Ready;
- 核心接口冒烟通过;
- 错误率在观察窗口内没有异常抬升。
五、别让流程依赖英雄主义
好的 DevOps,不是有人半夜特别能扛,而是流程设计得足够笨、足够稳。每次上线都能追踪、能回滚、能观测、能复盘,这比堆多少平台名词都重要。
发布流程一旦被当成产品维护,你就会开始关心它的可用性、可理解性和可恢复性。真正成熟的团队,竞争力往往不只是代码写得快,而是出了问题以后,系统和流程都能帮人,而不是拖人后腿。

浙公网安备 33010602011771号