NginxIngressを使用してカナリアリリースを達成する方法を教えてください

概要概要

この記事では、Nginx Ingressを使用して、使用シナリオの分析から詳細な使用、そして実践的な実践まで、カナリアリリースを実現する方法を紹介します。

前提条件

クラスタは、NginxIngressをIngressControllerとして展開する必要があり、外部エントリの統一されたフローを公開しました。TKEでのNginxIngressの展開を参照してください

Nginx Ingressはどのような公開シナリオで使用できますか?

カナリアリリースを達成するためにNginxIngressを使用できるシナリオは何ですか?これは主に、トラフィックセグメンテーションに使用される戦略によって異なります。現在、Nginx Ingressは、ヘッダー、Cookie、およびサービスウェイトに基づく3つのトラフィックセグメンテーション戦略をサポートしています。これらに基づいて、次の2つの公開シナリオを実装できます。

シナリオ1:一部のユーザーに新しいバージョンをグレースケールする

外の世界に7層のサービスを提供する一連のサービスAサービスがオンラインで実行されており、後で新しいバージョンのサービスAが開発されたと仮定します。オンラインにしたいのですが、元のサービスAを直接置き換えたくありません。最初に少数のユーザーをグレー表示したいと思います。一定期間動作が安定した後、新しいバージョンが徐々にリリースされ、最終的に古いバージョンがスムーズにオフラインになります。現時点では、Nginx Ingressを使用して、ヘッダーまたはCookieに基づくトラフィックセグメンテーションの戦略を公開できます。ビジネスでは、ヘッダーまたはCookieを使用して、さまざまなタイプのユーザーを識別します。指定されたヘッダーまたはCookieを持つリクエストがに転送されることを認識するようにIngressを構成します。新しいバージョン、その他は引き続き古いバージョンに転送されるため、一部のユーザーは新しいバージョンをグレー表示できます。

img

シナリオ2:トラフィックの特定の割合を新しいバージョンにカットする

外の世界に7層のサービスを提供する一連のサービスBサービスがオンラインで実行されており、いくつかの問題が後で修正され、新しいバージョンのサービスB 'をグレースケールで起動する必要があると仮定しますが、元のサービスBを直接置き換えるのではなく、最初にカットします。新しいバージョンへのトラフィックの10%、観察期間が安定するのを待ってから、古いバージョンが完全に置き換えられるまで新しいバージョンのトラフィック比率を徐々に増やし、最後に古いバージョンをオフラインにスライドして、新しいバージョンへのトラフィックの一定の割合を達成します。

img

注釈

Nginx Ingress Ingressリソースでサポートされているカナリアリリースを指定するためのアノテーションを使用して実現できます。サービスへの2つのイングレス(通常のイングレス)を作成する必要があります。もう1つは、nginx.ingress.kubernetes.io/canary: "true"イングレスでこの固定アノテーションを使用するため、カナリアと呼びます。 Ingressは通常、サービスの新しいバージョンを表し、トラフィックセグメンテーション戦略の別の注釈と組み合わせて、さまざまなシナリオでカナリアリリースを実現するように一緒に構成できます。これらの注釈の詳細な概要は次のとおりです。

  • nginx.ingress.kubernetes.io/canary-by-header:要求ヘッダーにここで指定されたヘッダー名と値が含まれているかどうかを示しalways、要求をIngressで定義された対応するバックエンドサービスにnever転送します。値が転送されない場合は、古いバージョンにロールバックするために使用できます。他の値は注釈を無視します。
  • nginx.ingress.kubernetes.io/canary-by-header-value:これはcanary-by-header補足として使用でき、リクエストヘッダーを他の値にカスタマイズできるように指定できます。isalwaysまたはnever;ここでカスタムリクエストヘッダー値の値がヒットすると、リクエストは対応する定義済みの入力に転送されます。バックエンドサービス。他の値の場合、注釈は無視されます。
  • nginx.ingress.kubernetes.io/canary-by-header-pattern:上記とcanary-by-header-value同様の唯一の違いは、特定の固定値ではなく、リクエストヘッダーに一致する正規の式であるということです。canary-by-header-value同時に存在する場合、注釈は無視されることに注意してください。
  • nginx.ingress.kubernetes.io/canary-by-cookie:これcanary-by-headerはCookieを除いて同様ですが、サポートalwaysneverはこれだけです。
  • nginx.ingress.kubernetes.io/canary-weight:Canary Ingressによって割り当てられたトラフィックの割合を示します。値の範囲は[0-100]です。たとえば、10に設定すると、トラフィックの10%がCanaryIngressに対応するバックエンドサービスに割り当てられます。

上記のルールは、優先度の高い順に評価されます。 canary-by-header -> canary-by-cookie -> canary-weight

注:イングレス進入がカナリーとしてマークされている場合は、ほかnginx.ingress.kubernetes.io/load-balancenginx.ingress.kubernetes.io/upstream-hash-byを超えて、他のすべての非カナリアコメントは無視されます。

実践的な練習

以下に、NginxIngressのカナリアリリースをすばやく開始できるようにするための例をいくつか示します。環境はTKEクラスターです。

YAMLを使用してリソースを作成する

この記事の例では、yamlを使用してワークロードをデプロイし、サービスを作成します。操作には2つの方法があります。

方法1:TKEまたはEKSコンソールの右上隅をクリックYAML 创建资源し、この記事のyamlの例を貼り付けます。

img

2番目の方法:yamlの例をファイルに保存してから、kubectlyamlで指定されたファイルを使用して次のように作成しますkubectl apply -f xx.yaml

2つのバージョンのサービスを展開する

例として簡単なnginxを次に示します。最初に、v1バージョンをデプロイします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      version: v1
  template:
    metadata:
      labels:
        app: nginx
        version: v1
    spec:
      containers:
      - name: nginx
        image: "openresty/openresty:centos"
        ports:
        - name: http
          protocol: TCP
          containerPort: 80
        volumeMounts:
        - mountPath: /usr/local/openresty/nginx/conf/nginx.conf
          name: config
          subPath: nginx.conf
      volumes:
      - name: config
        configMap:
          name: nginx-v1
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app: nginx
    version: v1
  name: nginx-v1
data:
  nginx.conf: |-
    worker_processes  1;
    events {
        accept_mutex on;
        multi_accept on;
        use epoll;
        worker_connections  1024;
    }
    http {
        ignore_invalid_headers off;
        server {
            listen 80;
            location / {
                access_by_lua '
                    local header_str = ngx.say("nginx-v1")
                ';
            }
        }
    }
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-v1
spec:
  type: ClusterIP
  ports:
  - port: 80
    protocol: TCP
    name: http
  selector:
    app: nginx
    version: v1

別のv2バージョンをデプロイします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      version: v2
  template:
    metadata:
      labels:
        app: nginx
        version: v2
    spec:
      containers:
      - name: nginx
        image: "openresty/openresty:centos"
        ports:
        - name: http
          protocol: TCP
          containerPort: 80
        volumeMounts:
        - mountPath: /usr/local/openresty/nginx/conf/nginx.conf
          name: config
          subPath: nginx.conf
      volumes:
      - name: config
        configMap:
          name: nginx-v2
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app: nginx
    version: v2
  name: nginx-v2
data:
  nginx.conf: |-
    worker_processes  1;
    events {
        accept_mutex on;
        multi_accept on;
        use epoll;
        worker_connections  1024;
    }
    http {
        ignore_invalid_headers off;
        server {
            listen 80;
            location / {
                access_by_lua '
                    local header_str = ngx.say("nginx-v2")
                ';
            }
        }
    }
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-v2
spec:
  type: ClusterIP
  ports:
  - port: 80
    protocol: TCP
    name: http
  selector:
    app: nginx
    version: v2

コンソールで展開ステータスを確認できます。

img

別のIngressを作成して、サービスのv1バージョンを指し、サービスを外部に公開します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: nginx-v1
          servicePort: 80
        path: /

訪問確認:

$ curl -H "Host: canary.example.com" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
nginx-v1

ヘッダーベースのトラフィックセグメンテーション

Canary Ingressを作成し、バックエンドサービスのv2バージョンを指定し、いくつかの注釈を追加して、Regionという名前のリクエストヘッダーとcdまたはszの値を持つリクエストのみが現在のCanary Ingressに転送され、シミュレートされたグレースケールの新しいバージョンがChengduに送信されるようにします。深セン地域のユーザー:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "Region"
    nginx.ingress.kubernetes.io/canary-by-header-pattern: "cd|sz"
  name: nginx-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: nginx-v2
          servicePort: 80
        path: /

テスト訪問:

$ curl -H "Host: canary.example.com" -H "Region: cd" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
nginx-v2
$ curl -H "Host: canary.example.com" -H "Region: bj" http://EXTERNAL-IP
nginx-v1
$ curl -H "Host: canary.example.com" -H "Region: cd" http://EXTERNAL-IP
nginx-v2
$ curl -H "Host: canary.example.com" http://EXTERNAL-IP
nginx-v1

ご覧のとおりRegionヘッダーがcdまたはszであるリクエストのみがv2バージョンサービスによって応答されます。

Cookieベースのトラフィックセグメンテーション

前と同様のヘッダーですが、Cookie値を使用してカスタマイズすることはできません。たとえば、Chengduユーザーの灰色の領域をシミュレートするために、たとえば、user_from_cd現在のCanaryIngressの名前だけでリクエストをCookieに転送します。まず、ヘッダートラフィックのセグメンテーションに基づいて以前のカナリアイングレスを削除してから、次の新しいカナリアイングレスを作成します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_cd"
  name: nginx-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: nginx-v2
          servicePort: 80
        path: /

テスト訪問:

$ curl -s -H "Host: canary.example.com" --cookie "user_from_cd=always" http://EXTERNAL-IP # EXTERNAL-IP 替换为 Nginx Ingress 自身对外暴露的 IP
nginx-v2
$ curl -s -H "Host: canary.example.com" --cookie "user_from_bj=always" http://EXTERNAL-IP
nginx-v1
$ curl -s -H "Host: canary.example.com" http://EXTERNAL-IP
nginx-v1

ご覧のとおり、v2バージョンのサービスによるリクエストへの応答user_from_cdCookiealwaysのみです。

サービスの重みに基づくトラフィックのセグメンテーション

サービスの重みに基づくCanaryIngressは単純で、インポートする必要のあるトラフィックの割合を直接定義します。これは、トラフィックの10%をv2にインポートする例です(存在する場合は、前のCanary Ingressを削除します)。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
  name: nginx-canary
spec:
  rules:
  - host: canary.example.com
    http:
      paths:
      - backend:
          serviceName: nginx-v2
          servicePort: 80
        path: /

テスト訪問:

$ for i in {1..10}; do curl -H "Host: canary.example.com" http://EXTERNAL-IP; done;
nginx-v1
nginx-v1
nginx-v1
nginx-v1
nginx-v1
nginx-v1
nginx-v2
nginx-v1
nginx-v1
nginx-v1

v2バージョンのサービスが応答する可能性は10分の1であり、10%のサービスウェイト設定を満たしていることがわかります。

既存の欠陥

Nginx Ingressを使用して、いくつかの異なるポーズでカナリアリリースを実装していますが、まだいくつかの欠陥があります。

  1. 同じサービスのCanaryIngressを1つだけ定義できるため、バックエンドサービスは最大2つのバージョンをサポートします。
  2. ドメイン名はIngressで設定する必要があります。設定しないと、有効になりません。
  3. Canary Ingressへのトラフィックが完全に遮断された場合でも、古いサービスが存在している必要があります。存在しない場合、エラーが報告されます。

総括する

この記事では、Nginx Ingressのカナリアパブリッシングの使用法を総合的にまとめています。NginxIngressのカナリアパブリッシングの機能は限られており、まだいくつかの欠陥がありますが、基本的にいくつかの一般的なシナリオをカバーできます。Nginxがクラスターで使用されている場合入力、および公開要件は複雑ではないため、このソリューションの使用を検討できます。

参照

おすすめ

転載: blog.51cto.com/14120339/2543143