发布策略是保障生产环境稳定性的关键。本文将详细介绍四种主流发布策略:滚动发布、蓝绿发布、金丝雀发布和多批次发布,分析它们的原理、优缺点及适用场景。
策略概览#
flowchart TB
subgraph 滚动发布
R1[v1] --> R2[v1+v2混合] --> R3[v2]
end
subgraph 蓝绿发布
B1[v1 蓝] --> B2[v2 绿准备] --> B3[切换到 v2]
end
subgraph 金丝雀发布
C1[v1 100%] --> C2[v1 90% + v2 10%] --> C3[v2 100%]
end
subgraph 多批次发布
M1[批次1: 10%] --> M2[批次2: 30%] --> M3[批次3: 60%] --> M4[批次4: 100%]
end
| 策略 | 资源占用 | 回滚速度 | 风险控制 | 复杂度 | 适用场景 |
|---|---|---|---|---|---|
| 滚动发布 | 低 | 中 | 低 | 低 | 常规更新 |
| 蓝绿发布 | 高(2倍) | 快 | 中 | 中 | 关键服务 |
| 金丝雀发布 | 中 | 快 | 高 | 高 | 高风险变更 |
| 多批次发布 | 中 | 中 | 高 | 中 | 大规模集群 |
滚动发布(Rolling Update)#
原理#
滚动发布逐步替换旧版本实例,是 Kubernetes Deployment 的默认策略。
sequenceDiagram
participant LB as 负载均衡
participant V1_1 as Pod v1-1
participant V1_2 as Pod v1-2
participant V1_3 as Pod v1-3
participant V2_1 as Pod v2-1
participant V2_2 as Pod v2-2
participant V2_3 as Pod v2-3
Note over V1_1,V1_3: 初始状态: 3 个 v1 Pod
rect rgb(200, 255, 200)
Note over V2_1: 创建 v2-1
V2_1->>LB: Ready
V1_1->>LB: Terminating
Note over V1_1: 删除 v1-1
end
rect rgb(200, 255, 200)
Note over V2_2: 创建 v2-2
V2_2->>LB: Ready
V1_2->>LB: Terminating
Note over V1_2: 删除 v1-2
end
rect rgb(200, 255, 200)
Note over V2_3: 创建 v2-3
V2_3->>LB: Ready
V1_3->>LB: Terminating
Note over V1_3: 删除 v1-3
end
Note over V2_1,V2_3: 完成: 3 个 v2 Pod
Kubernetes 配置#
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # 最多可超出期望副本数的比例
maxUnavailable: 25% # 最多不可用的副本比例
template:
spec:
containers:
- name: app
image: my-app:v2
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
关键参数#
| 参数 | 说明 | 示例 |
|---|---|---|
maxSurge | 滚动更新时最多可超出期望副本数 | 25% 或 2 |
maxUnavailable | 滚动更新时最多不可用的副本数 | 25% 或 1 |
计算示例(replicas=10, maxSurge=25%, maxUnavailable=25%):
- 最多同时存在:10 + 10×25% = 12 个 Pod
- 最少可用:10 - 10×25% = 7 个 Pod
优缺点#
优点:
- 资源占用低,不需要双倍资源
- Kubernetes 原生支持,配置简单
- 自动进行健康检查
缺点:
- 发布过程中新旧版本共存,可能导致兼容性问题
- 回滚需要时间(再次滚动更新)
- 无法精确控制流量比例
适用场景#
- 常规版本更新
- 向后兼容的变更
- 资源有限的环境
蓝绿发布(Blue-Green Deployment)#
原理#
蓝绿发布维护两套完全相同的环境,通过一次性全量切换流量实现发布。
注意:蓝绿发布的核心是"全切"(0% → 100%)。如果是逐步切换流量(5% → 30% → 100%),那就是金丝雀发布,不是蓝绿发布。
flowchart TB
subgraph 阶段1["阶段 1: 初始状态"]
direction LR
LB1[负载均衡] --> Blue1[蓝环境 v1
3 Pods]
Green1[绿环境
空闲]
end
阶段1 --> 阶段2
subgraph 阶段2["阶段 2: 部署新版本"]
direction LR
LB2[负载均衡] --> Blue2[蓝环境 v1
3 Pods]
Green2[绿环境 v2
3 Pods 准备中]
end
阶段2 --> 阶段3
subgraph 阶段3["阶段 3: 切换流量"]
direction LR
Blue3[蓝环境 v1
空闲]
LB3[负载均衡] --> Green3[绿环境 v2
3 Pods]
end
Kubernetes 实现#
方式一:Service Selector 切换
# 蓝环境 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-blue
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: blue
template:
metadata:
labels:
app: my-app
version: blue
spec:
containers:
- name: app
image: my-app:v1
---
# 绿环境 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-green
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: green
template:
metadata:
labels:
app: my-app
version: green
spec:
containers:
- name: app
image: my-app:v2
---
# Service(通过修改 selector 切换流量)
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app
version: blue # 切换时改为 green
ports:
- port: 80
targetPort: 8080
切换脚本:
#!/bin/bash
# blue-green-switch.sh
CURRENT=$(kubectl get svc my-app -o jsonpath='{.spec.selector.version}')
if [ "$CURRENT" = "blue" ]; then
echo "Switching from blue to green..."
kubectl patch svc my-app -p '{"spec":{"selector":{"version":"green"}}}'
else
echo "Switching from green to blue..."
kubectl patch svc my-app -p '{"spec":{"selector":{"version":"blue"}}}'
fi
echo "Current version: $(kubectl get svc my-app -o jsonpath='{.spec.selector.version}')"
优缺点#
优点:
- 切换速度快(秒级)
- 回滚快速(切回旧环境)
- 新旧版本完全隔离,无兼容性问题
- 可以充分测试新版本后再切换
缺点:
- 资源占用高(需要双倍资源)
- 数据库变更需要特殊处理
- 长连接切换可能有问题
适用场景#
- 关键业务服务
- 需要快速回滚的场景
- 重大版本升级
金丝雀发布(Canary Release)#
原理#
金丝雀发布先将小部分流量导向新版本,验证无问题后逐步扩大比例。
flowchart TB
subgraph 阶段1["阶段 1: 初始"]
LB1[负载均衡]
LB1 -->|100%| V1_1[v1 Pods]
end
subgraph 阶段2["阶段 2: 金丝雀 5%"]
LB2[负载均衡]
LB2 -->|95%| V1_2[v1 Pods]
LB2 -->|5%| V2_2[v2 Pod]
end
subgraph 阶段3["阶段 3: 扩大 30%"]
LB3[负载均衡]
LB3 -->|70%| V1_3[v1 Pods]
LB3 -->|30%| V2_3[v2 Pods]
end
subgraph 阶段4["阶段 4: 全量"]
LB4[负载均衡]
LB4 -->|100%| V2_4[v2 Pods]
end
Kruise Rollouts 实现#
Kruise Rollouts 是阿里开源的渐进式交付组件,特点是 Bypass 模式,不需要修改原有 Deployment:
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: my-app-rollout
spec:
# 关联原有 Deployment(不需要修改 Deployment)
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
strategy:
canary:
steps:
# 金丝雀:10% Pod
- replicas: 10%
pause:
duration: 300 # 5 分钟后自动继续
# 扩大:30%
- replicas: 30%
pause: {} # 手动确认继续
# 扩大:60%
- replicas: 60%
pause:
duration: 600
# 全量
- replicas: 100%
# 流量路由配置
trafficRoutings:
- service: my-app
# 支持 Nginx Ingress
ingress:
classType: nginx
name: my-app-ingress
# 或者 Gateway API
# gateway:
# httpRouteName: my-app-route
手动控制发布:
# 查看发布状态
kubectl get rollout my-app-rollout
# 手动继续下一批次
kubectl-kruise rollout approve rollout/my-app-rollout
# 回滚
kubectl-kruise rollout undo rollout/my-app-rollout
Kruise Rollouts 优势:
- Bypass 模式:与原有 Deployment 解耦,随时可添加/删除
- 兼容 HPA:不影响 HPA 自动扩缩容
- 多流量支持:Nginx Ingress、Gateway API、Istio
- Lua 扩展:通过 Lua 脚本扩展新的工作负载和流量类型
基于特征的金丝雀#
Kruise Rollouts 支持通过 trafficRoutings 配合 Ingress/Gateway 实现基于 Header 的流量路由:
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: my-app-rollout
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
strategy:
canary:
steps:
# 第一步:只对内部用户开放
- replicas: 1
matches:
- headers:
- name: x-user-type
value: internal
pause: {} # 手动确认
# 第二步:扩大到 10% 用户
- replicas: 10%
pause:
duration: 1800
# 第三步:全量
- replicas: 100%
trafficRoutings:
- service: my-app
ingress:
classType: nginx
name: my-app-ingress
优缺点#
优点:
- 风险可控,问题影响范围小
- 可以基于实际生产流量验证
- 支持按用户特征灰度
- 支持自动化分析和回滚
缺点:
- 配置复杂,需要流量管理组件
- 新旧版本共存,需考虑兼容性
- 监控和指标要求高
适用场景#
- 高风险变更
- 新功能验证
- 核心业务服务
- 需要按用户特征发布
多批次发布(Batch Deployment)#
原理#
多批次发布将集群分成多个批次,逐批更新,每批次完成后观察一段时间再继续。
gantt
title 多批次发布流程
dateFormat HH:mm
axisFormat %H:%M
section 批次1 (10%)
部署 :a1, 10:00, 5m
观察 :a2, after a1, 30m
section 批次2 (30%)
部署 :b1, after a2, 10m
观察 :b2, after b1, 30m
section 批次3 (60%)
部署 :c1, after b2, 15m
观察 :c2, after c1, 30m
section 批次4 (100%)
部署 :d1, after c2, 20m
完成 :d2, after d1, 5m
Kruise Rollouts 实现#
Kruise Rollouts 是 OpenKruise 提供的渐进式交付组件,支持金丝雀、多批次和 A/B 测试,兼容 Deployment、CloneSet、StatefulSet 等多种工作负载。
# 安装 Kruise Rollouts
# helm install kruise-rollouts https://... -n kruise-rollouts-system
# Rollout 资源定义
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: my-app-rollout
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
strategy:
canary:
steps:
# 批次 1: 10%
- replicas: 10%
pause:
duration: 1800 # 30 分钟
# 批次 2: 30%
- replicas: 30%
pause:
duration: 1800
# 批次 3: 60%
- replicas: 60%
pause:
duration: 1800
# 批次 4: 100%
- replicas: 100%
# 流量路由(可选,配合 Ingress/Gateway)
trafficRoutings:
- service: my-app
ingress:
classType: nginx
name: my-app-ingress
Kruise Rollouts 特点:
- Bypass 模式:不修改原有 Deployment,通过 Rollout 资源控制发布
- 即插即用:可随时添加或删除,不影响原有工作负载
- 多工作负载支持:Deployment、CloneSet、StatefulSet、DaemonSet
- 流量编排:支持 Nginx Ingress、Gateway API、Istio 等
优缺点#
优点:
- 风险分散,每批次影响范围有限
- 观察时间充足,问题发现及时
- 适合大规模集群
- 可以按区域/机房分批
缺点:
- 发布时间长
- 需要额外的编排工具
- 管理复杂度高
适用场景#
- 大规模集群(100+ 节点)
- 多区域/多机房部署
- 需要严格风险控制
- 监管要求严格的行业
策略对比与选型#
详细对比#
| 对比项 | 滚动发布 | 蓝绿发布 | 金丝雀发布 | 多批次发布 |
|---|---|---|---|---|
| 资源占用 | 低(+25%) | 高(2倍) | 中(+10%) | 中(分批) |
| 发布时间 | 中 | 快 | 长 | 最长 |
| 回滚时间 | 中 | 秒级 | 秒级 | 分批回滚 |
| 流量控制 | 无 | 全切 | 精确比例 | 按批次 |
| 版本共存 | 短暂 | 无 | 较长 | 较长 |
| 复杂度 | 低 | 中 | 高 | 高 |
| K8s 原生 | ✅ | 需配置 | 需 Istio | 需工具 |
选型决策树#
是否需要精确流量控制?
├── 是 → 是否需要按用户特征灰度?
│ ├── 是 → 金丝雀发布
│ └── 否 → 是否是大规模集群?
│ ├── 是 → 多批次发布
│ └── 否 → 金丝雀发布
│
└── 否 → 是否需要快速回滚?
├── 是 → 蓝绿发布
└── 否 → 是否资源有限?
├── 是 → 滚动发布
└── 否 → 蓝绿发布
组合策略#
实际生产中,常常组合使用多种策略:
金丝雀 + 多批次组合:
阶段 1: 金丝雀 5%(验证功能)
↓ 1小时观察
阶段 2: 批次1 10%(扩大验证)
↓ 30分钟观察
阶段 3: 批次2 30%
↓ 30分钟观察
阶段 4: 批次3 60%
↓ 30分钟观察
阶段 5: 批次4 100%
# Kruise Rollouts 组合策略
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: my-app-rollout
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
strategy:
canary:
steps:
# 金丝雀阶段:5% 流量,观察 1 小时
- replicas: 5%
pause:
duration: 3600
# 多批次阶段
- replicas: 10%
pause:
duration: 1800
- replicas: 30%
pause:
duration: 1800
- replicas: 60%
pause:
duration: 1800
- replicas: 100%
# 配合流量路由
trafficRoutings:
- service: my-app
ingress:
classType: nginx
name: my-app-ingress
最佳实践#
1. 发布前检查清单#
□ 代码审查完成
□ 单元测试通过
□ 集成测试通过
□ 变更说明文档准备
□ 回滚方案准备
□ 监控告警配置
□ 值班人员确认
□ 发布窗口确认
2. 健康检查配置#
# 完善的探针配置
spec:
containers:
- name: app
readinessProbe:
httpGet:
path: /healthz/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet:
path: /healthz/live
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 3
startupProbe:
httpGet:
path: /healthz/startup
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 30 # 最多等待 150 秒启动
3. 优雅终止#
spec:
terminationGracePeriodSeconds: 60
containers:
- name: app
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- |
# 通知停止接收新请求
curl -X POST localhost:8080/admin/drain
# 等待存量请求处理完成
sleep 30
4. 发布指标监控#
# Prometheus 告警规则
groups:
- name: deployment
rules:
- alert: HighErrorRateDuringDeployment
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) /
sum(rate(http_requests_total[5m])) > 0.01
for: 2m
labels:
severity: critical
annotations:
summary: "Error rate > 1% during deployment"
- alert: HighLatencyDuringDeployment
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
) > 1
for: 2m
labels:
severity: warning
annotations:
summary: "P99 latency > 1s during deployment"
总结#
| 策略 | 核心特点 | 推荐场景 |
|---|---|---|
| 滚动发布 | 简单、资源少 | 日常更新、资源有限 |
| 蓝绿发布 | 快速切换、快速回滚 | 关键服务、重大升级 |
| 金丝雀发布 | 精确控制、风险可控 | 高风险变更、新功能验证 |
| 多批次发布 | 分批观察、大规模适用 | 大集群、多区域 |
选择发布策略时,需要综合考虑:
- 业务重要性:越重要越需要精细控制
- 变更风险:高风险用金丝雀
- 集群规模:大规模用多批次
- 资源限制:资源少用滚动发布
- 回滚要求:快速回滚用蓝绿
最终目标是在发布速度和系统稳定性之间找到平衡。