概要概要
この記事では、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を構成します。新しいバージョン、その他は引き続き古いバージョンに転送されるため、一部のユーザーは新しいバージョンをグレー表示できます。
シナリオ2:トラフィックの特定の割合を新しいバージョンにカットする
外の世界に7層のサービスを提供する一連のサービスBサービスがオンラインで実行されており、いくつかの問題が後で修正され、新しいバージョンのサービスB 'をグレースケールで起動する必要があると仮定しますが、元のサービスBを直接置き換えるのではなく、最初にカットします。新しいバージョンへのトラフィックの10%、観察期間が安定するのを待ってから、古いバージョンが完全に置き換えられるまで新しいバージョンのトラフィック比率を徐々に増やし、最後に古いバージョンをオフラインにスライドして、新しいバージョンへのトラフィックの一定の割合を達成します。
注釈
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を除いて同様ですが、サポートalways
とnever
値はこれだけです。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-balance
とnginx.ingress.kubernetes.io/upstream-hash-by
を超えて、他のすべての非カナリアコメントは無視されます。
実践的な練習
以下に、NginxIngressのカナリアリリースをすばやく開始できるようにするための例をいくつか示します。環境はTKEクラスターです。
YAMLを使用してリソースを作成する
この記事の例では、yamlを使用してワークロードをデプロイし、サービスを作成します。操作には2つの方法があります。
方法1:TKEまたはEKSコンソールの右上隅をクリックYAML 创建资源
し、この記事のyamlの例を貼り付けます。
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
コンソールで展開ステータスを確認できます。
別の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_cd
はCookiealways
のみです。
サービスの重みに基づくトラフィックのセグメンテーション
サービスの重みに基づく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を使用して、いくつかの異なるポーズでカナリアリリースを実装していますが、まだいくつかの欠陥があります。
- 同じサービスのCanaryIngressを1つだけ定義できるため、バックエンドサービスは最大2つのバージョンをサポートします。
- ドメイン名はIngressで設定する必要があります。設定しないと、有効になりません。
- Canary Ingressへのトラフィックが完全に遮断された場合でも、古いサービスが存在している必要があります。存在しない場合、エラーが報告されます。
総括する
この記事では、Nginx Ingressのカナリアパブリッシングの使用法を総合的にまとめています。NginxIngressのカナリアパブリッシングの機能は限られており、まだいくつかの欠陥がありますが、基本的にいくつかの一般的なシナリオをカバーできます。Nginxがクラスターで使用されている場合入力、および公開要件は複雑ではないため、このソリューションの使用を検討できます。
参照
- Nginx Ingress Canary Annotation公式ドキュメント:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary
- Nginx IngressをTKEにデプロイします:https://cloud.tencent.com/document/product/457/47293