You need to enable JavaScript to run this app.
导航

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

最近更新时间2024.03.21 15:40:06

首次发布时间2024.03.21 15:40:06

Nginx Ingress 支持基于注解(Annotation)实现灰度发布和蓝绿发布。本文为您介绍如何使用 Nginx Ingress 实现蓝绿发布和灰度发布。

背景信息

什么是灰度发布

灰度发布,也称为金丝雀发布(Canary Release),是一种软件发布的策略,它允许开发者逐步地将新版本软件部署到生产环境中,而不是一次性发布。这样做的目的是为了降低软件发布时的风险,通过在小范围内先行发布来观察软件的表现,确保新版本稳定之后再全面推广。

灰度发布的主要特点包括:

  • 逐步发布:不是一次性对所有用户发布新版本,而是按照计划逐步扩大发布范围,比如先对1%的用户开放,观察一段时间后再扩大到10%,最终全面发布。
  • 风险控制:通过限制新版本软件的受众范围,可以在出现问题时迅速回滚,避免大规模影响。
  • 实时监控:在灰度发布期间,需要密切监控软件运行状况,包括性能指标、用户反馈等,确保新版本的稳定性。
  • 灵活回滚:如果新版本出现严重问题,可以快速回滚到旧版本,最小化对用户的影响。

灰度发布对于确保软件质量和用户体验非常重要,特别是在大规模和复杂的系统中。它使得团队能够更加灵活和安全地管理软件发布过程,减少潜在的风险。

Nginx Ingress 发布流程

Nginx Ingress 支持通过配置 Annotation 实现不同场景下的业务发布,包括:灰度发布、蓝绿发布、A/B 测试等。发布流程如下:

  1. 在集群中创建两个应用和服务。
  2. 为服务创建两个 Ingress,一个为普通 Nginx Ingress,另一个为包含nginx.ingress.kubernetes.io/canary: "true"注解的 Ingress,被称为 Canary Nginx Ingress。
  3. 使用 Annotation 为 Canary Nginx Ingress 配置流量切分策略,即可实现多种场景下的灰度发布。

alt

Nginx Ingress 注解说明

Nginx Ingress 支持通过配置以下 Annotation,实现灰度发布:

  • nginx.ingress.kubernetes.io/canary-by-header:基于 Header 的流量切分策略,适用于灰度发布。如果 Header 中包含指定的名称,并且值为 “always”,就将该请求转发给 Canary Nginx Ingress 指定的后端服务。
  • nginx.ingress.kubernetes.io/canary-by-header-value:与canary-by-header搭配使用,用于 Header 的取值,包含但不限于“always”“never”。当 Header 的值命中自定义值时,请求将会转发给 Canary Nginx Ingress 指定的后端服务。
  • nginx.ingress.kubernetes.io/canary-by-header-pattern:与canary-by-header-value使用方法类似,区别为该 Annotation 用正则表达式匹配 Header 的值,而不是固定值。

    说明

    如果该 Annotation 与canary-by-header-value同时存在,则该Annotation将被忽略。

  • nginx.ingress.kubernetes.io/canary-by-cookie:基于 Cookie 的流量切分策略,适用于灰度发布。如果 Header 中 Cookie 包含指定的名称,且值为“always”“never”,就将该请求转发给 Canary Nginx Ingress 指定的后端服务。Cookie 流量切分策略无法自定义取值。
  • nginx.ingress.kubernetes.io/canary-weight:基于服务权重的流量切分策略,适用于蓝绿发布。表示 Canary Nginx Ingress 所分配流量的百分比,取值范围为 0~100。当设置为 100 时,表示所有流量都将转发给 Canary Nginx Ingress 指定的后端服务。

说明

  • 上述 Annotation 的优先级为:canary-by-header > canary-by-cookie > canary-weight
  • 当 Nginx Ingress 被标记为 Canary Nginx Ingress 时,除了nginx.ingress.kubernetes.io/load-balancenginx.ingress.kubernetes.io/upstream-hash-by外,其他非Canary的注解都会被忽略。
  • 更多 Annotation 详情,请参见 官方文档

前提条件

在集群中部署服务

  1. 使用如下 YAML 配置,创建旧版本应用和服务。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-old
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-old
  template:
    metadata:
      labels:
        app: nginx-old
    spec:
      containers:
      - name: nginx
        image: doc-cn-beijing.cr.volces.com/vke/nginx-demo:v2.0
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: service-old
spec:
  selector:
    app: nginx-old
  ports:
  - name: rule
    protocol: TCP
    port: 80
    targetPort: 80
  type: NodePort
  1. 使用如下 YAML 配置,创建新版本的应用和服务。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-new
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-new
  template:
    metadata:
      labels:
        app: nginx-new
    spec:
      containers:
      - name: nginx
        image: doc-cn-beijing.cr.volces.com/vke/nginx-demo:v3.0
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: service-new
spec:
  selector:
    app: nginx-new
  ports:
  - name: rule
    protocol: TCP
    port: 80
    targetPort: 80
  type: NodePort
  1. 使用如下 YAML 配置,创建 Nginx Ingress,并指向旧版本服务。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-old # 路由规则的名称
spec:
  ingressClassName: nginx # 指定 Ingress Controller
  rules:
    - host: example.com  # 需要对外提供访问的域名
      http:
        paths:
        - pathType: Prefix # 路径匹配规则,默认为 Prefix(前缀匹配)
          path: / # 请求匹配的路径
          backend:
            service:
              name: service-old # 需要对接的服务名称
              port: 
                number: 80 # 需要对接服务的端口号
  1. 执行以下命令,验证是否可以访问到旧版本服务。其中,<EXTERNAL_IP>为 Nginx Ingress 对外暴露的 IP 地址。
curl -H "Host: example.com" http://<EXTERNAL_IP>

预期结果如下,访问到了后端旧版本的应用。

This is the old version of nginx

配置灰度发布

Nginx Ingress 支持基于 Header、Cookie 和服务权重三种流量切分策略,实现灰度发布。

注意

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

基于 Header 实现灰度发布

  1. 使用如下 YAML 配置,配置 Canary Nginx Ingress,指向新版本服务。使用 Annotation 启用并配置 Canary,基于 Header 实现流量筛选和转发。在本例中,访问请求 Header 中包含Region且值为beijing时,请求转发到新版本服务。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-new # 路由规则的名称
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 启用 Canary
    nginx.ingress.kubernetes.io/canary-by-header: "Region" # 配置基于 Header 的流量切分策略
    nginx.ingress.kubernetes.io/canary-by-header-pattern: "beijing" # Header 中包含 Region 且值为 beijing 的请求进行转发
spec:
  ingressClassName: nginx # 指定 Ingress Controller
  rules:
    - host: example.com  # 需要对外提供访问的域名
      http:
        paths:
        - pathType: Prefix # 路径匹配规则,默认为 Prefix(前缀匹配)
          path: / # 请求匹配的路径
          backend:
            service:
              name: service-new # 需要对接的服务名称
              port: 
                number: 80 # 需要对接服务的端口号
  1. 执行以下命令,进行访问测试,预期结果如下。
    • Region不存在时,转发到旧版本服务。
    curl -H "Host: example.com" http://<EXTERNAL_IP>
    This is the old version of nginx
    
    • Region存在且值不为beijing时,转发到旧版本服务。
    curl -H "Host: example.com" -H "Region: shanghai" http://<EXTERNAL_IP>
    This is the old version of nginx
    
    • Region存在且值为beijing时,转发到新版本服务。
    curl -H "Host: example.com" -H "Region: beijing" http://<EXTERNAL_IP>
    This is the new version of nginx
    
  1. 使用如下 YAML 配置,配置 Canary Nginx Ingress,指向新版本服务。使用 Annotation 启用并配置 Canary,基于 Cookie 实现流量筛选和转发。在本例中,访问请求Cookie的值为beijing时,请求转发到新版本服务。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-new # 路由规则的名称
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 启用 Canary
    nginx.ingress.kubernetes.io/canary-by-cookie: "beijing" # 配置基于 Cookie 的流量切分策略
spec:
  ingressClassName: nginx # 指定 Ingress Controller
  rules:
    - host: example.com  # 需要对外提供访问的域名
      http:
        paths:
        - pathType: Prefix # 路径匹配规则,默认为 Prefix(前缀匹配)
          path: / # 请求匹配的路径
          backend:
            service:
              name: service-new # 需要对接的服务名称
              port: 
                number: 80 # 需要对接服务的端口号
  1. 执行以下命令,进行访问测试,预期结果如下。
    • Cookie不存在时,转发到旧版本服务。
    curl -H "Host: example.com" http://<EXTERNAL_IP>
    This is the old version of nginx
    
    • Cookie存在且不为beijing时,转发到旧版本服务。
    curl -s -H "Host: example.com" --cookie "shanghai=always" http://<EXTERNAL_IP>
    This is the old version of nginx
    
    • Cookie存在且为beijing时,转发到新版本服务。
    curl -s -H "Host: example.com" --cookie "beijing=always" http://<EXTERNAL_IP>
    This is the new version of nginx
    

基于服务权重实现灰度发布

  1. 使用如下 YAML 配置,配置 Canary Nginx Ingress,指向新版本服务。使用 Annotation 启用并配置 Canary,基于服务权重实现流量筛选和转发。在本例中,将 25% 的访问请求转发到新版本服务。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-new # 路由规则的名称
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 启用 Canary
    nginx.ingress.kubernetes.io/canary-weight: "25" # 配置基于服务权重的流量切分策略,转发权重为 25,表示将 25% 的流量转发到新版本服务
spec:
  ingressClassName: nginx # 指定 Ingress Controller
  rules:
    - host: example.com  # 需要对外提供访问的域名
      http:
        paths:
        - pathType: Prefix # 路径匹配规则,默认为 Prefix(前缀匹配)
          path: / # 请求匹配的路径
          backend:
            service:
              name: service-new # 需要对接的服务名称
              port: 
                number: 80 # 需要对接服务的端口号
  1. 执行以下命令,进行 20 次访问测试。
for i in {1..20}; do curl -H "Host: example.com" http://<EXTERNAL_IP>; done;

预期结果如下,有 25% 的流量转发到了新版本服务。

This is the old version of nginx
This is the new version of nginx
This is the old version of nginx
This is the new version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the new version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the new version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the old version of nginx
This is the new version of nginx

说明

由于样本量较小(20 次),实际验证时可能会出现局部的数据偏差,属于正常情况。您可以多验证几次,或扩大样本数量。

配置蓝绿发布

  1. 基于服务权重的流量切分策略,当配置新服务的权重为 100% 时,即可实现蓝绿发布。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-new # 路由规则的名称
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 启用 Canary
    nginx.ingress.kubernetes.io/canary-weight: "100" # 配置新服务权重为 100%,表示蓝绿发布
spec:
  ingressClassName: nginx # 指定 Ingress Controller
  rules:
    - host: example.com  # 需要对外提供访问的域名
      http:
        paths:
        - pathType: Prefix # 路径匹配规则,默认为 Prefix(前缀匹配)
          path: / # 请求匹配的路径
          backend:
            service:
              name: service-new # 需要对接的服务名称
              port: 
                number: 80 # 需要对接服务的端口号
  1. 执行以下命令,进行 20 次访问测试。
for i in {1..20}; do curl -H "Host: example.com" http://<EXTERNAL_IP>; done;

预期结果如下。所有的的流量均转发到了新版本服务,同时保留了旧版本服务,可以根据需求进行流量切换和回滚。

This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx
This is the new version of nginx