要約すると
Kubernetes上で動作するAPIのカナリアリリースをしたかったので、Argo Rolloutsを導入してこれを実現しました。この記事ではその際の導入手順を紹介します。
概要
背景
Argo CDを利用しているので、Argo Projectのツールでカナリアリリースを実現したかった。
対象者
- CD (Continuous Delivery) を構築・運用する人
ゴール
Argo Rolloutsでカナリアリリースができるようになること
前提
公式ドキュメント
本記事の情報は時間が経つと古くなります。最新の情報は公式ドキュメントを参照してください。
Rolloutリソースについて
Argo Rolloutsでは Deployment
リソースの代替として Rollout
というリソースを使います。RolloutにはDeploymentとほとんど同じ内容を書くことができ、基本的な使い方は同じです。
異なる点として、spec.strategy
にデプロイ戦略を書くことで様々な方法でデプロイすることができるようになります。カナリアリリースもここに定義できる戦略のひとつです。
以下、導入手順です。
Argo Rolloutsをクラスターにインストール
専用のnamespace argo-rollouts
を作成し、そこにマニフェストをapplyします。
$ kubectl create namespace argo-rollouts $ kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
以上でインストールできました。簡単でした。
CLIツールをローカルPCにインストール
Argo Rolloutsの操作に使うCLIツールをインストールします。kubectlのプラグインという形で提供されています。
brewを使っている場合は以下
$ brew update $ brew install argoproj/tap/kubectl-argo-rollouts
バイナリをダウンロードする場合は以下
# Linuxの場合は "darwin" を "linux" に読み替える $ curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-darwin-amd64 $ chmod +x kubectl-argo-rollouts-darwin-amd64 # その後、名前を変更 & PATHを通す # 例 $ sudo mv ./kubectl-argo-rollouts-darwin-amd64 /usr/local/bin/kubectl-argo-rollouts
以下のコマンドで動作確認します。
$ kubectl argo rollouts version kubectl-argo-rollouts: v1.3.2+f780534 BuildDate: 2022-12-15T16:06:35Z GitCommit: f780534ebd66a4047c813ddd7841be93b122c3e6 GitTreeState: clean GoVersion: go1.18.9 Compiler: gc Platform: darwin/amd64
デモアプリをインストールしてみる
ターミナル1
テスト用にデモアプリが提供されているので動かしてみます。RolloutとServiceの定義をapplyします。
$ kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/rollout.yaml $ kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/service.yaml
完了したら rollouts-demo
というRolloutリソースが作成されます。
以下のコマンドでRolloutの状態を監視します。
$ kubectl argo rollouts get rollout rollouts-demo --watch
デモ用Rolloutのイメージタグを差し替えてカナリアリリースの動作確認をする
新しいターミナルを立ち上げてください。以下のコマンドでカナリアリリースが行われます。
ターミナル2
# イメージを更新する $ kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:yellow # このタイミングで全体の20%が新しいPodに入れ替わる # カナリアリリースを進める $ kubectl argo rollouts promote rollouts-demo # 全てのPodが新しいイメージのものに入れ替わる
このような挙動になるのは、Rolloutに以下のような定義があるからです。 Rolloutの中から、カナリアのステップを書いた部分を抜粋
spec: replicas: 5 strategy: canary: steps: - setWeight: 20 - pause: {} - setWeight: 40 - pause: {duration: 10} - setWeight: 60 - pause: {duration: 10} - setWeight: 80 - pause: {duration: 10}
意味
- 全体の20%を新しいpodに更新
- 無制限に待つ
- promoteコマンドを受け付けたら進む
- 全体の40%を新しいpodに更新
- 10秒待つ
- 全体の60%を新しいpodに更新
- 10秒待つ
- 全体の80%を新しいpodに更新
- 10秒待つ
- 全て新しいpodに更新
途中でロールバックしたいときは、promoteの代わりにabortします。
# 新しいイメージに更新 $ kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:red # このタイミングで全体の20%が新しいpodに更新される # puase中にabortする $ kubectl argo rollouts abort rollouts-demo # 先ほどまで動いていたargoproj/rollouts-demo:yellowに戻る
ここで、Rolloutを監視しているターミナル1を見てください。
abortすると、RolloutのSTATUSが Degraded
になります。これはあるべき状態と現在の状態が異なるからです。
上記の例では、先ほどイメージをrollouts-demo:redに更新するコマンドを実行したのにも関わらず、abortの結果現状がrollouts-demo:yellowに戻っているためです。
Healthy
に戻すためには、再度yellowを適用します。
$ kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:yellow
デモは以上です。 このように、カナリアリリースを行うことができます。
UIで操作したい
以下のコマンドを叩くと、localhost:3100 でUIを見ることができます。
$ kubectl argo rollouts dashboard
カナリアリリース実行中は以下のような画面になります。
Rolloutリソースを定義する
次に、自身の環境でRolloutを作成していきましょう。 2つの方法があります。
- Rolloutだけを定義する
- Deploymentを定義してから、それを参照する形でRolloutを定義しする
Migrating - Argo Rollouts - Kubernetes Progressive Delivery Controller
今回は、既存のDeploymentを参照する形式でRolloutを定義する方法を紹介します。
理由は、すでに定義済みのDeploymentが存在する状況の場合が多そうであることや、Rolloutをやめたいときに戻りやすそうであるためです。
まず、以下のようにDeploymentを spec.replicas: 0
で定義します。そして、Rolloutに spec.workloadRef
を記載することで、Deploymentを参照することができます。
# 既存のDeployment # 名前は my-api apiVersion: apps/v1 kind: Deployment metadata: name: my-api namespace: apps spec: selector: matchLabels: app: my-api replicas: 0 # Deployment側のレプリカ数を0にすることで、Rollout管理のPodのみを動作させることができる template: # 略 --- # 新しく定義するRollout # Argo Rolloutsによってカナリアリリース等を実現するための、Deploymentを代替するリソース apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: my-api namespace: apps spec: replicas: 3 selector: matchLabels: app: my-api workloadRef: # 既存のDeploymentを参照する apiVersion: apps/v1 kind: Deployment name: my-api strategy: canary: steps: - setWeight: 10 - pause: {} - setWeight: 50 - pause: {duration: 30s}
DeploymentからRolloutに移行するときの注意点
先述した以下のドキュメントにも書いてありますが、
Migrating - Argo Rollouts - Kubernetes Progressive Delivery Controller
いきなりDeploymentの spec.replicas
を0にした定義をapplyすると、Rolloutで定義したPodが全て立ち上がる前に、既存のDeployment管理下のPodが全て削除されてしまい、ダウンタイムが発生します。そのため、はじめはDeployment側のreplicasを減らさずにリリースして、Rollout管理下のpodが全て稼働するようになってからDeploymentを縮退させる修正を反映させるとダウンタイムを抑えられます。
リリース工程
フェーズ1
- Rolloutを作る
- pod数は現行のDeploymentと同じ
- この時点でDeployment管理下とRollout管理下のPodが共存する状態になる
ただし、この手順をそのまま採用すると一時的にPod数が2倍になるため、cpu、memory、storage等のリソースを考慮してオペレーションの手順を調整する必要があります。弊チームでRolloutを導入した際は、負荷が少ない時間帯を選び、Pod数が半分になることまでは許容することにしました。
フェーズ2
- Deploymentのreplicasを0にする
サポートバージョン
最後に、サポートされているバージョンについて。
Installation - Argo Rollouts - Kubernetes Progressive Delivery Controller
公式ページには以下の記載があります。
- Argo Rolloutsは最新版しかサポートされていない
- 対応するKubernetesのバージョンは最新とそのひとつ前だけ
クラウドサービスプロバイダーによっては新しいKubernetesバージョンをサポートしていない場合もあり、この条件に対応するk8sクラスターを用意できない場合があると思います。
もし古いバージョンのk8s上で最新のArgo Rolloutsが動作しない場合、自己責任にはなりますが、Argo Rollouts本体、kubectl-argo-rollouts (CLI) のいずれかもしくは両方を古いバージョンにすることで動作することがあります。
# 最新をインストールするときのコマンド $ kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml # バージョンを指定してインストールするときのコマンド # kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/download/v1.3.2/install.yaml