Skip to content
发布策略

发布策略

滚动更新、金丝雀发布(灰度发布)的实现与局限性。


1. 发布策略概述

策略 说明 风险 适用场景
滚动更新(Rolling Update) 逐步替换旧版本 Pod Deployment 默认策略,适用于大多数场景
金丝雀发布(Canary) 小范围部署新版本,逐步扩大 需要按比例验证新版本的场景
蓝绿部署(Blue-Green) 新旧两套环境,流量一次性切换 低(可秒级回滚) 需要瞬时切换的场景
A/B 测试 按用户特征分流到不同版本 需要按用户属性分流的场景

2. 滚动更新(Rolling Update)

Deployment 的默认更新策略。

spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1         # 更新期间最多允许多出几个 Pod
      maxUnavailable: 1   # 更新期间最多允许几个 Pod 不可用
参数 说明 默认值
maxSurge 峰值时超出 replicas 的 Pod 数量 25%
maxUnavailable 更新中不可用的 Pod 最大数量 25%

示例流程(replicas=3, maxSurge=1, maxUnavailable=1):

初始状态:  [v1] [v1] [v1]
步骤1:     [v1] [v1] [v1] [v2]     (创建 1 个新 Pod)
步骤2:     [v1] [v1] [v2]          (删除 1 个旧 Pod)
步骤3:     [v1] [v1] [v2] [v2]     (创建 1 个新 Pod)
步骤4:     [v1] [v2] [v2]          (删除 1 个旧 Pod)
...
终态:      [v2] [v2] [v2]

相关命令

# 更新镜像
kubectl set image deploy/nginx-deploy nginx=nginx:1.23

# 查看更新状态
kubectl rollout status deploy/nginx-deploy

# 查看历史版本
kubectl rollout history deploy/nginx-deploy

# 回滚
kubectl rollout undo deploy/nginx-deploy
kubectl rollout undo deploy/nginx-deploy --to-revision=1

# 暂停/恢复更新
kubectl rollout pause deploy/nginx-deploy
kubectl rollout resume deploy/nginx-deploy

3. 金丝雀发布(Canary Deployment)

3.1 命名来源

早期矿工下井前,会先放入一只金丝雀检测井下是否有毒气。金丝雀对有毒气体更敏感,若金丝雀死亡则立即撤离。

对应到软件发布:先用少量用户验证新版本,确认无问题后再逐步推广到全部用户。

3.2 部署过程

1. 发布 v1 版本(100% 流量)
2. 发布 v2 版本(1 个实例,≈10-20% 流量)
3. 观察 v2 运行情况,逐步扩容 v2
4. 确认无误后,将 v1 缩容至 0
5. 清理 v1,v2 接替全部流量

3.3 基于 Service Label Selector 的简化实现

核心思路:两个 Deployment 使用相同的 Label,Service 通过 Selector 自动将流量分发给两者。

步骤 1:部署 v1

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-v1
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
        version: v1
    spec:
      containers:
        - name: nginx
          image: nginx:1.22
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: canary-demo
  namespace: dev
spec:
  type: NodePort
  selector:
    app: nginx                    # 选所有 app=nginx 的 Pod
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30008

步骤 2:部署金丝雀版本(v2)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-canary
  namespace: dev
spec:
  replicas: 1                     # 只有 1 个副本(金丝雀)
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx                # 与 v1 相同的 Selector 标签
        version: v2
        track: canary             # 区分标签
    spec:
      containers:
        - name: new-nginx
          image: docker/getting-started
          ports:
            - containerPort: 80

步骤 3:逐步扩大 v2 占比

# 扩容 v2
kubectl scale deploy nginx-deployment-canary --replicas=3 -n=dev

# 观察 v2 运行正常后,下线 v1
kubectl scale deploy nginx-deployment-v1 --replicas=0 -n=dev

3.4 流量分配原理

请求 → Service(selector: app=nginx) → 随机分配到 app=nginx 的所有 Pod
                                          ├── v1 Pod × 3 (75%)
                                          └── v2 Pod × 1 (25%)

由于 Service 的负载均衡是随机分配的,通过调整两个 Deployment 的副本数比例来控制流量分配。


4. 金丝雀发布的局限性(🚨 重要)

局限性 说明
无法基于请求内容分流 Service 只在 TCP 层做负载均衡,不解析 HTTP 内容
无法按用户属性分流 不能根据用户 ID、地区、注册时间等分配流量
用户粘性缺失 同一用户的多次请求可能路由到不同版本
无精细流量控制 只能按 Pod 数量比例(粗粒度),不能精确到百分比

4.1 局限性示例

用户 A 第 1 次请求 → Service → v1 Pod
用户 A 第 2 次请求 → Service → v2 Pod  (体验不一致)

4.2 解决方案

对于需要精细流量控制的场景,应使用 Service Mesh(如 Istio、Linkerd)或 API 网关

方案 能力
Istio 基于 HTTP Header/Cookie 的流量路由、权重百分比
Linkerd 金丝雀发布、流量分割
Argo Rollouts 声明式渐进式交付,支持蓝绿和金丝雀
Nginx Ingress 基于 Cookie/Header 的流量分割
Traefik K3s 内置 Ingress 控制器,支持金丝雀发布

5. 回滚策略

# 查看发布历史
kubectl rollout history deploy/nginx-deploy

# 查看指定版本详情
kubectl rollout history deploy/nginx-deploy --revision=3

# 快速回滚到上一版本
kubectl rollout undo deploy/nginx-deploy

# 回滚到指定版本
kubectl rollout undo deploy/nginx-deploy --to-revision=2

💡 最佳实践:每次发布时使用 kubectl annotate 记录变更原因,便于后续排查:

kubectl annotate deploy/nginx-deploy kubernetes.io/change-cause="Upgrade nginx to 1.23"