软件项目开发全流程 · 第 25 课 · 持续交付与部署
1、从"周五晚上的惊魂上线"说起
老式发布流程长这样:半夜所有人待命,运维手工敲命令,代码从 U 盘/共享盘拷到服务器,出问题立刻手动回滚——心跳加速、全员加班、出事靠人肉。
而高效团队的状态是:每天发布几十次,发布是件平淡无奇的小事。 差别就在于自动化。本课讲:持续交付(CD)与环境、流水线、灰度/蓝绿发布。
2、三种"持续":CI / CD / CD
这三个缩写容易混,用一句话分清:
持续集成 CI(Continuous Integration)
代码一提交就自动构建 + 测试,早发现冲突
↓
持续交付 CD(Continuous Delivery)
在 CI 基础上,自动把制品推到「可随时上线」的状态,
但「上线」这一步由人**按按钮**触发
↓
持续部署 CD(Continuous Deployment)
连「上线」也自动化,测试通过即自动上生产关键区分:
- CI 解决"代码能不能合"。
- 持续交付:随时可发布,发布与否是业务决策。
- 持续部署:自动发布,需要极强的测试与监控信心。
多数团队先做到持续交付(人工点最后一下),再逐步走向持续部署。
3、环境:代码流过的地方
一个规范的环境链路:
开发环境(Dev) → 测试环境(Test/QA) → 预发环境(Staging) → 生产环境(Prod)
写代码 功能验证 模拟生产 真实用户环境管理铁律:
| 原则 | 说明 |
|---|---|
| 环境一致性 | 各环境配置尽量一致(用 IaC/容器),否则"预发没问题、生产炸" |
| 配置外置 | 环境差异(数据库地址、密钥)放配置/环境变量,不进代码 |
| 预发≈生产 | 预发要尽可能像生产(数据量、拓扑、配置),才有预演价值 |
| 生产最小权限 | 生产访问严格管控、审计留痕 |
十二要素应用(12-Factor App) 里最相关的一条:在环境中存储配置——同样的制品,靠环境变量适配不同环境。
4、部署流水线(Pipeline)
一条完整的 CD 流水线长这样:
提交代码
│
▼
① 构建 → ② 单元测试 → ③ 集成测试 → ④ 制品入库
│
▼
⑤ 部署到测试环境 → ⑥ 自动化验收/E2E
│
▼
⑦ 部署到预发 → ⑧ 人工审批 ──▶ ⑨ 部署到生产
│
▼
⑩ 健康检查/冒烟测试
│
失败 ◀──────┴──────▶ 成功
│ │
▼ ▼
自动回滚 观察监控# GitHub Actions 示例(简版)
name: CD Pipeline
on:
push:
branches: [main]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: pytest # 测试不过,后面全不执行
- run: docker build -t myapp:${{ github.sha }} .
- run: docker push registry/myapp:${{ github.sha }}
deploy-staging:
needs: build-test # 依赖上一步成功
environment: staging
steps:
- run: ./deploy.sh staging ${{ github.sha }}
deploy-prod:
needs: deploy-staging
environment: production # 配了人工审批
steps:
- run: ./deploy.sh production ${{ github.sha }}流水线设计原则:
- 快速失败:前面的门(构建/测试)先拦住问题,别把坏制品往后传。
- 每一步可观察:谁失败、为什么失败,一眼可见。
- 可重复:同一版本,重跑流水线结果一致。
5、发布策略:怎么把风险降到最低
直接替换(停机发布):简单,但有服务中断,不适合高可用系统。
蓝绿发布(Blue-Green):两套环境,切换流量:
┌── Blue(当前生产,v1)◀── 全部流量
负载均衡┤
└── Green(新版本 v2,先部署好,测好)
切换:把流量从 Blue 切到 Green → 出问题秒切回 Blue- ✅ 秒级切换、秒级回滚。
- ❌ 需要双倍资源。
灰度/金丝雀发布(Canary):先放一小撮流量给新版本:
v1(旧) ◀── 95% 流量
v2(新) ◀── 5% 流量 ← 观察错误率/延迟
↓ 观察期没问题
v1 ◀── 50% v2 ◀── 50%
↓
v1 ◀── 0% v2 ◀── 100%- ✅ 小范围试错,影响面可控;可按用户/地域/设备分批。
- ❌ 需要流量切分能力与精细监控。
滚动发布(Rolling):逐台替换实例,不停服。
实例: [v1][v1][v1][v1]
→ [v2][v1][v1][v1] (替换一台,健康后再下一台)
→ [v2][v2][v2][v2]发布策略选择:
| 策略 | 回滚速度 | 资源成本 | 适用 |
|---|---|---|---|
| 直接替换 | 慢 | 低 | 内部小系统 |
| 蓝绿 | 秒级 | 高(双倍) | 关键系统、需快速回滚 |
| 灰度 | 快(切流量) | 中 | 用户量大的线上服务 |
| 滚动 | 中 | 低 | 容器化集群 |
6、发布与回滚必须成对设计
任何没有回滚预案的发布都是赌博。
发布前:明确"怎么算成功"(健康检查、核心指标)
明确"什么情况回滚"(错误率 > x%、P95 > y ms)
明确"怎么回滚"(切流量 / 回滚镜像 / 数据库兼容)
发布后:冒烟测试 → 观察指标 → 确认稳定数据库回滚是最难的部分:代码能秒回,数据迁移往往不可逆。
解法:让 schema 变更向后兼容。加字段先加可空的、改字段分两步(先双写、再切读)、删除字段延后到确认无人用。这样新旧代码能共存,回滚随时可行(第 31 课细讲)。
7、常见误区
| 误区 | 问题 | 正解 |
|---|---|---|
| 手工部署 | 易错、不可复现 | 流水线自动化 |
| 各环境制品不同 | "测过的"≠"上线的" | 同一制品走完全程 |
| 配置写死在代码里 | 换环境就炸 | 配置外置(环境变量) |
| 没有回滚方案 | 出事只能硬扛 | 发布必配回滚 |
| 直接全量上线 | 问题影响所有用户 | 蓝绿/灰度/滚动 |
| 数据库变更不留退路 | 回滚就丢数据 | 向后兼容的迁移 |
8、动手实验 🎯
任务:为贯穿项目「团队任务清单」搭一条持续交付流水线。
- 分环境配置:用环境变量管理数据库地址等差异,让同一镜像能跑在不同环境。
- 写流水线(GitHub Actions / GitLab CI):提交 → 测试 → 构建 → 推制品,测试失败则阻断。
- 加人工审批门:生产部署设为需人工确认(environment protection)。
- 实现灰度发布:用一个反向代理(如 Nginx)把 10% 流量导向新版本,5 分钟后全量。
- 设计回滚:写一个
rollback.sh,一条命令切回上一版本;实测一次。 - 做一次向后兼容的迁移:给任务表加一个字段(先可空),验证新旧代码都能跑。
- 反思:如果发布根本不需要开"发布大会",你的团队还需要哪些能力?
下一课:上线发布:计划、回滚与变更管理。
9、今天你带走的三句话
- CI 管"能不能合",持续交付管"随时可发",持续部署管"自动发"。
- 同一制品走遍所有环境,配置外置,环境尽量一致。
- 发布与回滚成对设计;用蓝绿/灰度/滚动降低风险,数据库变更要向后兼容。
下一课:上线发布:计划、回滚与变更管理。