なになれ

IT系のことを記録していきます

Kubernetesでカナリアリリースを試す

Kubernetesではコンテナイメージを実行するのにDeploymentが使われます。
ただこのDeploymentではカナリアリリースを実現することはできません。
そこでArgo Rolloutsを使って、カナリアリリースを試します。

argoproj.github.io

以下に試した内容を紹介します。
Argo Rolloutsのバージョンはv0.9.1時点の内容になります。

Argo Rolloutsとは

Kubernetesにおけるデプロイ戦略にブルーグリーンデプロイメントとカナリアリリースを追加します。
今回はこの2つのうち、カナリアリリースを試します。

カナリアリリースを試す

Argo Rolloutsをインストールする

kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml

Argo RolloutsのKubectl Pluginをインストールする

brew install argoproj/tap/kubectl-argo-rollouts

検証用のイメージを準備する

カナリアリリースによって、指定した割合で新バージョンになっているか確認するためのイメージを用意します。
nginxを使って、表示する内容を変更したイメージを用意します。

Dockerfile

FROM nginx
COPY app /usr/share/nginx/html

version:0.0.1

app/index.html

<html><body>1</body></html>

version:0.0.2

app/index.html

<html><body>2</body></html>

カナリアリリースを実施する

Argo Rolloutsをインストールすることで使用可能になったRolloutリソースでコンテナイメージを実行します。
strategycanaryを指定することでカナリアリリースになります。
setWeightで新バージョンをデプロイした時の割合を決めます。ここでは20%にしています。

nginx.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: sample
spec:
  replicas: 5
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
        - name: nginx
          image: hi1280/nginx:0.0.1
          ports:
            - containerPort: 80
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {}

version:0.0.1のnginxイメージをrolloutリソースでデプロイします。

kubectl apply -f nginx.yaml 

最初のデプロイ時点での状態です。
kubectl pluginのgetコマンドで状態を可視化できます。

$ kubectl argo rollouts get rollout sample --watch
Name:            sample
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          2/2
  SetWeight:     100
  ActualWeight:  100
Images:          hi1280/nginx:0.0.1 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5

NAME                                KIND        STATUS     AGE  INFO
⟳ sample                            Rollout     ✔ Healthy  11s
└──# revision:1
   └──⧉ sample-747794b696           ReplicaSet  ✔ Healthy  11s  stable
      ├──□ sample-747794b696-rbczl  Pod         ✔ Running  11s  ready:1/1
      ├──□ sample-747794b696-sgtj7  Pod         ✔ Running  11s  ready:1/1
      ├──□ sample-747794b696-xklcb  Pod         ✔ Running  11s  ready:1/1
      ├──□ sample-747794b696-xvf54  Pod         ✔ Running  11s  ready:1/1
      └──□ sample-747794b696-zxrpn  Pod         ✔ Running  11s  ready:1/1

version:0.0.2のnginxイメージをデプロイします。
set imageコマンドでイメージをデプロイできます。

kubectl argo rollouts set image sample nginx=hi1280/nginx:0.0.2

デプロイした後の状態です。20%の割合でデプロイされていることが分かります。

$ kubectl argo rollouts get rollout sample --watch
Name:            sample
Namespace:       default
Status:          ॥ Paused
Strategy:        Canary
  Step:          1/2
  SetWeight:     20
  ActualWeight:  20
Images:          hi1280/nginx:0.0.1 (stable)
                 hi1280/nginx:0.0.2 (canary)
Replicas:
  Desired:       5
  Current:       5
  Updated:       1
  Ready:         5
  Available:     5

NAME                                KIND        STATUS     AGE   INFO
⟳ sample                            Rollout     ॥ Paused   9m6s
├──# revision:2
│  └──⧉ sample-5669f74b97           ReplicaSet  ✔ Healthy  17s   canary
│     └──□ sample-5669f74b97-rzl8z  Pod         ✔ Running  17s   ready:1/1
└──# revision:1
   └──⧉ sample-747794b696           ReplicaSet  ✔ Healthy  9m6s  stable
      ├──□ sample-747794b696-rbczl  Pod         ✔ Running  9m6s  ready:1/1
      ├──□ sample-747794b696-xklcb  Pod         ✔ Running  9m6s  ready:1/1
      ├──□ sample-747794b696-xvf54  Pod         ✔ Running  9m6s  ready:1/1
      └──□ sample-747794b696-zxrpn  Pod         ✔ Running  9m6s  ready:1/1

promoteコマンドを実行することで、100%の割合でデプロイします。

kubectl argo rollouts promote sample

100%でデプロイした後の状態です。

$ kubectl argo rollouts get rollout rollouts-demo --watch
Name:            sample
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          2/2
  SetWeight:     100
  ActualWeight:  100
Images:          hi1280/nginx:0.0.2 (stable)
Replicas:
  Desired:       5
  Current:       5
  Updated:       5
  Ready:         5
  Available:     5

NAME                                KIND        STATUS        AGE    INFO
⟳ sample                            Rollout     ✔ Healthy     11m
├──# revision:2
│  └──⧉ sample-5669f74b97           ReplicaSet  ✔ Healthy     2m47s  stable
│     ├──□ sample-5669f74b97-rzl8z  Pod         ✔ Running     2m47s  ready:1/1
│     ├──□ sample-5669f74b97-wtvbq  Pod         ✔ Running     37s    ready:1/1
│     ├──□ sample-5669f74b97-zvvjl  Pod         ✔ Running     37s    ready:1/1
│     ├──□ sample-5669f74b97-8l8z9  Pod         ✔ Running     35s    ready:1/1
│     └──□ sample-5669f74b97-jjhkj  Pod         ✔ Running     35s    ready:1/1
└──# revision:1
   └──⧉ sample-747794b696           ReplicaSet  • ScaledDown  11m

少ない割合で新バージョンをデプロイして、その後、新バージョンに変更することができました。

指定した時間だけ新バージョンをデプロイする

カナリアリリースの設定によって、指定した時間だけ新バージョンを試して、自動的に旧バージョンに戻すといったことが可能です。

stepsに記述します。
ここでは、30秒間は20%の割合で新バージョンを試して、その後は0%の割合にすることで旧バージョンに戻しています。

nginx.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: sample
spec:
  replicas: 5
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
        - name: nginx
          image: hi1280/nginx:0.0.1
          ports:
            - containerPort: 80
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause:
          duration: 30
      - setWeight: 0
      - pause: {}

durationの単位は秒数になります。

Rolloutリソースでローリングアップデートを実施する

ローリングアップデートはDeploymentリソースでも実施できますが、リソースが異なるので取り回しが面倒です。
ローリングアップデートも同じリソースでできると便利です。

ローリングアップデートはcanary:{}で実現できます。

nginx.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: sample
spec:
  replicas: 5
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
        - name: nginx
          image: hi1280/nginx:0.0.1
          ports:
            - containerPort: 80
  strategy:
    canary: {}

まとめ

カナリアリリースは既に一般的なデプロイ戦略だと思いますが、Kubernetesではそれができないのが残念なところでした。
Argo Rolloutsを使うとKubernetesで簡単にカナリアリリースを実現することができます。