切换产品类型

您可以点击下拉框切换本产品的不同产品类型,帮助您更高效地阅读文档。

计算
弹性云服务器 ECS
Flexus云服务
裸金属服务器 BMS
弹性伸缩 AS
镜像服务 IMS
专属主机 DeH
函数工作流 FunctionGraph
云手机服务器 CPH
Huawei Cloud EulerOS
网络
虚拟私有云 VPC
弹性公网IP EIP
虚拟专用网络 VPN
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
VPC终端节点 VPCEP
云连接 CC
企业路由器 ER
企业交换机 ESW
全球加速 GA
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
边缘安全 EdgeSec
态势感知 SA
威胁检测服务 MTD
CDN与智能边缘
内容分发网络 CDN
CloudPond云服务
智能边缘云 IEC
迁移
主机迁移服务 SMS
对象存储迁移服务 OMS
云数据迁移 CDM
迁移中心 MGC
大数据
MapReduce服务 MRS
数据湖探索 DLI
表格存储服务 CloudTable
云搜索服务 CSS
数据接入服务 DIS
数据仓库服务 GaussDB(DWS)
数据治理中心 DataArts Studio
数据可视化 DLV
数据湖工厂 DLF
湖仓构建 LakeFormation
企业应用
云桌面 Workspace
应用与数据集成平台 ROMA Connect
云解析服务 DNS
专属云
专属计算集群 DCC
IoT物联网
IoT物联网
设备接入 IoTDA
智能边缘平台 IEF
用户服务
账号中心
费用中心
成本中心
资源中心
企业管理
工单管理
国际站常见问题
ICP备案
我的凭证
支持计划
客户运营能力
合作伙伴支持计划
专业服务
区块链
区块链服务 BCS
Web3节点引擎服务 NES
解决方案
SAP
高性能计算 HPC
视频
视频直播 Live
视频点播 VOD
媒体处理 MPC
实时音视频 SparkRTC
数字内容生产线 MetaStudio
存储
对象存储服务 OBS
云硬盘 EVS
云备份 CBR
存储容灾服务 SDRS
高性能弹性文件服务 SFS Turbo
弹性文件服务 SFS
云硬盘备份 VBS
云服务器备份 CSBS
数据快递服务 DES
专属分布式存储服务 DSS
容器
云容器引擎 CCE
容器镜像服务 SWR
应用服务网格 ASM
华为云UCS
云容器实例 CCI
管理与监管
云监控服务 CES
统一身份认证服务 IAM
资源编排服务 RFS
云审计服务 CTS
标签管理服务 TMS
云日志服务 LTS
配置审计 Config
资源访问管理 RAM
消息通知服务 SMN
应用运维管理 AOM
应用性能管理 APM
组织 Organizations
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
应用身份管理服务 OneAccess
数据库
云数据库 RDS
文档数据库服务 DDS
数据管理服务 DAS
数据复制服务 DRS
云数据库 GeminiDB
云数据库 GaussDB
分布式数据库中间件 DDM
数据库和应用迁移 UGO
云数据库 TaurusDB
人工智能
人脸识别服务 FRS
图引擎服务 GES
图像识别 Image
内容审核 Moderation
文字识别 OCR
AI开发平台ModelArts
图像搜索 ImageSearch
对话机器人服务 CBS
华为HiLens
视频智能分析服务 VIAS
语音交互服务 SIS
应用中间件
分布式缓存服务 DCS
API网关 APIG
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
多活高可用服务 MAS
事件网格 EG
企业协同
华为云会议 Meeting
云通信
消息&短信 MSGSMS
云生态
合作伙伴中心
云商店
开发者工具
SDK开发指南
API签名指南
Terraform
华为云命令行工具服务 KooCLI
其他
产品价格详情
系统权限
管理控制台
客户关联华为云合作伙伴须知
消息中心
公共问题
开发与运维
应用管理与运维平台 ServiceStage
软件开发生产线 CodeArts
需求管理 CodeArts Req
部署 CodeArts Deploy
性能测试 CodeArts PerfTest
编译构建 CodeArts Build
流水线 CodeArts Pipeline
制品仓库 CodeArts Artifact
测试计划 CodeArts TestPlan
代码检查 CodeArts Check
代码托管 CodeArts Repo
云应用引擎 CAE
开天aPaaS
云消息服务 KooMessage
云手机服务 KooPhone
云空间服务 KooDrive
文档首页/ 云容器引擎 CCE/ 最佳实践/ 发布/ 使用Nginx Ingress实现灰度发布和蓝绿发布

使用Nginx Ingress实现灰度发布和蓝绿发布

更新时间:2025-01-08 GMT+08:00

本文将介绍使用Nginx Ingress实现灰度发布和蓝绿发布的应用场景、用法详解及实践步骤。

应用场景

使用Nginx Ingress实现灰度发布适用场景主要取决于业务流量切分的策略,目前Nginx Ingress支持基于Header、Cookie和服务权重三种流量切分的策略,基于这三种策略可实现以下两种发布场景:

  • 场景一:切分部分用户流量到新版本

    假设线上已运行了一套对外提供七层服务的Service A,此时开发了一些新的特性,需要发布上线一个新的版本Service A',但又不想直接替换原有的Service A,而是期望将Header中包含foo=bar或者Cookie中包含foo=bar的用户请求转发到新版本Service A'中。待运行一段时间稳定后,再逐步全量上线新版本,平滑下线旧版本。示意图如下:

  • 场景二:切分一定比例的流量到新版本

    假设线上已运行了一套对外提供七层服务的Service B,此时修复了一些问题,需要发布上线一个新的版本Service B',但又不想直接替换原有的Service B,而是期望将20%的流量切换到新版本Service B'中。待运行一段时间稳定后,再将所有的流量从旧版本切换到新版本中,平滑下线旧版本。

注解说明

Nginx Ingress支持通过配置注解(Annotations)来实现不同场景下的发布和测试,可以满足灰度发布、蓝绿发布、A/B测试等业务场景。具体实现过程如下:为服务创建两个Ingress,一个为常规Ingress,另一个为带nginx.ingress.kubernetes.io/canary: "true"注解的Ingress,称为Canary Ingress;为Canary Ingress配置流量切分策略Annotation,两个Ingress相互配合,即可实现多种场景的发布和测试。Nginx Ingress的Annotation支持以下几种规则:

  • nginx.ingress.kubernetes.io/canary-by-header

    基于Header的流量切分,适用于灰度发布。如果请求头中包含指定的header名称,并且值为“always”,就将该请求转发给Canary Ingress定义的对应后端服务。如果值为“never”则不转发,可用于回滚到旧版本。如果为其他值则忽略该annotation,并通过优先级将请求流量分配到其他规则。

  • nginx.ingress.kubernetes.io/canary-by-header-value

    必须与canary-by-header一起使用,可自定义请求头的取值,包含但不限于“always”“never”。当请求头的值命中指定的自定义值时,请求将会转发给Canary Ingress定义的对应后端服务,如果是其他值则忽略该annotation,并通过优先级将请求流量分配到其他规则。

  • nginx.ingress.kubernetes.io/canary-by-header-pattern

    与canary-by-header-value类似,唯一区别是该annotation用正则表达式匹配请求头的值,而不是某一个固定值。如果该annotation与canary-by-header-value同时存在,该annotation将被忽略。

  • nginx.ingress.kubernetes.io/canary-by-cookie

    基于Cookie的流量切分,适用于灰度发布。与canary-by-header类似,该annotation用于cookie,仅支持“always”“never”,无法自定义取值。

  • nginx.ingress.kubernetes.io/canary-weight

    基于服务权重的流量切分,适用于蓝绿部署。表示Canary Ingress所分配流量的百分比,取值范围[0-100]。例如,设置为100,表示所有流量都将转发给Canary Ingress对应的后端服务。

说明:
  • 以上注解规则会按优先级进行评估,优先级为:canary-by-header -> canary-by-cookie -> canary-weight。
  • 当Ingress被标记为Canary Ingress时,除了nginx.ingress.kubernetes.io/load-balance和nginx.ingress.kubernetes.io/upstream-hash-by外,所有其他非Canary的注解都将被忽略。
  • 更多内容请参阅官方文档Annotations

前提条件

  • 使用Nginx Ingress实现灰度发布的集群,需安装nginx-ingress插件作为Ingress Controller,并且对外暴露统一的流量入口。详细操作可参考安装插件
  • 已上传Nginx镜像至容器镜像服务。为方便观测流量切分效果,Nginx镜像包含新旧两个版本,欢迎页分别为“Old Nginx”“New Nginx”

资源创建方式

本文提供以下两种方式使用YAML部署Deployment和Service:

  • 方式1:在创建无状态工作负载向导页面,单击右侧“YAML创建”,再将本文示例的YAML文件内容输入编辑窗中。
  • 方式2:将本文的示例YAML保存为文件,再使用kubectl指定YAML文件进行创建。例如:kubectl create -f xxx.yaml

步骤1:部署两个版本的服务

在集群中部署两个版本的Nginx服务,并通过Nginx Ingress对外提供七层域名访问。

  1. 创建第一个版本的Deployment和Service,本文以old-nginx为例。YAML示例如下:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: old-nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: old-nginx
      template:
        metadata:
          labels:
            app: old-nginx
        spec:
          containers:
          - image: {your_repository}/nginx:old  # 容器使用的镜像为:nginx:old
            name: container-0
            resources:
              limits:
                cpu: 100m
                memory: 200Mi
              requests:
                cpu: 100m
                memory: 200Mi
          imagePullSecrets:
          - name: default-secret
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: old-nginx
    spec:
      selector:
        app: old-nginx
      ports:
      - name: service0
        targetPort: 80
        port: 8080
        protocol: TCP
      type: NodePort

  2. 创建第二个版本的Deployment和Service,本文以new-nginx为例。YAML示例如下:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: new-nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: new-nginx
      template:
        metadata:
          labels:
            app: new-nginx
        spec:
          containers:
          - image: {your_repository}/nginx:new  # 容器使用的镜像为:nginx:new
            name: container-0
            resources:
              limits:
                cpu: 100m
                memory: 200Mi
              requests:
                cpu: 100m
                memory: 200Mi
          imagePullSecrets:
          - name: default-secret
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: new-nginx
    spec:
      selector:
        app: new-nginx
      ports:
      - name: service0
        targetPort: 80
        port: 8080
        protocol: TCP
      type: NodePort

    您可以登录云容器引擎控制台看部署情况。

  3. 创建Ingress,对外暴露服务,指向old版本的服务。YAML示例如下:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gray-release
      namespace: default
      annotations:
        kubernetes.io/elb.port: '80'
    spec:
      rules:
        - host: www.example.com
          http:
            paths:
              - path: /
                backend:
                  service:
                    name: old-nginx      # 指定后端服务为old-nginx
                    port:
                      number: 80
                property:
                  ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
                pathType: ImplementationSpecific
      ingressClassName: nginx   # 表示使用Nginx Ingress

  4. 执行以下命令,进行访问验证。

    curl -H "Host: www.example.com"  http://<EXTERNAL_IP>

    其中,<EXTERNAL_IP>为Nginx Ingress对外暴露的IP。

    预期输出:

    Old Nginx

步骤2:灰度发布新版本服务

设置访问新版本服务的流量切分策略。云容器引擎CCE支持设置以下三种策略,实现灰度发布和蓝绿发布,您可以根据实际情况进行选择。

基于Header的流量切分基于Cookie的流量切分基于服务权重的流量切分

基于Header、Cookie和服务权重三种流量切分策略均可实现灰度发布;基于服务权重的流量切分策略,调整新服务权重为100%,即可实现蓝绿发布。您可以在下述示例中了解具体使用方法。

注意:

示例中,有以下两点需要注意:

  • 相同服务的Canary Ingress仅能够定义一个,从而使后端服务最多支持两个版本。
  • 即使流量完全切到了Canary Ingress上,旧版服务仍需存在,否则会出现报错。
  • 基于Header的流量切分

    以下示例仅Header中包含Region且值为bj或gz的请求才能转发到新版本服务。

    1. 创建Canary Ingress,指向新版本的后端服务,并增加annotation。
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: canary-ingress
        namespace: default
        annotations:
          nginx.ingress.kubernetes.io/canary: "true"                       # 启用Canary
          nginx.ingress.kubernetes.io/canary-by-header: "Region"
          nginx.ingress.kubernetes.io/canary-by-header-pattern: "bj|gz"    # Header中包含Region且值为bj或gz的请求转发到Canary Ingress
          kubernetes.io/elb.port: '80'
      spec:
        rules:
          - host: www.example.com
            http:
              paths:
                - path: /
                  backend:
                    service:
                      name: new-nginx      # 指定后端服务为new-nginx
                      port:
                        number: 80
                  property:
                    ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
                  pathType: ImplementationSpecific
        ingressClassName: nginx   # 表示使用Nginx Ingress
    2. 执行以下命令,进行访问测试。
      $ curl -H "Host: www.example.com" -H "Region: bj" http://<EXTERNAL_IP>
      New Nginx
      $ curl -H "Host: www.example.com" -H "Region: sh" http://<EXTERNAL_IP>
      Old Nginx
      $ curl -H "Host: www.example.com" -H "Region: gz" http://<EXTERNAL_IP>
      New Nginx
      $ curl -H "Host: www.example.com" http://<EXTERNAL_IP>
      Old Nginx

      其中,<EXTERNAL_IP>为Nginx Ingress对外暴露的IP。

      可以看出,仅当Header中包含Region且值为bj或gz的请求才由新版本服务响应。

  • 基于Cookie的流量切分

    以下示例仅Cookie中包含user_from_bj的请求才能转发到新版本服务。

    1. 创建Canary Ingress,指向新版本的后端服务,并增加annotation。
      说明:

      若您已在上述步骤创建Canary Ingress,则请删除后再参考本步骤创建。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: canary-ingress
        namespace: default
        annotations:
          nginx.ingress.kubernetes.io/canary: "true"                      # 启用Canary
          nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_bj"    # Cookie中包含user_from_bj的请求转发到Canary Ingress
          kubernetes.io/elb.port: '80'
      spec:
        rules:
          - host: www.example.com
            http:
              paths:
                - path: /
                  backend:
                    service:
                      name: new-nginx      # 指定后端服务为new-nginx
                      port:
                        number: 80
                  property:
                    ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
                  pathType: ImplementationSpecific
        ingressClassName: nginx   # 表示使用Nginx Ingress
    2. 执行以下命令,进行访问测试。
      $ curl -s -H "Host: www.example.com" --cookie "user_from_bj=always" http://<EXTERNAL_IP>
      New Nginx
      $ curl -s -H "Host: www.example.com" --cookie "user_from_gz=always" http://<EXTERNAL_IP>
      Old Nginx
      $ curl -s -H "Host: www.example.com" http://<EXTERNAL_IP>
      Old Nginx

      其中,<EXTERNAL_IP>为Nginx Ingress对外暴露的IP。

      可以看出,仅当Cookie中包含user_from_bj且值为always的请求才由新版本服务响应。

  • 基于服务权重的流量切分

    示例1:仅允许20%的流量被转发到新版本服务中,实现灰度发布。

    1. 创建Canary Ingress,并增加annotation,将20%的流量导入新版本的后端服务。
      说明:

      若您已在上述步骤创建Canary Ingress,则请删除后再参考本步骤创建。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: canary-ingress
        namespace: default
        annotations:
          nginx.ingress.kubernetes.io/canary: "true"         # 启用Canary
          nginx.ingress.kubernetes.io/canary-weight: "20"    # 将20%的流量转发到Canary Ingress
          kubernetes.io/elb.port: '80'
      spec:
        rules:
          - host: www.example.com
            http:
              paths:
                - path: /
                  backend:
                    service:
                      name: new-nginx      # 指定后端服务为new-nginx
                      port:
                        number: 80
                  property:
                    ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
                  pathType: ImplementationSpecific
        ingressClassName: nginx   # 表示使用Nginx Ingress
    2. 执行以下命令,进行访问测试。
      $ for i in {1..20}; do curl -H "Host: www.example.com" http://<EXTERNAL_IP>; done;
      Old Nginx
      Old Nginx
      Old Nginx
      New Nginx
      Old Nginx
      New Nginx
      Old Nginx
      New Nginx
      Old Nginx
      Old Nginx
      Old Nginx
      Old Nginx
      Old Nginx
      New Nginx
      Old Nginx
      Old Nginx
      Old Nginx
      Old Nginx
      Old Nginx
      Old Nginx

      其中,<EXTERNAL_IP>为Nginx Ingress对外暴露的IP。

      可以看出,有4/20的几率由新版本服务响应,符合20%服务权重的设置。

      说明:

      基于权重(20%)进行流量切分后,访问到新版本的概率接近20%,流量比例可能会有小范围的浮动,这属于正常现象。

    示例2:允许所有的流量被转发到新版本服务中,实现蓝绿发布。

    1. 创建Canary Ingress,并增加annotation,将100%的流量导入新版本的后端服务。
      说明:

      若您已在上述步骤创建Canary Ingress,则请删除后再参考本步骤创建。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: canary-ingress
        namespace: default
        annotations:
          nginx.ingress.kubernetes.io/canary: "true"          # 启用Canary
          nginx.ingress.kubernetes.io/canary-weight: "100"    # 所有流量均转发到Canary Ingress
          kubernetes.io/elb.port: '80'
      spec:
        rules:
          - host: www.example.com
            http:
              paths:
                - path: /
                  backend:
                    service:
                      name: new-nginx      # 指定后端服务为new-nginx
                      port:
                        number: 80
                  property:
                    ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
                  pathType: ImplementationSpecific
        ingressClassName: nginx   # 表示使用Nginx Ingress
    2. 执行以下命令,进行访问测试。
      $ for i in {1..10}; do curl -H "Host: www.example.com" http://<EXTERNAL_IP>; done;
      New Nginx
      New Nginx
      New Nginx
      New Nginx
      New Nginx
      New Nginx
      New Nginx
      New Nginx
      New Nginx
      New Nginx

      其中,<EXTERNAL_IP>为Nginx Ingress对外暴露的IP。

      可以看出,所有的访问均由新版本服务响应,成功实现了蓝绿发布。

我们使用cookie来确保您的高速浏览体验。继续浏览本站,即表示您同意我们使用cookie。 详情

文档反馈

文档反馈

意见反馈

0/500

标记内容

同时提交标记内容