全部產品
Search
文件中心

:通過Nginx Ingress實現灰階發布和藍綠髮布

更新時間:Jun 20, 2024

當對服務進行版本更新升級時,需要使用到滾動升級、分批暫停發布、藍綠髮布以及灰階發布等發布方式。本文將介紹在ACK叢集中如何通過Nginx Ingress Controller來實現應用服務的灰階發布。

背景資訊

灰階及藍綠髮布是為新版本建立一個與老版本完全一致的生產環境,在不影響老版本的前提下,按照一定的規則把部分流量切換到新版本,當新版本試運行一段時間沒有問題後,將使用者的全量流量從老版本遷移至新版本。

其中藍綠髮布就是一種灰階發布方式,一部分使用者繼續使用老版本的服務,將一部分使用者的流量切換到新版本,如果新版本運行穩定,則逐步將所有使用者移轉到新版本。

Container ServiceACK控制台調整了灰階發布功能的用法,分為兩種。

  • canary-*註解方式:使用canary-* Annotation配置藍綠髮布與灰階發布,canary-* Annotation是社區官方實現的灰階發布方式。

  • service-*註解方式:使用service-* Annotation配置藍綠髮布與灰階發布。service-* Annotation是ACK Nginx Ingress Controller早期實現灰階發布的方式。service-matchservice-weight功能已不再維護,並即將廢棄。service-* Annotation功能目前仍正常保留,不影響使用。

應用情境

基於用戶端請求的流量切分情境

假設當前線上環境,您已經有一套服務Service A對外提供7層服務,此時上線了一些新的特性,需要發布上線一個新的版本Service A'。但又不想直接替換Service A服務,而是希望將要求標頭中包含foo=bar或者Cookie中包含foo=bar的用戶端請求轉寄到Service A'服務中。待運行一段時間穩定後,可將所有的流量從Service A切換到Service A'服務中,再平滑地將Service A服務下線。

基於服務權重的流量切分情境

假設當前線上環境,您已經有一套服務Service B對外提供7層服務,此時修複了一些問題,需要發布上線一個新的版本Service B'。但又不想將所有用戶端流量切換到新版本Service B'中,而是希望將20%的流量切換到新版本Service B'中。待運行一段時間穩定後,再將所有的流量從Service B切換到Service B'服務中,再平滑地將Service B服務下線。

針對以上多種不同的應用發布需求,阿里雲Container ServiceIngress Controller支援了多種流量切分方式:

  • 基於Request Header的流量切分,適用於灰階發布以及AB測試情境。

  • 基於Cookie的流量切分,適用於灰階發布以及AB測試情境。

  • 基於Query Param的流量切分,適用於灰階發布以及AB測試情境。

  • 基於服務權重的流量切分,適用於藍綠髮布情境。

canary-*註解方式

註解說明

Nginx Ingress Controller通過下列canary-* Annotation來支援應用服務的灰階發布機制。

Annotation

說明

適用的ACK Nginx Ingress Controller版本

nginx.ingress.kubernetes.io/canary

  • 必須設定該Annotation值為true,否則其他規則將不會生效。

  • 取值:

    • true:啟用canary功能。

    • false:不啟用canary功能。

≥v0.22.0

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

  • 表示基於要求標頭的名稱進行灰階發布。

  • 要求標頭名稱的特殊取值:

    • always:無論什麼情況下,流量均會進入灰階服務。

    • never:無論什麼情況下,流量均不會進入灰階服務。

  • 若沒有指定要求標頭名稱的值,則只要該頭存在,都會進行流量轉寄。

≥v0.22.0

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

  • 表示基於要求標頭的值進行灰階發布。

  • 需要與canary-by-header頭配合使用。

≥v0.30.0

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

  • 表示基於要求標頭的值進行灰階發布,並對要求標頭的值進行正則匹配。

  • 需要與canary-by-header頭配合使用。

  • 取值為用於匹配要求標頭的值的Regex。

≥v0.44.0

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

  • 表示基於Cookie進行灰階發布。例如,nginx.ingress.kubernetes.io/canary-by-cookie: foo

  • Cookie內容的取值:

    • always:當foo=always,流量會進入灰階服務。

    • never:當foo=never,流量不會進入灰階服務。

  • 只有當Cookie存在,且值為always時,才會進行流量轉寄。

≥v0.22.0

nginx.ingress.kubernetes.io/canary-weight

  • 表示基於權重進行灰階發布。

  • 取值範圍:0~權重總值。

  • 若未設定總值,預設總值為100。

≥v0.22.0

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

  • 表示設定的權重總值。

  • 若未設定總值,預設總值為100。

≥v1.1.2

不同灰階方式的優先順序由高到低為:

canary-by-header>canary-by-cookie>canary-weight

說明

目前每個Ingress規則只支援同時指定一個Canary Ingress,大於一個的Canary Ingress將會被忽略。

步驟一:部署服務

部署Nginx服務並通過Nginx Ingress Controller對外提供7層網域名稱訪問。

  1. 建立Deployment和Service。

    1. 建立nginx.yaml

      展開查看YAML檔案

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: old-nginx
      spec:
        replicas: 2
        selector:
          matchLabels:
            run: old-nginx
        template:
          metadata:
            labels:
              run: old-nginx
          spec:
            containers:
            - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/old-nginx
              imagePullPolicy: Always
              name: old-nginx
              ports:
              - containerPort: 80
                protocol: TCP
            restartPolicy: Always
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: old-nginx
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 80
        selector:
          run: old-nginx
        sessionAffinity: None
        type: NodePort
    2. 執行以下命令,建立Deployment和Service。

      kubectl apply -f nginx.yaml
  2. 部署Ingress。

    1. 建立ingress.yaml

      1.19版本之前叢集

      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: gray-release
      spec:
        rules:
        - host: www.example.com
          http:
            paths:
            # 老版本服務。
            - path: /
              backend:
                serviceName: old-nginx
                servicePort: 80

      1.19及之後版本叢集

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: gray-release
      spec:
        rules:
        - host: www.example.com
          http:
            paths:
            # 老版本服務。
            - path: /
              backend:
                service: 
                  name: old-nginx
                  port:
                    number: 80
              pathType: ImplementationSpecific
    2. 執行以下命令,部署Ingress。

      kubectl apply -f ingress.yaml
  3. 測試訪問情況。

    1. 執行以下命令,擷取外部IP。

      kubectl get ingress
    2. 執行以下命令,查看路由訪問情況。

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

      預期輸出:

      old

步驟二:灰階發布新版本服務

發布一個新版本的Nginx服務並配置路由規則。

  1. 部署新版本的Deployment和Service。

    1. 建立nginx1.yaml

      展開查看YAML檔案

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: new-nginx
      spec:
        replicas: 1
        selector:
          matchLabels:
            run: new-nginx
        template:
          metadata:
            labels:
              run: new-nginx
          spec:
            containers:
            - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/new-nginx
              imagePullPolicy: Always
              name: new-nginx
              ports:
              - containerPort: 80
                protocol: TCP
            restartPolicy: Always
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: new-nginx
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 80
        selector:
          run: new-nginx
        sessionAffinity: None
        type: NodePort
    2. 執行以下命令,部署新版本的Deployment和Service。

      kubectl apply -f nginx1.yaml
  2. 設定訪問新版本服務的路由規則。

    ACK支援設定以下三種路由規則,您可以根據實際情況選擇路由規則。

    • 設定滿足特定規則的用戶端才能訪問新版本服務。以下樣本僅要求標頭中滿足foo=bar的用戶端請求才能路由到新版本服務。

      1. 按照以上條件,在ingress1.yaml檔案中建立新的Ingress資源gray-release-canary

        1.19版本之前叢集

        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        metadata:
          name: gray-release-canary
          annotations:
            # 開啟Canary。
            nginx.ingress.kubernetes.io/canary: "true"
            # 要求標頭為foo。
            nginx.ingress.kubernetes.io/canary-by-header: "foo"
            # 要求標頭foo的值為bar時,請求才會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/canary-by-header-value: "bar"
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 新版本服務。
              - path: /
                backend:
                  serviceName: new-nginx
                  servicePort: 80

        1.19及之後版本叢集

        apiVersion: networking.k8s.io/v1
        kind: Ingress
        metadata:
          name: gray-release-canary
          annotations:
            # 開啟Canary。
            nginx.ingress.kubernetes.io/canary: "true"
            # 要求標頭為foo。
            nginx.ingress.kubernetes.io/canary-by-header: "foo"
            # 要求標頭foo的值為bar時,請求才會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/canary-by-header-value: "bar"
            
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 新版本服務。
              - path: /
                backend:
                  service: 
                    name: new-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
      2. 執行以下命令,部署Ingress1。

        kubectl apply -f ingress1.yaml
      3. 執行以下命令,擷取外部IP。

        kubectl get ingress
      4. 查看路由訪問情況。

        1. 執行以下命令,訪問服務。

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

          預期輸出:

          old
        2. 執行以下命令,要求標頭中滿足foo=bar的用戶端請求訪問服務。

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

          預期輸出:

          new

        重複執行以上命令,可以看到,僅要求標頭中滿足foo=bar的用戶端請求才能路由到新版本服務。

    • 在特定規則未被滿足時,再按照一定比例將請求路由到新版本服務中。以下樣本要求要求標頭中滿足foo=bar的用戶端請求,若不包含該要求標頭,會將50%的流量路由到新版本服務中。

      1. 按照以下內容,修改步驟2中建立的Ingress。

        1.19版本之前叢集

        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        metadata:
          name: gray-release-canary
          annotations:
            # 開啟Canary。
            nginx.ingress.kubernetes.io/canary: "true"
            # 要求標頭為foo。
            nginx.ingress.kubernetes.io/canary-by-header: "foo"
            # 要求標頭foo的值為bar時,請求才會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/canary-by-header-value: "bar"
            # 在未滿足上述匹配規則的基礎上僅允許50%的流量會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/canary-weight: "50"
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 新版本服務。
              - path: /
                backend:
                  serviceName: new-nginx
                  servicePort: 80

        1.19及之後版本叢集

        apiVersion: networking.k8s.io/v1
        kind: Ingress
        metadata:
          name: gray-release-canary
          annotations:
            # 開啟Canary。
            nginx.ingress.kubernetes.io/canary: "true"
            # 要求標頭為foo。
            nginx.ingress.kubernetes.io/canary-by-header: "foo"
            # 要求標頭foo的值為bar時,請求才會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/canary-by-header-value: "bar"
            # 在未滿足上述匹配規則的基礎上僅允許50%的流量會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/canary-weight: "50"
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 新版本服務。
              - path: /
                backend:
                  service: 
                    name: new-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
      2. 執行以下命令,部署Ingress。

        kubectl apply -f ingress.yaml
      3. 執行以下命令,擷取外部IP。

        kubectl get ingress
      4. 查看路由訪問情況。

        1. 執行以下命令,訪問服務。

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

          預期輸出:

          old

        2. 執行以下命令,要求標頭中滿足foo=bar的用戶端請求訪問服務。

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

          預期輸出:

          new
        • foo=bar要求標頭:

          請求流量100%會路由到新版本new-nginx服務中,由canary-by-headercanary-by-header-value控制。

        • 沒有foo=bar要求標頭:

          請求流量50%會路由到新版本new-nginx服務中,由canary-weight控制。

    • 設定一定比例的請求被路由到新版本服務中,以下樣本中僅50%的流量被路由到新版本服務中。

      1. 按照以下內容,修改步驟2建立的Ingress。

        1.19版本之前叢集

        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        metadata:
          name: gray-release-canary
          annotations:
            # 開啟Canary。
            nginx.ingress.kubernetes.io/canary: "true"
            # 僅允許50%的流量會被路由到新版本服務new-nginx中。
            # 預設總值為100。
            nginx.ingress.kubernetes.io/canary-weight: "50"
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 新版本服務。
              - path: /
                backend:
                  serviceName: new-nginx
                  servicePort: 80

        1.19及之後版本叢集

        apiVersion: networking.k8s.io/v1
        kind: Ingress
        metadata:
          name: gray-release-canary
          annotations:
            # 開啟Canary。
            nginx.ingress.kubernetes.io/canary: "true"
            # 僅允許50%的流量會被路由到新版本服務new-nginx中。
            # 預設總值為100。
            nginx.ingress.kubernetes.io/canary-weight: "50"
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 新版本服務。
              - path: /
                backend:
                  service: 
                    name: new-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
      2. 執行以下命令,部署Ingress。

        kubectl apply -f ingress.yaml

      3. 執行以下命令,擷取外部IP。

        kubectl get ingress

      4. 執行以下命令,查看路由訪問情況。

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

      重複執行以上命令,可以看到僅50%的流量路由到新版本服務。

步驟三:刪除老版本服務

系統運行一段時間後,當新版本服務已經穩定並且符合預期後,需要下線老版本的服務 ,僅保留新版本服務線上上運行。為了達到該目標,需要將舊版本的Service指向新版本服務的Deployment,並且刪除舊版本的Deployment和新版本的Service。

  1. 修改舊版本Service檔案nginx.yaml,使其指向新版本服務。

    展開查看YAML檔案

    apiVersion: v1
    kind: Service
    metadata:
      name: old-nginx
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        # 指向新版本服務。
        run: new-nginx
      sessionAffinity: None
      type: NodePort
  2. 執行以下命令,部署舊版本服務。

    kubectl apply -f nginx.yaml
  3. 執行以下命令,擷取外部IP。

    kubectl get ingress
  4. 執行以下命令,查看路由訪問情況。

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

    預期輸出:

    new

    重複執行以上命令,可以看到請求全部被路由到了新版本的服務。

  5. 執行以下命令,刪除Canary Ingress資源gray-release-canary

    kubectl delete ingress gray-release-canary
  6. 刪除舊版本的Deployment和新版本的Service。

    1. 執行以下命令,刪除舊版本的Deployment。

      kubectl delete deploy old-nginx
    2. 執行以下命令,刪除新版本的Service。

      kubectl delete svc new-nginx

service-*註解方式

註解說明

Nginx Ingress Controller通過下列Annotation來支援應用服務的灰階發布機制。

  • nginx.ingress.kubernetes.io/service-match

    該註解用來配置新版本服務的路由匹配規則。

    nginx.ingress.kubernetes.io/service-match: | 
        <service-name>: <match-rule>
    # 參數說明:
    # service-name:服務名稱,滿足match-rule的請求會被路由到該服務中。
    # match-rule:路由匹配規則
    #
    # 路由匹配規則:
    # 1. 支援的匹配類型
    # - header:基於要求標頭,支援正則匹配和完整匹配。
    # - cookie:基於cookie,支援正則匹配和完整匹配。
    # - query:基於請求參數,支援正則匹配和完整匹配。
    #
    # 2. 匹配方式
    # - 正則匹配格式:/{regular expression}/,使用反斜線(//)表明採用正則方式匹配。
    # - 完整匹配格式:"{exact expression}",使用引號("")表明採用完整方式匹配。

    路由匹配規則配置樣本:

    # 要求標頭中滿足foo正則匹配^bar$的請求被轉寄到新版本服務new-nginx中。
    new-nginx: header("foo", /^bar$/)
    # 要求標頭中滿足foo完整匹配bar的請求被轉寄到新版本服務new-nginx中。
    new-nginx: header("foo", "bar")
    # cookie中滿足foo正則匹配^sticky-.+$的請求被轉寄到新版本服務new-nginx中。
    new-nginx: cookie("foo", /^sticky-.+$/)
    # query param中滿足foo完整匹配bar的請求被轉寄到新版本服務new-nginx中。
    new-nginx: query("foo", "bar")
  • nginx.ingress.kubernetes.io/service-weight

    該註解用來配置新舊版本服務的流量權重。

    nginx.ingress.kubernetes.io/service-weight: | 
        <new-svc-name>:<new-svc-weight>, <old-svc-name>:<old-svc-weight>
    參數說明:
    new-svc-name:新版本服務名稱
    new-svc-weight:新版本服務權重
    old-svc-name:舊版本服務名稱
    old-svc-weight:舊版本服務權重

    服務權重配置樣本:

    nginx.ingress.kubernetes.io/service-weight: | 
        new-nginx: 20, old-nginx: 60

步驟一:部署服務

部署Nginx服務並通過Nginx Ingress Controller對外提供7層網域名稱訪問。

  1. 建立Deployment和Service。

    1. 建立nginx.yaml

      展開查看YAML檔案

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: old-nginx
      spec:
        replicas: 2
        selector:
          matchLabels:
            run: old-nginx
        template:
          metadata:
            labels:
              run: old-nginx
          spec:
            containers:
            - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/old-nginx
              imagePullPolicy: Always
              name: old-nginx
              ports:
              - containerPort: 80
                protocol: TCP
            restartPolicy: Always
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: old-nginx
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 80
        selector:
          run: old-nginx
        sessionAffinity: None
        type: NodePort
    2. 執行以下命令,建立Deployment和Service。

      kubectl apply -f nginx.yaml
  2. 部署Ingress。

    1. 建立ingress.yaml

      1.19版本之前叢集

      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: gray-release
      spec:
        rules:
        - host: www.example.com
          http:
            paths:
            # 老版本服務。
            - path: /
              backend:
                serviceName: old-nginx
                servicePort: 80

      1.19及之後版本叢集

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: gray-release
      spec:
        rules:
        - host: www.example.com
          http:
            paths:
            # 老版本服務。
            - path: /
              backend:
                service: 
                  name: old-nginx
                  port:
                    number: 80
              pathType: ImplementationSpecific
    2. 執行以下命令,部署Ingress。

      kubectl apply -f ingress.yaml
  3. 測試訪問情況。

    1. 執行以下命令,擷取外部IP。

      kubectl get ingress
    2. 執行以下命令,查看路由訪問情況。

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

      預期輸出:

      old

步驟二:灰階發布新版本服務

發布一個新版本的Nginx服務並配置路由規則。

  1. 部署新版本的Deployment和Service。

    1. 建立nginx1.yaml

      展開查看YAML檔案

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: new-nginx
      spec:
        replicas: 1
        selector:
          matchLabels:
            run: new-nginx
        template:
          metadata:
            labels:
              run: new-nginx
          spec:
            containers:
            - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/new-nginx
              imagePullPolicy: Always
              name: new-nginx
              ports:
              - containerPort: 80
                protocol: TCP
            restartPolicy: Always
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: new-nginx
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 80
        selector:
          run: new-nginx
        sessionAffinity: None
        type: NodePort
    2. 部署新版本的Deployment和Service。

      kubectl apply -f nginx1.yaml
  2. 設定訪問新版本服務的路由規則。

    ACK支援設定以下三種路由規則,您可以根據實際情況選擇路由規則。

    • 設定滿足特定規則的用戶端才能訪問新版本服務。以下樣本僅要求標頭中滿足foo=bar的用戶端請求才能路由到新版本服務。

      1. 按照以下內容,修改步驟2建立的Ingress。

      1.19版本之前叢集

      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: gray-release
        annotations:
          # 要求標頭中滿足正則匹配foo=bar的請求才會被路由到新版本服務new-nginx中。
          nginx.ingress.kubernetes.io/service-match: | 
            new-nginx: header("foo", /^bar$/)
      spec:
        rules:
        - host: www.example.com
          http:
            paths:
            # 老版本服務。
            - path: /
              backend:
                serviceName: old-nginx
                servicePort: 80
            # 新版本服務。
            - path: /
              backend:
                serviceName: new-nginx
                servicePort: 80

      1.19及之後版本叢集

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: gray-release
        annotations:
          # 要求標頭中滿足正則匹配foo=bar的請求才會被路由到新版本服務new-nginx中。
          nginx.ingress.kubernetes.io/service-match: | 
            new-nginx: header("foo", /^bar$/)
      spec:
        rules:
        - host: www.example.com
          http:
            paths:
            # 老版本服務。
            - path: /
              backend:
                service: 
                  name: old-nginx
                  port:
                    number: 80
              pathType: ImplementationSpecific
            # 新版本服務。
            - path: /
              backend:
                service: 
                  name: new-nginx
                  port:
                    number: 80
              pathType: ImplementationSpecific
      1. 執行以下命令,部署Ingress。

        kubectl apply -f ingress.yaml
      2. 執行以下命令,擷取外部IP。

        kubectl get ingress
      3. 查看路由訪問情況。

        1. 執行以下命令,訪問服務。

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

          預期輸出:

          old

        2. 執行以下命令,要求標頭中滿足foo=bar的用戶端請求訪問服務。

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

          預期輸出:

          new

      重複執行以上命令,可以看到,僅要求標頭中滿足foo=bar的用戶端請求才能路由到新版本服務。

    • 在滿足特定規則的基礎上設定一定比例的請求被路由到新版本服務中。以下樣本要求要求標頭中滿足foo=bar的用戶端請求,且僅允許其中50%的流量被路由到新版本服務中。

      1. 按照以下內容,修改步驟2建立的Ingress。

        1.19版本之前叢集

        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        metadata:
          name: gray-release
          annotations:
            # 要求標頭中滿足正則匹配foo=bar的請求才會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/service-match: |
                new-nginx: header("foo", /^bar$/)
            # 在滿足上述匹配規則的基礎上僅允許50%的流量會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/service-weight: |
                new-nginx: 50, old-nginx: 50
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 老版本服務。
              - path: /
                backend:
                  serviceName: old-nginx
                  servicePort: 80
              # 新版本服務。
              - path: /
                backend:
                  serviceName: new-nginx
                  servicePort: 80
         servicePort: 80

        1.19及之後版本叢集

        apiVersion: networking.k8s.io/v1
        kind: Ingress
        metadata:
          name: gray-release
          annotations:
            # 要求標頭中滿足正則匹配foo=bar的請求才會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/service-match: |
                new-nginx: header("foo", /^bar$/)
            # 在滿足上述匹配規則的基礎上僅允許50%的流量會被路由到新版本服務new-nginx中。
            nginx.ingress.kubernetes.io/service-weight: |
                new-nginx: 50, old-nginx: 50
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 老版本服務。
              - path: /
                backend:
                  service: 
                    name: old-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
              # 新版本服務。
              - path: /
                backend:
                  service: 
                    name: new-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
      2. 執行以下命令,部署Ingress。

        kubectl apply -f ingress.yaml
      3. 執行以下命令,擷取外部IP。

        kubectl get ingress

      4. 查看路由訪問情況。

        1. 執行以下命令,訪問服務。

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

          預期輸出:

          old

        2. 執行以下命令,要求標頭中滿足foo=bar的用戶端請求訪問服務。

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

          預期輸出:

          new

        重複執行以上命令。可以看到,僅要求標頭中滿足foo=bar的用戶端請求,且只有50%的流量才能路由到新版本服務。

    • 設定一定比例的請求被路由到新版本服務中,以下樣本中僅50%的流量被路由到新版本服務中。

      1. 按照以下內容,修改步驟2建立的Ingress。

        1.19版本之前叢集

        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        metadata:
          name: gray-release
          annotations:
              # 允許50%的流量被路由到新版本服務new-nginx中。
              nginx.ingress.kubernetes.io/service-weight: |
                  new-nginx: 50, old-nginx: 50
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 老版本服務。
              - path: /
                backend:
                  serviceName: old-nginx
                  servicePort: 80
              # 新版本服務。
              - path: /
                backend:
                  serviceName: new-nginx
                  servicePort: 80

        1.19及之後版本叢集

        apiVersion: networking.k8s.io/v1
        kind: Ingress
        metadata:
          name: gray-release
          annotations:
              # 允許50%的流量被路由到新版本服務new-nginx中。
              nginx.ingress.kubernetes.io/service-weight: |
                  new-nginx: 50, old-nginx: 50
        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              # 老版本服務。
              - path: /
                backend:
                  service: 
                    name: old-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
              # 新版本服務。
              - path: /
                backend:
                  service: 
                    name: new-nginx
                    port:
                      number: 80
                pathType: ImplementationSpecific
      2. 執行以下命令,部署Ingress。

        kubectl apply -f ingress.yaml
      3. 執行以下命令,擷取外部IP。

        kubectl get ingress

      4. 執行以下命令,查看路由訪問情況。

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

        重複執行以上命令,可以看到僅50%的流量路由到新版本服務。

步驟三:刪除老版本服務

系統運行一段時間後,當新版本服務已經穩定並且符合預期後,需要下線老版本的服務 ,僅保留新版本服務線上上運行。

  1. 按照以下內容,修改步驟2建立的Ingress。

    1.19版本之前叢集

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: gray-release
    spec:
      rules:
      - host: www.example.com
        http:
          paths:
          # 新版本服務。
          - path: /
            backend:
              serviceName: new-nginx
              servicePort: 80

    1.19及之後版本叢集

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gray-release
    spec:
      rules:
      - host: www.example.com
        http:
          paths:
          # 新版本服務。
          - path: /
            backend:
              service: 
                name: new-nginx
                port:
                  number: 80
            pathType: ImplementationSpecific
  2. 執行以下命令,部署Ingress。

    kubectl apply -f ingress.yaml
  3. 執行以下命令,擷取外部IP。

    kubectl get ingress

  4. 執行以下命令,查看路由訪問情況。

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

    預期輸出:

    new

    重複執行以上命令,可以看到請求全部被路由到了新版本的服務。

  5. 刪除舊版本的Deployment和Service。

    1. 執行以下命令,刪除舊版本的Deployment。

      kubectl delete deploy <Deployment名稱>
    2. 執行以下命令,刪除舊版本的Service。

      kubectl delete svc <Service名稱>