参考 : https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary

创建2个nginx版本分别为v1与v2

# Nginx v1 配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config-v1
data:
  index.html: |
    <p class="version">This is Nginx Version 1.0</p>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
      version: v1
  template:
    metadata:
      labels:
        app: nginx
        version: v1
    spec:
      containers:
      - name: nginx
        image: registry.kylincloud.org:4001/kcc/images/nginx:1.23.1
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-html-v1
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nginx-html-v1
        configMap:
          name: nginx-config-v1
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-v1
spec:
  selector:
    app: nginx
    version: v1
  ports:
  - port: 80
    targetPort: 80
  type: NodePort
---

# Nginx v2 配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config-v2
data:
  index.html: |
    <p class="version">This is Nginx Version 2.0</p>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
      version: v2
  template:
    metadata:
      labels:
        app: nginx
        version: v2
    spec:
      containers:
      - name: nginx
        image: registry.kylincloud.org:4001/kcc/images/nginx:1.23.1
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-html-v2
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nginx-html-v2
        configMap:
          name: nginx-config-v2
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-v2
spec:
  selector:
    app: nginx
    version: v2
  ports:
  - port: 80
    targetPort: 80
  type: NodePort

创建ingress

# 第一个Ingress定义,用于常规服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-v1  # 定义Ingress的名称
spec:
  ingressClassName: ingress-nginx
  rules:
  - host: nginx.lyx.com  # 设置主机名,所有的请求都会被转发到这个域名下的服务
    http:
      paths:
      - backend:
          service:
            name: nginx-service-v1
            port:
              number: 80  # 指定后端服务监听的端口
        path: /  # 所有访问根路径的请求都会被转发到此服务
        pathType: Prefix  # 路径类型为前缀,表示所有以"/"开头的请求都将被转发到此服务

流量切分

canary规则按优先级顺序进行评估。优先级如下:请求头(canary-by-header)→ Cookie (canary-by-cookie)→ 权重(canary-weight)

Tip

当某个 ingress 标记为canary时,除了nginx.ingress.kubernetes.io/load-balance、nginx.ingress.kubernetes.io/upstream-hash-by以及与会话亲和性相关的注解外,其他所有非canary注解都会被忽略(这些注解会从对应的主 ingress 继承)。如果您希望恢复canary的原始行为(即忽略会话亲和性),请在canary的ingress 定义中设置注解 nginx.ingress.kubernetes.io/affinity-canary-behavior,并将其值设为legacy

流量切分---基于权重的灰度发布

## 第二个Ingress定义,用于灰度发布服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:  # 添加注解来控制灰度发布
    nginx.ingress.kubernetes.io/canary: "true"  # 开启灰度发布模式
    nginx.ingress.kubernetes.io/canary-weight: "10"  # 设置灰度发布的权重为10%,即10%的流量会被路由至此服务
  name: canary-v2  # 定义Ingress的名称
spec:
  ingressClassName: ingress-nginx
  rules:
  - host: nginx.lyx.com  # 设置主机名,所有的请求都会被转发到这个域名下的服务
    http:
      paths:
      - backend:
          service:
            name: nginx-service-v2
            port:
              number: 80  # 指定后端服务监听的端口
        path: /  # 所有访问根路径的请求都会被转发到此服务
        pathType: Prefix  # 路径类型为前缀,表示所有以"/"开头的请求都将被转发到此服务

访问测试

[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>

ingress日志

10.42.42.215 - - [11/Aug/2025:15:45:17 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.017 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.1.240:80 49 0.017 200 d95ea8fd385cdd9ff2cbbf6864fd20f6
10.42.42.215 - - [11/Aug/2025:15:45:18 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.011 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.011 200 4000402fa79014b4a67c0666216d33dc
10.42.42.215 - - [11/Aug/2025:15:45:19 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.004 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.004 200 6a255fdd7a772194202abde616d9cdc8
10.42.42.215 - - [11/Aug/2025:15:45:19 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.033 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.033 200 1b194da2053c441a1d0bf8d5a5a97324
10.42.42.215 - - [11/Aug/2025:15:45:20 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.003 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.003 200 0f26b64c4ab606a0ddd3f10075833110
10.42.42.215 - - [11/Aug/2025:15:45:20 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.016 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.016 200 eb3ce85c093a344008d5455fe42c77ee
10.42.42.215 - - [11/Aug/2025:15:45:21 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.019 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.1.240:80 49 0.019 200 40b91965d1a470fcb06f250a0054103a
10.42.42.215 - - [11/Aug/2025:15:45:21 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.013 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.013 200 a6f91c529d693629930605ad20026756
10.42.42.215 - - [11/Aug/2025:15:45:22 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.006 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.006 200 f0d2115b945cdb5f1cefb3fa77786c6d
10.42.42.215 - - [11/Aug/2025:15:45:23 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.013 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.014 200 32e1a4370112292029c7698c3969f6a9
10.42.42.215 - - [11/Aug/2025:15:45:23 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.013 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.013 200 82837580f752bdf27dd1dc7cb3d94de9
10.42.42.215 - - [11/Aug/2025:15:45:24 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.047 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.047 200 ebbc9337bf107e092b5108305ba17b26
10.42.42.215 - - [11/Aug/2025:15:45:24 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.017 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.017 200 c387cc0bb9ca2f16a92a85adbc2d6066
10.42.42.215 - - [11/Aug/2025:15:45:25 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.003 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.003 200 86aa9bca9724a2a3253d3547f5e3d5fb
10.42.42.215 - - [11/Aug/2025:15:45:26 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.024 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.0.168:80 49 0.025 200 29678f4334c59b6105d03a553ea4d2d1

流量切分---基于请求头的灰度发布

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-header-new  # 定义第二个Ingress资源的名称
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"  # 开启灰度发布模式
    nginx.ingress.kubernetes.io/canary-by-header: "canary"  # 指定使用HTTP头部来区分流量
    nginx.ingress.kubernetes.io/canary-by-header-value: "new"  # 指定HTTP头部的值为"new"时,请求会被路由到新版本服务
spec:
  ingressClassName: ingress-nginx
  rules:
  - host: nginx.lyx.com  # 设置主机名,所有请求都会被转发到这个域名下的服务
    http:
      paths:
      - backend:
          service:
            name: nginx-service-v2
            port:
              number: 80  # 指定后端服务监听的端口
        path: /  # 所有访问根路径的请求都会被转发到此服务
        pathType: Prefix  # 路径类型为前缀,表示所有以"/"开头的请求都将被转发到此服务

访问测试

[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl -H "canary: new" nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>
[root@node2 ~]# curl -H "canary: new" nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>
[root@node2 ~]# curl -H "canary: new" nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>

ingress日志

10.42.42.215 - - [11/Aug/2025:15:54:14 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.012 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.012 200 6a4931aba828dfd9179a3000294ffd6a
10.42.42.215 - - [11/Aug/2025:15:54:15 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.006 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.006 200 f7bf797308eff3880b86799b9cb5a77d
10.42.42.215 - - [11/Aug/2025:15:54:15 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.008 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.008 200 d95b5e889c5b856c358858f334c3ad1a
10.42.42.215 - - [11/Aug/2025:15:54:19 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.005 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.005 200 3360a1161ae52f80de976f6db0df679e
10.42.42.215 - - [11/Aug/2025:15:54:20 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.016 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.016 200 1a983a1a2a2e2139000d3cb8aee91680
10.42.42.215 - - [11/Aug/2025:15:54:20 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.004 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.004 200 686fe639c8c094ee4ecf425ed1ee8dde
10.42.42.215 - - [11/Aug/2025:15:54:37 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.031 [default-nginx-service-v1-80] [] 10.119.0.167:80 49 0.030 200 e80775fb331c4bdd5ebb39a38ce75266
10.42.42.215 - - [11/Aug/2025:15:54:46 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 90 0.004 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.1.240:80 49 0.004 200 02c764ac9dfb23cef1f498493e50dc0e
10.42.42.215 - - [11/Aug/2025:15:54:47 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 90 0.004 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.0.168:80 49 0.004 200 ad2bdd119e40147392a6a1233a9205f3
10.42.42.215 - - [11/Aug/2025:15:54:48 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 90 0.009 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.1.240:80 49 0.009 200 21c8ea19289b31f5f8b4cb8763089d77

流量切分---基于cookie的灰度发布

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: canary-cookie-new  # 定义第二个Ingress资源的名称
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_xx"
spec:
  ingressClassName: ingress-nginx
  rules:
  - host: nginx.lyx.com  # 设置主机名,所有请求都会被转发到这个域名下的服务
    http:
      paths:
      - backend:
          service:
            name: nginx-service-v2
            port:
              number: 80  # 指定后端服务监听的端口
        path: /  # 所有访问根路径的请求都会被转发到此服务
        pathType: Prefix  # 路径类型为前缀,表示所有以"/"开头的请求都将被转发到此服务

访问测试

当cookie值被设置为always时,它将被路由到canary。当cookie设置为never时,它将永远不会被路由到canary。对于任何其他值,cookie将被忽略,并按优先级将请求与其他canary规则进行比较。

[root@node2 ~]# curl nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl --cookie "user_from_xx" nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl --cookie "user_from_xx=ddd" nginx.lyx.com
<p class="version">This is Nginx Version 1.0</p>
[root@node2 ~]# curl --cookie "user_from_xx=always" nginx.lyx.com
<p class="version">This is Nginx Version 2.0</p>

ingress日志

10.42.42.215 - - [11/Aug/2025:16:08:55 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.007 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.006 200 517f2139a12bf464b0c1ba397404d6f2
10.42.42.215 - - [11/Aug/2025:16:08:59 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 77 0.004 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.004 200 bdfa6fc5814bbd899704054a848736b0
10.42.42.215 - - [11/Aug/2025:16:09:01 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 103 0.002 [default-nginx-service-v1-80] [] 10.119.1.239:80 49 0.002 200 b87f52a700b759ac5c5087e976fb701f
10.42.42.215 - - [11/Aug/2025:16:09:04 +0800] "GET / HTTP/1.1" 200 49 "-" "curl/7.66.0" 106 0.006 [default-nginx-service-v1-80] [default-nginx-service-v2-80] 10.119.1.240:80 49 0.006 200 7936ce0c4cf85d5699dc486cb2a3b87a