部署策略-蓝绿-金丝雀-滚动
1. 三大策略对比
| 策略 | 原理 | 回滚速度 | 资源开销 | 适合 |
|---|---|---|---|---|
| 滚动更新 | 逐批替换旧 Pod | 中(回滚重新滚) | 低(+1 Pod) | 默认首选 |
| 蓝绿部署 | 两套环境切流量 | 快(切回旧) | 高(双倍资源) | 要求极快回滚 |
| 金丝雀 | 少量流量灰度新版 | 快 | 中 | 风险高的变更 |
2. 滚动更新(K8s 默认)
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多多 1 个 Pod
maxUnavailable: 0 # 更新期间不能减少可用数
过程:创建 1 新 Pod → 就绪 → 销毁 1 旧 Pod → 循环。
回滚:
kubectl rollout undo deployment/frontend
2.1 零停机前提
readinessProbe必须配maxUnavailable: 0preStophook sleep 5s 让 Service 摘流量- 应用正确处理 SIGTERM
3. 蓝绿部署
两套 Deployment(blue/green),Service selector 切换:
# deployment-blue.yaml (当前生产)
metadata:
name: frontend-blue
labels:
version: blue
spec:
replicas: 3
template:
metadata:
labels:
app: frontend
version: blue
# deployment-green.yaml (新版本)
metadata:
name: frontend-green
labels:
version: green
spec:
replicas: 3
template:
metadata:
labels:
app: frontend
version: green
# service.yaml — 切换流量
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
selector:
app: frontend
version: blue # 改成 green 即完成切换
步骤:
- 部署 green(不接流量)
- 测试 green:
kubectl port-forward deploy/frontend-green 8080:80 - 切 Service selector → green
- 确认 OK 后删 blue
回滚:selector 改回 blue。
3.1 Ingress 层蓝绿
nginx-ingress 用 annotation:
# canary ingress(指向新版本)
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "100" # 100% = 蓝绿切
4. 金丝雀(Canary)
少量流量先走新版本,确认无问题再全量。
4.1 K8s 原生(调副本比例)
新旧版本共用 Service,按 Pod 数做权重:
旧版本 Deployment: replicas=9
新版本 Deployment: replicas=1
→ 约 10% 流量到新版
粗糙但不需额外组件。
4.2 nginx-ingress canary
# 主 Ingress(旧版本)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: frontend
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
service:
name: frontend-stable
port: {number: 80}
# 金丝雀 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: frontend-canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% 流量
# 或按 header
# nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
# nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
service:
name: frontend-canary
port: {number: 80}
4.3 Argo Rollouts(推荐)
功能完整的渐进式交付:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: frontend
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 10
- pause: { duration: 5m }
- setWeight: 30
- pause: { duration: 5m }
- setWeight: 60
- pause: { duration: 5m }
- setWeight: 100
canaryMetadata:
labels:
version: canary
stableMetadata:
labels:
version: stable
trafficRouting:
nginx:
stableIngress: frontend
自动金丝雀 + 指标检查 + 自动回滚。
4.4 CDN 层金丝雀(前端静态站)
CDN 按 cookie/header 分流到不同源站目录:
CDN 规则:
X-Version: canary → 回源 /v2/dist/
其他 → 回源 /v1/dist/
Cloudflare Workers 路由:
export default {
async fetch(request) {
const cookie = request.headers.get('Cookie') || ''
const bucket = cookie.includes('canary=1') ? 'v2' : 'v1'
return fetch(`https://origin.example.com/${bucket}${new URL(request.url).pathname}`)
}
}
5. 选型决策
| 场景 | 推荐 |
|---|---|
| 日常迭代 | 滚动更新 |
| 大版本(重写/架构变更) | 蓝绿 |
| 高风险变更(支付流程改动) | 金丝雀 |
| 前端 SPA 无服务器 | CDN 层金丝雀 |
| 需要按用户/地区灰度 | 金丝雀 by header/cookie |
6. 常见反模式
- 滚动更新不配 readinessProbe:新 Pod 未就绪就接流量 → 5xx
- 蓝绿不清理旧版本:双倍资源一直占
- 金丝雀没监控:放了 10% 但不看错误率,等全量才发现问题
- 不做数据库兼容:新版 schema 和旧版不兼容,金丝雀期间崩
- 回滚靠重新部署旧版:慢。应该靠 selector 切换 / Argo Rollout 自动 abort
- 用户看到两个版本的 JS 混搭:静态资源 hash + 保留旧版本文件
7. 延伸阅读
- Argo Rollouts
- nginx-ingress canary annotations
- Flagger — 另一个渐进式交付工具
- 模块 09 CDN 缓存策略与刷新