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处理金丝雀规则的优先级为:
- 基于Header的规则
- 基于Cookie的规则
- 基于权重的规则
2. 使用限制
- 相同服务的Canary Ingress只能定义一个,因此后端服务最多支持两个版本
- Ingress中必须配置域名,否则不会生效
- 即使流量完全切到了Canary Ingress上,旧版服务也必须存在,否则会报错
- 当Ingress被标记为Canary时,除了负载均衡相关的注解外,其他非Canary注解都会被忽略
3. 最佳实践建议
- 渐进式发布:从较小权重(如5-10%)开始,逐步增加
- 监控指标:密切监控新版本的性能指标和错误率
- 回滚机制:准备好快速回滚方案,如将权重设为0或设置Header/Cookie为never
- 清理旧版本:全量发布后,记得删除旧版本服务和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控制器实现流量切换。
三种主要实现方式
- 基于权重的流量切换
- 特点:渐进式流量迁移,精确控制比例
- 关键注解:
canary-weight
- 适用场景:常规业务系统升级
- 基于Header/Cookie的流量切换
- 特点:定向流量路由,精准用户测试
- 关键注解:
canary-by-header
/canary-by-cookie
- 适用场景:A/B测试、区域验证
- 完全环境切换
- 特点:原子性切换,快速回滚
- 实现方式: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:基于权重的渐进式发布(电商平台升级)
# 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服务更新)
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的用户测试(教育平台新算法)
发布流程图:
典型测试流程图:
详细步骤:
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>
四、蓝绿发布最佳实践
发布流程可视化图:
前三种:(省略图片:看上方、四种蓝绿发布实战案例中的三种方式)
下面两种:
完全环境切换流程
紧急回滚流程:
-
环境准备:
- 确保蓝绿环境配置完全一致
- 新版本部署后先进行内部验证
- 准备监控仪表盘和告警规则
-
数据一致性:
主从复制主从复制数据库蓝色环境DB绿色环境DB缓存蓝色环境缓存绿色环境缓存
-
自动化发布流程:
1. 部署绿色环境 2. 运行自动化测试 3. 小流量导入(权重/Header) 4. 监控关键指标 5. 全量切换 6. 蓝色环境待命观察 7. 最终下线蓝色环境
-
回滚策略:
- 权重模式:立即调回100%旧版本
- Header/Cookie模式:移除Canary Ingress
- 完全切换模式:DNS切回蓝色环境
-
资源优化:
- 使用HPA自动缩放副本数
- 旧环境保留时间策略(如24小时后自动删除)
- 考虑使用命名空间隔离蓝绿环境
五、常见问题解决方案
-
会话保持问题:
- 方案:确保Session亲和性配置一致
apiVersion: v1 kind: Service metadata: name: app-service annotations: nginx.ingress.kubernetes.io/affinity: "cookie"
-
配置漂移问题:
- 方案:使用ConfigMap/Secret版本控制
kubectl rollout history configmap app-config
-
监控指标分离:
- 方案:为不同环境添加不同标签
template: metadata: labels: app: myapp env: blue # 或 green
-
数据库迁移:
- 推荐工具:
- Flyway
- Liquibase
- 自定义双写中间件
- 推荐工具:
六、总结对比表
策略类型 | 实现复杂度 | 回滚速度 | 资源消耗 | 适用场景 |
---|---|---|---|---|
权重切换 | 中等 | 快(秒级) | 中(双副本) | 常规业务发布 |
Header控制 | 低 | 快 | 低 | A/B测试、区域发布 |
Cookie控制 | 低 | 快 | 低 | 特定用户测试 |
完全切换 | 高 | 最快 | 高(双环境) | 关键业务系统 |
Query Param | 低 | 快 | 低 | 功能预览 |