1. はじめに
以前ArgoRolloutsを利用したBlue/Greenデプロイの検証結果をまとめましたが、今回はカナリアデプロイの動作について検証します。
以前実施したBlue/Greenデプロイ方式の動作検証結果はこちらとなります。
環境はBlue/Greenデプロイ検証と同じmninikube
を利用します。
またアプリもBlue/Greenデプロイ検証で利用したアプリを利用するため、Blueアプリ・Greenアプリと呼びます。
2. ArgoRolloutsを利用したカナリアデプロイについて
ArgoRolloutsではデプロイ戦略にカナリアデプロイが利用できます。
カナリアデプロイでは指定した重みに基づいてリクエストを新旧のアプリに振り分けます。
通常のRolloutとServiceの構成では、リクエストの重みのみが設定可能ですが、Ingressを利用することでヘッダー情報によるリクエストの振り分けることも可能です。
今回は下記の方式について検証することにします。
- 通常の重み付けによるリクエストの振り分け方式
- Nginx Ingress Controllerによる振り分け方式
Ingressを利用するトラフィック制御はNginx以外にもALBやistioなども利用可能です。
3. 通常の重み付けによるリクエストの振り分け方式
3.1 概要
下図の順にカナリアデプロイが動作することを検証します。
今回の例では下記の順でGreenアプリがデプロイされ、リクエストが振り分けられます。
(1). リクエストの20%をGreenアプリに振り分ける
(2). 手動でのPromote後にリクエストの50%をGreenアプリに振り分ける
(3). Promote完了の60秒後にリクエストの80%Greenアプリに振り分ける
(4). すべてのリクエストをGreenアプリに振り分ける
3.1 マニフェストファイルの作成
Rolloutリソースに対応するServiceリソースを作成します。
apiVersion: v1
kind: Service
metadata:
name: rollout-canary-rest-api-app-svc
spec:
selector:
app: rollout-canary-rest-api-app
type: NodePort
ports:
- protocol: TCP
port: 8080
targetPort: 8080
Blue/Greenデプロイと同様、マニフェストファイルのkindはDeployment
ではなくRollout
になります。
また、Rollout
の構造はDeployment
とよく似ていますが、strategy:
にデプロイ戦略の設定を追記します。
カナリアリリースの場合は、canary.steps
で各Stepでの操作を指定します。
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout-canary-rest-api-app
spec:
replicas: 5
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollout-canary-rest-api-app
template:
metadata:
labels:
app: rollout-canary-rest-api-app
spec:
containers:
- name: rollout-canary-rest-api-app
image: rest-api-app:blue
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
strategy:
canary:
steps:
- setWeight: 20
- pause: {}
- setWeight: 50
- pause: {duration: 60}
- setWeight: 80
- pause: {}
3.2 カナリアデプロイの実行
カナリアデプロイを実行するため、Serviceリソースを立ち上げます。
また、minikube
のコマンドを利用してServiceのURLを取得します。
$ kubectl apply -n sample canary-service.yaml
$ minikube service -n sample rollout-canary-rest-api-app-svc --url
http://192.168.49.2:30576
3.2.1 Blueアプリのリリース
Rolloutリソースをデプロイします。
Rolloutリソースのイメージタグはblue
を指定しているため、レスポンスもblue
となります。
$ kubectl apply -n sample -f canary-rollout.yaml
$ curl http://192.168.49.2:30576/sample/version
{"appVersion":"blue","env":" default"}
ArgoRolloutでのダッシュボードは下記のとおりとなります。
3.2.2 Greenアプリのリリース
canary-rollout.yaml
のイメージタグをgreen
に変更し、Rolloutリソースをデプロイします。
すでにBlueアプリがデプロイ済みのため、新規にGreenアプリのアプリが立ち上がります。
リクエストの振り分けは20%となっているため、1/5の確率でGreenアプリからレスポンスが返ります。
$ kubectl apply -n sample -f canary-rollout.yaml
$ curl http://192.168.49.2:30576/sample/version
{"appVersion":"blue","env":" default"}
{"appVersion":"blue","env":" default"}
{"appVersion":"blue","env":" default"}
{"appVersion":"blue","env":" default"}
{"appVersion":"green","env":" default"}
ArgoRolloutでのダッシュボードでもGreenアプリのPodが立ち上がっていることがわかります。
その後、promote
コマンドを実行しGreenアプリのPod数を増やします。
リクエストを50%ずつに割り振るため、blue
/green
それぞれのアプリのPod数は3となります。
$ kubectl argo rollouts promote -n sample rollout-canary-rest-api-app
promote
コマンド実行完了の60秒後にリクエストの振り分けを80%にするためPod数の調整が自動で実行されます。
Pod数の自動調整後promote
コマンドを実行します。
promote
コマンド実行によりblue
バージョンのPodは縮退し、すべてのPodがgreen
バージョンに切り替わります。
4. Nginx Ingress Controllerによる振り分け方式
4.1 概要 {#nginx-abstract}
Nginx Ingress Controllerによりリクエストを振り分けます。
Nginx Ingress Controllerによるトラッフィク制御については下記に記載されています。
今回検証したアプリの構成は下図のとおりです。
また、今回の検証に当たりこちらの記事を参考にしました。
4.2 MinikubeのIngress設定
Minikube環境を利用しているのでIngressを有効化する必要があります。
下記コマンドによりIngressを有効化します。
$ minikube addons enable ingress
4.3 マニフェストファイルの作成
Serviceのマニフェストを下記のように定義します。
4.1 概要に記載した通り、Serviceは2つ必要となります。
apiVersion: v1
kind: Service
metadata:
name: rollout-canary-rest-api-app-svc-stable
spec:
selector:
app: rollout-canary-rest-api-app
type: NodePort
ports:
- protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: rollout-canary-rest-api-app-svc-canary
spec:
selector:
app: rollout-canary-rest-api-app
type: NodePort
ports:
- protocol: TCP
port: 8080
targetPort: 8080
次にNginx Ingress Controllerリソースをデプロイする必要があります。
Ingressのマニフェストは下記のとおりです。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rollout-canary-stable-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: rollout-canary-rest-api-app.info
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rollout-canary-rest-api-app-svc-stable
port:
number: 8080
最後にRolloutリソースを定義します。
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout-canary-rest-api-app
spec:
replicas: 4
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollout-canary-rest-api-app
template:
metadata:
labels:
app: rollout-canary-rest-api-app
spec:
containers:
- name: rollout-canary-rest-api-app
image: rest-api-app:blue
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
strategy:
canary:
stableService: rollout-canary-rest-api-app-svc-stable
canaryService: rollout-canary-rest-api-app-svc-canary
trafficRouting:
nginx:
stableIngress: rollout-canary-stable-ingress
annotationPrefix: nginx.ingress.kubernetes.io
additionalIngressAnnotations:
canary-by-header: 'X-Canary'
canary-by-header-value: 'true'
canary-weight: '0'
steps:
- setWeight: 10
- pause: {}
strategy:canary:
に2つのServiceを設定します。
また、trafficRouting
にリクエストの振り分けルールを定義します。
そして、steps
に重みを設定します。
この設定により、リクエストのヘッダにX-Canary:true
が設定されたリクエストはカナリア面に振り分けられます。
一方でヘッダが設定されていないリクエストは重みの設定に従い、10%の確率でカナリア面に振り分けられます。
また、これら以外にもCookie
によるリクエストの振り分けも可能です。
ルーティングの制御ルールには優先度があり、canary-by-header
が最も優先度高くcanary-by-cookie
、canary-weight
の順となります。
詳細は下記を参照ください。
4.4 カナリアデプロイの実行
4.4.1 Blueアプリのリリース
Nginxを利用するため、IPではなくホスト名でアクセスする必要があります。
まずはMinikubeが公開しているIPを下記コマンドで調べます。
$ minikube ip
判明したIPを/etc/hosts
に設定します。
ホスト名にはIngressのマニフェストに記載したhost
部となります。
# Ingress hosts configuration
192.168.49.2 rollout-canary-rest-api-app.info
Rolloutリソースをデプロイします。
Rolloutリソースのイメージタグはblue
を指定しているため、レスポンスもblue
となります。
$ curl http://rollout-canary-rest-api-app.info/sample/version
{"appVersion":"blue","env":" default"}
4.4.2 Greenアプリのリリース
canary-rollout.yaml
のイメージタグをgreen
に変更し、Rolloutリソースをデプロイします。
すでにBlueアプリがデプロイ済みのため、新規にGreenアプリが立ち上がります。
Podの数は下図のとおりです。
リクエストの振り分けは10%となっているため、1/10の確率でGreenアプリからレスポンスが返ります。
$ curl http://rollout-canary-rest-api-app.info/sample/version
{"appVersion":"blue","env":" default"}
{"appVersion":"blue","env":" default"}
・・・
{"appVersion":"green","env":" default"}
次に、リクエストヘッダーを付与してリクエストすると、Greenアプリからレスポンスが返ります。
$ curl -H 'X-Canary:true' http://rollout-canary-rest-api-app.info/sample/version
{"appVersion":"green","env":" default"}
以上のことからNginx Ingress Controllerによる振り分け制御が有効化されていることがわかります。