なになれ

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

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

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

argoproj.github.io

以下に試した内容を示します。

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

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

カナリアリリースによって、指定した割合で新バージョンになっているか確認するためのイメージを用意します。
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 

最初のデプロイ時点でのreplicasetの状態です。

$ kubectl get replicaset -o wide
NAME                DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES               SELECTOR
sample-7bf8db5b89   5         5         5       7m51s   nginx        hi1280/nginx:0.0.1   app=sample,rollouts-pod-template-hash=7bf8db5b89

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

kubectl patch rollout sample -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"hi1280/nginx:0.0.2"}]}}}}' --type merge

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

$ kubectl get replicaset -o wide
NAME                DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES               SELECTOR
sample-5f8c88ddd4   1         1         1       8s      nginx        hi1280/nginx:0.0.2   app=sample,rollouts-pod-template-hash=5f8c88ddd4
sample-7bf8db5b89   4         4         4       9m47s   nginx        hi1280/nginx:0.0.1   app=sample,rollouts-pod-template-hash=7bf8db5b89

pausedfalseに更新することで、100%の割合でデプロイします。

kubectl patch rollout sample -p '{"spec": {"paused": false}}' --type merge

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

$ kubectl get replicaset -o wide
NAME                DESIRED   CURRENT   READY   AGE    CONTAINERS   IMAGES               SELECTOR
sample-5f8c88ddd4   5         5         5       7m7s   nginx        hi1280/nginx:0.0.2   app=sample,rollouts-pod-template-hash=5f8c88ddd4
sample-7bf8db5b89   0         0         0       16m    nginx        hi1280/nginx:0.0.1   app=sample,rollouts-pod-template-hash=7bf8db5b89

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

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

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

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.2
          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.2
          ports:
            - containerPort: 80
  strategy:
    canary: {}

まとめ

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