CICD:Ingress金丝雀发布的实现方式及案例详解

Ingress金丝雀发布的实现方式及案例详解

金丝雀发布(Canary Release)是一种渐进式发布策略,允许将新版本服务逐步暴露给部分用户或流量,以降低发布风险。通过Nginx Ingress Controller,我们可以实现多种金丝雀发布方式。下面我将详细介绍各种实现方式及具体案例。

一、金丝雀发布的三种主要方式

1. 基于请求头(Header)的流量切分

这种方式通过检查HTTP请求头中的特定字段来决定是否将请求路由到新版本服务。

关键注解

  • nginx.ingress.kubernetes.io/canary-by-header:指定用于金丝雀发布的请求头名称
  • nginx.ingress.kubernetes.io/canary-by-header-value:指定匹配的请求头值
  • nginx.ingress.kubernetes.io/canary-by-header-pattern:使用正则表达式匹配请求头值

优先级:基于Header的规则具有最高优先级26

适用场景:适合需要将新版本灰度给特定用户群体的场景,如内部测试人员、VIP用户等

2. 基于Cookie的流量切分

这种方式类似于基于Header的方式,但是通过Cookie来标识用户。

关键注解

  • nginx.ingress.kubernetes.io/canary-by-cookie:指定用于金丝雀发布的Cookie名称

特点

  • 仅支持"always"和"never"两个值
  • 当Cookie值为"always"时,请求被路由到新版本
  • 当Cookie值为"never"时,请求被路由到旧版本
  • 其他值会被忽略46

优先级:低于基于Header的规则,但高于基于权重的规则

3. 基于服务权重的流量切分

这种方式按照设定的百分比随机分配流量到新旧版本。

关键注解

  • nginx.ingress.kubernetes.io/canary-weight:指定分配给新版本流量的百分比(0-100)

特点

  • 设置值为10表示分配10%流量到新版本
  • 权重为0表示不路由任何流量到新版本
  • 权重为100表示所有流量都路由到新版本

优先级:三种方式中优先级最低

二、具体实现案例

案例1:基于Header的金丝雀发布

场景:将新版本仅开放给带有特定Header的内部测试人员

YAML配置

# 常规Ingress(旧版本)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-main
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-v1
            port:
              number: 80

# Canary Ingress(新版本)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
    nginx.ingress.kubernetes.io/canary-by-header-value: "internal"
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-v2
            port:
              number: 80

测试方法

# 带指定Header的请求会被路由到新版本
curl -H "Host: example.com" -H "X-Canary: internal" http://ingress-ip/

# 不带Header或Header值不匹配的请求会被路由到旧版本
curl -H "Host: example.com" http://ingress-ip/

案例2:基于权重的金丝雀发布

场景:将10%的流量逐步导入新版本

YAML配置

# Canary Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-v2
            port:
              number: 80

测试结果
执行10次请求后,大约有1次会由新版本服务响应:

nginx-v1
nginx-v1
nginx-v1
nginx-v1
nginx-v1
nginx-v1
nginx-v2
nginx-v1
nginx-v1
nginx-v1
```:cite[10]

案例3:基于Cookie的金丝雀发布

场景:通过设置Cookie将特定用户路由到新版本

YAML配置

# Canary Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "canary"
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-v2
            port:
              number: 80

测试方法

# 设置Cookie值为always的请求会被路由到新版本
curl -H "Host: example.com" --cookie "canary=always" http://ingress-ip/

# 设置Cookie值为never的请求会被路由到旧版本
curl -H "Host: example.com" --cookie "canary=never" http://ingress-ip/

三、组合使用与注意事项

1. 规则优先级

Nginx Ingress处理金丝雀规则的优先级为:

  1. 基于Header的规则
  2. 基于Cookie的规则
  3. 基于权重的规则

2. 使用限制

  • 相同服务的Canary Ingress只能定义一个,因此后端服务最多支持两个版本
  • Ingress中必须配置域名,否则不会生效
  • 即使流量完全切到了Canary Ingress上,旧版服务也必须存在,否则会报错
  • 当Ingress被标记为Canary时,除了负载均衡相关的注解外,其他非Canary注解都会被忽略

3. 最佳实践建议

  1. 渐进式发布:从较小权重(如5-10%)开始,逐步增加
  2. 监控指标:密切监控新版本的性能指标和错误率
  3. 回滚机制:准备好快速回滚方案,如将权重设为0或设置Header/Cookie为never
  4. 清理旧版本:全量发布后,记得删除旧版本服务和Ingress资源

四、总结

Nginx Ingress提供了灵活的金丝雀发布机制,通过Header、Cookie和权重三种方式可以满足不同的灰度发布需求。虽然存在一些限制,但对于大多数常见的发布场景已经足够使用。在实际应用中,可以根据业务需求选择合适的策略或组合使用多种策略,实现安全、可控的服务发布流程

Ingress蓝绿发布的实现方式及案例详解

学习文档:https://support.huaweicloud.com/bestpractice-cce/cce_bestpractice_10003.html

概念:

基于服务权重的流量切分

  • 原理:通过调整新旧版本服务对应的权重,来控制流量分配。新版本服务初始权重设置为0,旧版本服务权重为100%,此时所有流量都流向旧版本服务。当新版本服务部署完成后,逐步增加新版本服务的权重,减少旧版本服务的权重,直至新版本服务权重达到100%,实现流量完全切换到新版本服务。
  • 案例:假设有一个在线购物网站,当前运行的旧版本服务权重为100%,新版本服务部署后,先将其权重设置为20%,此时大约20%的用户访问会被路由到新版本服务。经过一段时间的观察和验证,如果没有问题,再将新版本服务权重逐步增加到50%、80%,最后达到100%,完成蓝绿发布。

基于Header的流量切分

  • 原理:根据HTTP请求头中的特定字段值来决定流量路由。只有请求头中携带特定字段且值匹配预设条件的请求,才会被转发到新版本服务。
  • 案例:一个内容分发网络(CDN)服务,希望通过蓝绿发布更新其内容处理逻辑。设置规则为:只有请求头中包含"Region"字段且值为"bj"或"gz"的请求,才会被路由到新版本服务。这样,只有来自北京或广州地区的用户请求会被转发到新版本服务,其他地区的用户仍然访问旧版本服务。

基于Cookie的流量切分

  • 原理:类似于基于Header的流量切分,但是根据HTTP请求中的Cookie字段值来决定流量路由。只有携带特定Cookie值的请求才会被转发到新版本服务。
  • 案例:一个在线教育平台,为了测试新推出的课程推荐算法,使用基于Cookie的蓝绿发布。设置规则为:只有Cookie中包含"test=newalgo"的用户请求才会被路由到新版本服务。这样,只有参与测试的用户才会体验到新课程推荐算法,其他用户仍然使用旧的推荐算法。

基于Query Param的流量切分

  • 原理:根据HTTP请求URL中的查询参数来决定流量路由。只有当URL查询参数满足特定条件时,请求才会被转发到新版本服务。
  • 案例:一个新闻网站,计划更新其文章页面的布局。设置规则为:只有当URL查询参数中包含"layout=new"时,请求才会被路由到新版本服务。这样,只有主动在URL中添加该参数的用户才会看到新布局,其他用户仍然看到旧布局。

基于Zadig + Ingress的蓝绿发布

  • 原理:在Zadig中结合Ingress实现蓝绿发布,通过复制当前工作负载,设置新镜像,并创建一个指向新版本服务的新服务。然后在原有Ingress基础上创建一个相同Host的Ingress,指向新版本服务,并开启Canary配置,按实际情况修改权重配置。当新版本服务稳定后,将生产使用的镜像设置为新镜像,并切断新版本服务的流量,最后清理新版本服务。
  • 案例:一个企业使用Zadig进行应用的持续集成和持续部署。在发布新版本应用时,首先在Zadig中复制当前的生产环境工作负载,设置新版本应用的镜像,并创建一个新的服务指向该工作负载。接着在Ingress中创建一个新的路由规则,将部分流量(如20%)路由到新版本服务。经过一段时间的验证,如果新版本服务运行稳定,再将生产环境的镜像更新为新版本镜像,并关闭新版本服务的Canary配置,完成蓝绿发布。

一、蓝绿发布核心概念与实现方式

蓝绿发布是一种通过维护两个完全独立的生产环境(蓝色和绿色)来实现零停机部署的策略。在Kubernetes中,主要通过Ingress控制器实现流量切换。

三种主要实现方式

  1. 基于权重的流量切换
    • 特点:渐进式流量迁移,精确控制比例
    • 关键注解:canary-weight
    • 适用场景:常规业务系统升级
  2. 基于Header/Cookie的流量切换
    • 特点:定向流量路由,精准用户测试
    • 关键注解:canary-by-header/canary-by-cookie
    • 适用场景:A/B测试、区域验证
  3. 完全环境切换
    • 特点:原子性切换,快速回滚
    • 实现方式:DNS或负载均衡器级别切换
    • 适用场景:关键业务系统升级

二、从0到1的完整蓝绿发布实战案例

1. 初始环境搭建(旧版本)

# 旧版本Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: old-app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: old-app
  template:
    metadata:
      labels:
        app: old-app
    spec:
      containers:
      - name: old-app-container
        image: old-app-image:1.0
        ports:
        - containerPort: 80

# 旧版本Service
apiVersion: v1
kind: Service
metadata:
  name: old-app-service
spec:
  selector:
    app: old-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

# 初始Ingress(100%流量到旧版本)(老版本ingress规则)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: main-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: old-app-service
                port:
                  number: 80

2. 部署新版本准备

# 新版本Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: new-app-deployment
spec:
  replicas: 3  # 保持与旧版本相同副本数
  selector:
    matchLabels:
      app: new-app
  template:
    metadata:
      labels:
        app: new-app
    spec:
      containers:
      - name: new-app-container
        image: new-app-image:2.0
        ports:
        - containerPort: 80

# 新版本Service
apiVersion: v1
kind: Service
metadata:
  name: new-app-service
spec:
  selector:
    app: new-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

三、四种蓝绿发布实战案例

案例1:基于权重的渐进式发布(电商平台升级)

1751616482565

# Canary Ingress配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10" # 初始10%流量
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: new-app-service
                port:
                  number: 80

# 发布流程:
# 1. 初始10%流量到新版本
# 2. 监控无异常后调整至30% → 50% → 80% → 100%
# 3. 完全切换后删除旧版本资源

验证命令

for i in {1..20}; do curl -H "Host: example.com" http://<EXTERNAL_IP>; done
# 预期约2次(10%)访问到新版本

案例2:基于Header的区域发布(CDN服务更新)

1751616482565

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "Region"
    nginx.ingress.kubernetes.io/canary-by-header-pattern: "bj|gz" # 北京/广州
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: new-app-service
                port:
                  number: 80

测试命令

# 北京用户访问新版本
curl -H "Host: example.com" -H "Region: bj" http://<EXTERNAL_IP>

# 其他地区访问旧版本
curl -H "Host: example.com" http://<EXTERNAL_IP>

案例3:基于Cookie的用户测试(教育平台新算法)

发布流程图:

1751616482565

典型测试流程图:

1751616482565

详细步骤:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "test=newalgo"
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: new-app-service
                port:
                  number: 80

测试方法

# 测试用户访问
curl -H "Host: example.com" --cookie "test=newalgo" http://<EXTERNAL_IP>

# 普通用户访问
curl -H "Host: example.com" http://<EXTERNAL_IP>

案例4:基于Query Param的功能预览(新闻网站改版)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-query-param: "layout=new"
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              service:
                name: new-app-service
                port:
                  number: 80

测试方法

# 预览新布局
curl -H "Host: example.com" "http://<EXTERNAL_IP>?layout=new"

# 默认旧布局
curl -H "Host: example.com" http://<EXTERNAL_IP>

四、蓝绿发布最佳实践

发布流程可视化图:

前三种:(省略图片:看上方、四种蓝绿发布实战案例中的三种方式)

下面两种:

完全环境切换流程

1751616482565

紧急回滚流程:

1751616482565

  1. 环境准备

    • 确保蓝绿环境配置完全一致
    • 新版本部署后先进行内部验证
    • 准备监控仪表盘和告警规则
  2. 数据一致性

    1751616482565

    主从复制主从复制数据库蓝色环境DB绿色环境DB缓存蓝色环境缓存绿色环境缓存

  3. 自动化发布流程

    1. 部署绿色环境
    2. 运行自动化测试
    3. 小流量导入(权重/Header)
    4. 监控关键指标
    5. 全量切换
    6. 蓝色环境待命观察
    7. 最终下线蓝色环境
    
    
  4. 回滚策略

    • 权重模式:立即调回100%旧版本
    • Header/Cookie模式:移除Canary Ingress
    • 完全切换模式:DNS切回蓝色环境
  5. 资源优化

    • 使用HPA自动缩放副本数
    • 旧环境保留时间策略(如24小时后自动删除)
    • 考虑使用命名空间隔离蓝绿环境

五、常见问题解决方案

  1. 会话保持问题

    • 方案:确保Session亲和性配置一致
    apiVersion: v1
    kind: Service
    metadata:
      name: app-service
      annotations:
        nginx.ingress.kubernetes.io/affinity: "cookie"
    
    
  2. 配置漂移问题

    • 方案:使用ConfigMap/Secret版本控制
    kubectl rollout history configmap app-config
    
    
  3. 监控指标分离

    • 方案:为不同环境添加不同标签
    template:
      metadata:
        labels:
          app: myapp
          env: blue  # 或 green
    
    
  4. 数据库迁移

    • 推荐工具:
      • Flyway
      • Liquibase
      • 自定义双写中间件

六、总结对比表

策略类型 实现复杂度 回滚速度 资源消耗 适用场景
权重切换 中等 快(秒级) 中(双副本) 常规业务发布
Header控制 A/B测试、区域发布
Cookie控制 特定用户测试
完全切换 最快 高(双环境) 关键业务系统
Query Param 功能预览
posted @ 2025-07-06 01:22  姬高波  阅读(55)  评论(0)    收藏  举报