跳转至

0004-Rollouts-金丝雀

一、金丝雀发布概述

1. 什么是金丝雀发布?

金丝雀发布(Canary Release)是 Kubernetes 环境下渐进式风险控制型部署策略,核心是通过 “小流量验证→指标确认→流量阶梯扩容” 的闭环流程,将生产流量从旧版本逐步迁移至新版本,在最小化故障影响范围的同时,完成版本迭代的安全落地。其核心逻辑与技术价值如下:

2. 核心实现逻辑

1. 流量分层:小比例启动,控制影响范围

初始部署阶段,仅将极小比例的生产流量(如 5%~10%)路由至新版本(金丝雀版本),剩余 90%~95% 流量仍由旧版本承载。这种 “少量试错” 模式可避免新版本潜在问题直接影响全量用户,将故障影响范围精准控制在小部分群体内。

2. 指标验证:基于业务数据确认版本可用性

通过与 Prometheus、Grafana 等监控系统联动,实时采集新版本的核心业务指标(如接口成功率、交易转化率、响应延迟)与基础设施指标(如 Pod 存活状态、CPU 使用率)。仅当指标符合预设阈值(如错误率<0.1%、响应延迟<500ms)时,才进入下一阶段流量扩容,避免单纯依赖 “基础设施健康” 忽略业务层问题。

3. 自动化决策:阈值驱动流程,减少人工干预

支持基于指标阈值配置自动化规则:若新版本指标正常,自动按预设阶梯(如 5%→20%→50%→100%)扩大流量比例;若指标异常(如错误率超标),则立即触发流量回切(将金丝雀流量归零,全量回归旧版本),无需人工手动操作,降低人为误判风险与运维成本。

3. 核心技术价值

  1. 风险可控性高:异常仅影响小比例用户,可快速隔离金丝雀版本、回切流量,避免故障扩散至全量业务,大幅降低生产事故等级。

  2. 验证精准度高:突破 “仅验证基础设施健康” 的局限,直接基于真实业务数据(如用户交互成功率、订单完成率)判断版本可用性,更贴合实际业务场景需求。

  3. 资源利用率高:无需像蓝绿发布那样 “双版本全量部署”,仅需为金丝雀版本部署少量 Pod 即可完成验证,显著节省 Kubernetes 集群的 CPU、内存等计算资源。

二、Argo Rollouts 能力解析

聚焦 Argo Rollouts 如何基于 Kubernetes 生态落地金丝雀发布策略,并通过功能增强实现 “更精细的流量管控、更智能的决策机制、更灵活的发布节奏”,其核心能力拆解如下:

1. 核心能力:从流量到决策的全链路管控

1. 精细化流量控制:多维度实现流量精准分配

Argo Rollouts 突破传统 “单一百分比分配” 的局限,提供两种核心流量管控模式,适配不同金丝雀验证场景:

  • 百分比权重控制:支持按阶梯式比例分配流量(如 5%→20%→50%→100%),可根据业务需求自定义每阶段流量占比,避免流量骤增导致新版本负载波动,确保发布过程平滑过渡。
  • 基于请求头的精准路由:支持按 HTTP 请求头(如 X-User: betaX-Test: canary)定向分发流量,仅将特定用户群(如内部测试用户、beta 体验用户)的请求路由至金丝雀版本,满足 “定向灰度验证” 需求,避免对普通用户造成影响。

2. 多维监控与自动化决策:以指标驱动发布安全

通过与监控生态深度集成,实现 “指标采集→阈值判断→自动执行” 的闭环,减少人工干预成本,提升发布可靠性:

  • 主流监控系统无缝集成:内置与 Prometheus、Datadog、New Relic 等监控工具的适配能力,无需额外开发适配插件,即可实时拉取金丝雀版本的 “基础设施指标”(如 Pod CPU 使用率、内存占用)与 “业务指标”(如接口错误率、交易成功率、响应延迟)。
  • 自定义指标阈值配置:支持用户根据业务场景定义关键指标阈值,例如 “错误率<1%、接口响应时间<500ms、Pod 就绪率 = 100%”,仅当所有指标符合阈值要求时,才允许推进后续流量扩容。
  • 异常自动回滚机制:若金丝雀版本的指标超出预设阈值(如错误率突增至 5%),Argo Rollouts 会立即触发自动回滚 —— 将金丝雀流量比例归零,全量流量切回旧版本,无需人工手动操作,大幅缩短故障响应时间。

3. 分阶段发布策略:灵活定义验证节奏

支持通过 YAML 配置 “多步骤、可暂停” 的发布流程,兼顾 “自动化效率” 与 “人工干预灵活性”,示例配置如下:

steps:
  - setWeight: 20        # 第一阶段:分配20%流量至金丝雀版本
  - pause: {}            # 手动暂停:需运维人员确认指标正常后,手动触发下一阶段(适合核心业务)
  - setWeight: 50        # 第二阶段:扩容至50%流量,扩大验证范围
  - pause: {duration: 30s}  # 自动暂停30秒:预留时间观察指标波动,无需人工操作
  - setWeight: 100       # 第三阶段:全量发布,100%流量切换至金丝雀版本

该模式允许用户根据业务重要性灵活选择 “自动暂停” 或 “手动暂停”—— 核心服务可通过 “手动确认” 增加安全校验环节,非核心服务可通过 “自动暂停” 提升发布效率。

三、基于 Argo Rollouts 金丝雀发布

使用 Argo Rollouts 搭配 Ingress-NGINXargoproj/rollouts-demo:green 镜像实现金丝雀发布,实现流量按比例逐步迁移、暂停验证、自动推进的渐进式发布策略。

1. 项目结构

bluegreen-rollout/
.
├── 1-1-blue-canary.yaml
├── 1-2-blue-service.yaml
├── 1-3-green-service.yaml
└── 1-4-blue-ingress.yaml
mkdir /argocd/canary && cd /argocd/canary

2. 编写配置文件

cat > 1-1-blue-canary.yaml << "EOF"
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: canary-demo
  labels:
    app: canary-demo
spec:
  replicas: 1  # 启动一个副本用于测试
  selector:
    matchLabels:
      app: canary-demo
  template:
    metadata:
      labels:
        app: canary-demo
    spec:
      containers:
        - name: canary-demo
          image: argoproj/rollouts-demo:blue  # 示例镜像,可替换为业务镜像
          imagePullPolicy: Always
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          resources:
            requests:
              memory: 32Mi
              cpu: 5m
  strategy:
    canary:                              # 金丝雀发布策略
      canaryService: service-canary      # 金丝雀服务
      stableService: service-stable      # 稳定服务
      canaryMetadata:
        labels:
          deployment: canary             # 金丝雀版本的标签
      stableMetadata:
        labels:
          deployment: stable             # 稳定版本的标签
      trafficRouting:
        nginx:
          stableIngress: canary-demo     # 关联 ingress-nginx.yaml 中的 Ingress
          additionalIngressAnnotations:
            canary-by-header: X-Canary   # 支持按 Header 精准控制流量
      steps:                             # 金丝雀发布阶段控制
        - setWeight: 20                  # 第一阶段:20% 流量进入金丝雀
        - pause: {}                      # 暂停,需要手动操作继续
        - setWeight: 50                  # 第二阶段:50% 流量
        - pause:
            duration: 30s                # 暂停 30 秒进行监控验证
        - setWeight: 100                  # 第三阶段:100% 流量
        - pause:
            duration: 30s                # 最后验证后全量切换
EOF
cat > 1-2-blue-service.yaml << "EOF"
service-stable.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-stable
  labels:
    app: canary-demo
spec:
  selector:
    app: canary-demo
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
EOF
cat > 1-3-green-service.yaml << "EOF"
apiVersion: v1
kind: Service
metadata:
  name: service-canary
  labels:
    app: canary-demo
spec:
  selector:
    app: canary-demo
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
EOF
cat > 1-4-blue-ingress.yaml << "EOF"
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-demo
spec:
  ingressClassName: kubesphere-router-cluster
  tls:
    - hosts:
        - canary.k8s.example.cn
      secretName: 3-k8s
  rules:
  - host: canary.k8s.example.cn
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service-stable
            port:
              number: 80
EOF

3. 部署与验证

1. 部署蓝资源

kubectl apply -f 1-1-blue-canary.yaml  
kubectl apply -f 1-2-blue-service.yaml
kubectl apply -f 1-3-green-service.yaml  
kubectl apply -f 1-4-blue-ingress.yaml

2. 查看蓝色版本效果

image-20250828154040076 image-20250828154047924

3. 触发金丝雀绿色版本发布

kubectl argo rollouts set image canary-demo \
  canary-demo=argoproj/rollouts-demo:green

4. 浏览器流量验证(第一阶段 20% 流量蓝)

查看应用两个版本请求都有 当前新版本比例是20%
image-20250828154258075 image-20250828154311961
1. 批量请求测试分流比例
#!/bin/bash

# 配置变量 - 可根据实际情况修改
INGRESS_IP="https://canary.k8s.example.cn/color"  # 替换为实际的INGRESS_IP
HOST_HEADER="canary.k8s.example.cn"          # Host头信息
REQUEST_COUNT=20                   # 请求次数

# 检查INGRESS_IP是否已配置
if [ "$INGRESS_IP" = "your-ingress-ip-here" ]; then
  echo "错误:请先设置正确的INGRESS_IP变量"
  exit 1
fi

echo "开始发送 $REQUEST_COUNT 次请求..."
echo "目标地址: http://$INGRESS_IP"
echo "Host头: $HOST_HEADER"
echo "----------------------------------------"

# 执行请求并保存结果到临时文件
temp_file=$(mktemp)
for ((i=1; i<=$REQUEST_COUNT; i++)); do
  # 发送请求并提取Pod Image信息
  result=$(curl -s -k "$INGRESS_IP" -H "Host: $HOST_HEADER" )
  echo "第 $i 次: $result"
  echo "$result" >> "$temp_file"
done

echo "----------------------------------------"
echo "次数统计:"
sort "$temp_file" | uniq -c

echo -e "\n占比统计:"
# 计算并显示百分比
sort "$temp_file" | uniq -c | awk -v total=$REQUEST_COUNT \
  '{percent = ($1 / total) * 100; printf "%s: %d次 (%.2f%%)\n", $0, $1, percent}'

# 清理临时文件
rm "$temp_file"
echo -e "\n统计完成"
使用 curl 查看效果大概是 20% 查看 rollouts 网页大概也是 20%
image-20250828162435365 image-20250828162351480
2. 服务强制路由到金丝雀(A/B)

在 Ingress 中配置 Header 匹配规则,实现定向灰度测试(A/B测试):定向邀请内测用户(如 X-Canary: always),

1. 可以先走金丝雀发布流程。

  • nginx.ingress.kubernetes.io/canary-by-header: X-Canary:支持通过 HTTP 头 X-Canary强制分流,例如:
  • 若请求头包含 X-Canary: always,则流量强制走金丝雀版本。
  • 若包含 X-Canary: never,则流量强制走主版本。

2. 查看效果

此时会有一条稳定版ingress规则和一条手动金丝雀的ingress规则。 验证完成后、删除手动创建的金丝雀规则、回复自动创建的规则。继续走金丝雀发布流程。

通过 -H "X-Canary " 强制路由到金丝雀版本

使用 ModHeader 插件添加 X-Canary: never 使用 ModHeader 插件添加 X-Canary: always
image-20250902114803935 image-20250902114541241

通过 -H "hah :test" 强制路由到金丝雀版本

nginx.ingress.kubernetes.io/canary-by-header: hah
nginx.ingress.kubernetes.io/canary-by-header-value: test

5. 手动推进发布流程

1. 等待全量发布完成验证
手动推进等待全量发布完成 全量发布完成验证
image-20250828162955790 image-20250828163145076
2. 关键流程示意图
graph TD
  A[创建初始资源] --> B[触发金丝雀发布]
  B --> C{阶段1: 分配20%流量}
  C -->|手动验证通过| D[人工确认后进入下一阶段]
  D --> E{阶段2: 分配50%流量}
  E -->|自动暂停30秒| F[监控指标自动检查]
  F -->|指标正常| G{阶段3: 分配100%流量}
  G -->|自动暂停30秒| H[最终完整性验证]
  H -->|验证通过| I[全量发布完成]

6. 回滚版本

点击回滚 查看回滚比例差不多
image-20250828163541084 image-20250828163629406
手动推进等待全量发布完成 查看应用已经回滚成蓝版本
image-20250828163813390 image-20250828163739662

四、金丝雀发布底层原理

1. 核心机制:组件协作与流量控制

金丝雀发布的本质,是由 Argo Rollouts 控制器作为 “调度中枢”,动态协调 Ingress、Service、ReplicaSet 等 Kubernetes 原生资源,通过 “资源联动 + 策略驱动” 实现从旧版本到新版本的渐进式流量切换与灰度控制。整个过程遵循预设规则自动执行,无需人工干预,确保发布流程的标准化与可靠性。

2. 核心组件角色与交互逻辑

组件 核心作用
Argo Rollouts 控制器 统筹调度核心:解析 Rollout 策略配置,创建 / 管理 ReplicaSet、更新 Service 标签、联动 Ingress 分流
Ingress 流量入口:根据控制器指令实现 “多版本流量拆分”(如 80%→稳定版、20%→金丝雀版)
Service 流量路由:分为 “稳定版 Service”(指向旧版本 Pod)和 “金丝雀版 Service”(指向新版本 Pod),实现版本隔离
ReplicaSet 实例管理:分别承载旧版本(稳定实例)与新版本(金丝雀实例),通过副本比例控制流量权重

3. 分阶段解析原理

阶段 1:初始状态 —— 全流量指向稳定版

graph LR
    A[用户请求] --> B[Ingress]
    B --> C[service-stable(稳定版Service)]
    C --> D[旧版本Pod]

原理解析

  • service-stable 通过标签选择器(如 rollouts-pod-template-hash=a1234)精准匹配旧版本 Pod,确保流量定向;
  • Ingress 初始路由规则仅指向 service-stable,100% 生产流量由旧版本承载,业务处于稳定运行状态。

阶段 2:金丝雀阶段 —— 流量渐进切换

1. 环境准备(控制器自动执行)
  1. 创建新版本 ReplicaSet(如 canary-demo-a1235),启动金丝雀实例;
  2. 生成 service-canary(金丝雀版 Service),其标签选择器指向新版本 Pod,为分流做准备。
2. Ingress 动态分流
graph LR
    A[用户请求] --> B[Ingress]
    B -->|80%流量| C[service-stable]
    B -->|20%流量| D[service-canary]
    C --> E[旧版本Pod]
    D --> F[新版本Pod]

原理解析

  • service-stable 通过标签选择器(如 rollouts-pod-template-hash=a1234)精准匹配旧版本 Pod,确保流量定向;
  • Ingress 初始路由规则仅指向 service-stable,100% 生产流量由旧版本承载,业务处于稳定运行状态。
3. 分阶段推进规则流量控制的两种核心模式
  • 模式 1:按权重分配(副本比例控制)

  • 通过调整新版本 ReplicaSet 的副本比例实现流量分配(如旧版本 4 副本 + 新版本 1 副本 → 新版本承接 20% 流量);

  • 模式 2按请求特征匹配(精准路由)

  • 实现方式:在 Ingress 中配置请求头匹配规则,仅将符合特征的流量路由至金丝雀版本,示例配置如下:

    annotations:
      nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"  # 匹配的请求头键
      nginx.ingress.kubernetes.io/canary-by-header-value: "beta" # 匹配的请求头值
    
  • 典型场景:定向邀请内测用户(如 X-Canary: beta 标记的内部用户);

暂停机制:每个流量阶段可配置 “人工确认暂停”(pause: {})或 “自动定时暂停”(pause: {duration: 30m}),预留时间验证指标,避免风险扩散。

最终切换 —— 全量发布至新版本

1. 原子化操作(控制器自动执行)
  1. 更新 service-stable 的标签选择器,从 “指向旧版本 Pod” 切换为 “指向新版本 Pod”;
  2. 逐步缩容旧版本 ReplicaSet 至 0 副本,释放资源但保留配置(用于回滚)。
graph LR
    A[用户请求] --> B[Ingress]
    B --> C[service-stable]
    C --> D[新版本Pod]

4. Argo Rollouts 协调逻辑流图

sequenceDiagram
    participant 用户
    participant ArgoRollouts as Argo Rollouts 控制器
    participant K8sAPI as Kubernetes API Server
    participant Ingress
    participant RS_Stable as 旧版本ReplicaSet
    participant RS_Canary as 新版本ReplicaSet

    用户->>ArgoRollouts: 触发发布(修改Rollout镜像)
    ArgoRollouts->>K8sAPI: 创建新版本ReplicaSet(RS_Canary)
    K8sAPI-->>ArgoRollouts: 新版本Pod就绪
    ArgoRollouts->>K8sAPI: 调整副本比例(如RS_Canary:20%)
    Ingress->>K8sAPI: 监听Endpoint变化(新旧Pod地址)
    Ingress->>Ingress: 按副本比例分配流量(80%→稳定版,20%→金丝雀版)

    loop 分阶段推进流量
        ArgoRollouts->>ArgoRollouts: 等待人工确认/定时暂停(如30分钟)
        ArgoRollouts->>K8sAPI: 提升金丝雀副本比例(如50%→100%)
        Ingress->>Ingress: 同步更新流量分配比例
    end

    ArgoRollouts->>K8sAPI: 缩容旧版本ReplicaSet(RS_Stable→0副本)
    ArgoRollouts->>K8sAPI: 更新service-stable标签→指向新版本Pod

5. 资源生命周期管理

1. Service 生命周期

  • 稳定版 Service(service-stable):全程存在,发布前指向旧版本、发布后指向新版本,保持服务入口(如域名、端口)不变,确保业务无感知切换;
  • 金丝雀版 Service(service-canary):仅在发布阶段存在,全量发布后闲置,建议通过标签(如 env: canary-temp)标记,便于后续清理。

2. ReplicaSet 生命周期

  • 旧版本 ReplicaSet:全量发布后缩容至 0 副本,但保留配置文件,支持通过 kubectl argo rollouts undo 秒级回滚;
  • 新版本 ReplicaSet:发布完成后长期保留,作为下一版本更新的 “稳定版” 基础。