ローリングアップデート、切り戻し、ブルーグリーン、カナリア
目標
Deploymentのロールアウトのパラメーターを調整し、リビジョンを積み重ねて目的の時点に戻し、ブルーグリーンとカナリアをラベル・セレクター・レプリカだけで構成できるようになります。
なぜ重要なのか
DeploymentがReplicaSetを複数管理するという事実を理解すれば、残りはすべて自然にわかります。イメージを変えると新しいReplicaSetが作られ、古いものはレプリカ0のまま残ります。rollout undoが即座に効く理由は、イメージを再取得するのではなく、すでにあるReplicaSetを再びスケールアップするからです。revisionHistoryLimitを0にすると、その安全網が失われます。
maxSurgeとmaxUnavailableは、「どれだけ速いか」と「どれだけ安全か」のトレードオフです。maxUnavailable: 0はデプロイ中も利用可能なPod数を維持しますが、新しいPodがReadyになるまで待つ必要があるので遅くなります。そして、この安全装置はReadiness Probeがあって初めて意味を持ちます。プローブがないと、コンテナが起動した直後にReadyとみなされます。
ブルーグリーンとカナリアは、別途CRDを使わずにラベルだけで作れます。違いはServiceセレクターの狭さです。セレクターにバージョンのラベルまで入れると片方だけが受け取り(ブルーグリーン)、共通のラベルだけを入れると両方が入ってきて、個数の比率どおりに分かれます(カナリア)。
ステップ
- ネームスペース
ckad-deployを作成し、Deploymentwebを作成してください。イメージはnginx:1.25、レプリカは4です。(コンテナ名はnginxになります。) webの戦略をRollingUpdateにして、maxSurge: 1、maxUnavailable: 0を設定してください。webのイメージをnginx:1.26に更新し、Deploymentにアノテーションkubernetes.io/change-cause=nginx 1.26 으로 업데이트を付けてください(韓国語で「nginx 1.26へ更新」を意味する文です)。webのイメージをnginx:1.27にもう一度更新し、アノテーションをkubernetes.io/change-cause=nginx 1.27 으로 업데이트で更新してください(韓国語で「nginx 1.27へ更新」を意味する文です)。この時点でReplicaSetが3つ以上存在している必要があります。webをリビジョン2に戻してください。戻すことも前に進む変更なので、リビジョン4が新しく作成され、そのリビジョンのイメージはnginx:1.26になっている必要があります。- ブルーグリーンを作成してください。Deployment
checkout-blue(レプリカ2、ラベルapp=checkoutとversion=blue、イメージnginx:1.26)とcheckout-green(レプリカ2、ラベルapp=checkoutとversion=green、イメージnginx:1.27)を作成し、Servicecheckout(ポート80、targetPort 80)のセレクターをapp=checkout+version=greenにしてください。 - カナリアを作成してください。Deployment
pay-stable(レプリカ9、ラベルapp=payとtrack=stable、イメージnginx:1.26)とpay-canary(レプリカ1、ラベルapp=payとtrack=canary、イメージnginx:1.27)を作成し、Servicepay(ポート80、targetPort 80)のセレクターはapp=payだけを指定してください。 webにkubectl rollout pauseを先にかけてから、イメージをnginx:1.28に変更し、revisionHistoryLimitを3に設定してください。一時停止の状態なので、新しいReplicaSetは作成されないはずです。(再開しないでください。レプリカ4はそのままにしてください。)
参考
kubectl patch deployment web -n ckad-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'kubectl annotate deployment web -n ckad-deploy kubernetes.io/change-cause='...' --overwritekubectl rollout history deployment/web -n ckad-deployと--revision=2で、リビジョンごとの内容を確認します。- よくある間違い1:
kubectl set imageにコンテナ名の代わりにDeployment名を書くことです。deployment/web nginx=nginx:1.26のように컨테이너=이미지の形式です(プレースホルダーはコンテナ名とイメージです)。 - よくある間違い2: カナリアでServiceのセレクターに
trackまで入れることです。そうすると片方だけが受け取るので、カナリアではなくブルーグリーンになります。 - ステップ8は、
pauseを先にかけて初めて意味があります。順序が逆だと、ロールアウトがすでに始まっています。
ネームスペースとDeploymentを作成する
ネームスペースckad-deployを作成し、Deployment webを作成してください。イメージはnginx:1.25、レプリカは4です。(コンテナ名はnginxになります。)
kubectl create deploymentに--imageと--replicasを指定します。作成されたDeploymentのラベルとセレクターが何かを確認しておいてください。あとのステップで使います。
ローリングアップデートのパラメーターを調整する
webの戦略をRollingUpdateにして、maxSurge: 1、maxUnavailable: 0を設定してください。
spec.strategy.rollingUpdateの下に2つの値があります。kubectl editで編集するか、kubectl patchにJSONを渡せば設定できます。maxUnavailable: 0は、デプロイ中も元の個数を維持するという意味です。
イメージを更新してchange-causeを記録する
webのイメージをnginx:1.26に更新し、Deploymentにアノテーションkubernetes.io/change-cause=nginx 1.26 으로 업데이트を付けてください(韓国語で「nginx 1.26へ更新」を意味する文です)。
kubectl set image deployment/이름 컨테이너=이미지の形式です(プレースホルダーはDeployment名とコンテナ名、イメージです)。コンテナ名を正確に書く必要があります。CHANGE-CAUSEは、kubernetes.io/change-causeアノテーションで直接付けます。
もう一度更新してリビジョンを積み重ねる
webのイメージをnginx:1.27にもう一度更新し、アノテーションをkubernetes.io/change-cause=nginx 1.27 으로 업데이트で更新してください(韓国語で「nginx 1.27へ更新」を意味する文です)。この時点でReplicaSetが3つ以上存在している必要があります。
リビジョンはReplicaSetとして残ります。kubectl get rs -n <ns>でいくつたまったか、kubectl rollout historyでリビジョン番号がどこまで進んだかを確認します。
特定のリビジョンに戻す
webをリビジョン2に戻してください。戻すことも前に進む変更なので、リビジョン4が新しく作成され、そのリビジョンのイメージはnginx:1.26になっている必要があります。
kubectl rollout undoに--to-revision=번호を指定します(プレースホルダーは番号です)。戻してもリビジョン番号は減らず、新しい番号が付きます。どのリビジョンがどのイメージだったかは、kubectl rollout history --revision=Nで確認します。
ブルーグリーン: Serviceセレクターの切り替え
ブルーグリーンを作成してください。Deployment checkout-blue(レプリカ2、ラベルapp=checkoutとversion=blue、イメージnginx:1.26)とcheckout-green(レプリカ2、ラベルapp=checkoutとversion=green、イメージnginx:1.27)を作成し、Service checkout(ポート80、targetPort 80)のセレクターをapp=checkout + version=greenにしてください。
2つのDeploymentは、共通のラベル1つと、互いに異なるバージョンのラベルを持ちます。Serviceのセレクターにバージョンのラベルまで入れると、そちらだけがエンドポイントに入ります。Serviceを作成したあと、セレクターだけを変えてみるのが、このパターンのすべてです。
カナリア: レプリカの比率でトラフィックを分ける
カナリアを作成してください。Deployment pay-stable(レプリカ9、ラベルapp=payとtrack=stable、イメージnginx:1.26)とpay-canary(レプリカ1、ラベルapp=payとtrack=canary、イメージnginx:1.27)を作成し、Service pay(ポート80、targetPort 80)のセレクターはapp=payだけを指定してください。
カナリアは逆に、Serviceのセレクターを共通のラベルだけに絞って、2つのDeploymentのPodがどちらも入るようにします。すると、トラフィックの比率がレプリカ数の比率になります。各Deploymentには、区別するためのラベルを別に付けます。
一時停止の状態で変更をためる(総合)
webにkubectl rollout pauseを先にかけてから、イメージをnginx:1.28に変更し、revisionHistoryLimitを3に設定してください。一時停止の状態なので、新しいReplicaSetは作成されないはずです。(再開しないでください。レプリカ4はそのままにしてください。)
kubectl rollout pauseを先にかけると、以降のテンプレートの変更はすぐには新しいReplicaSetを作らず、たまっていきます。順序が逆だと、ロールアウトがすでに始まっています。保管する以前のReplicaSetの個数を決めるフィールドも、一緒に設定します。