TT Lab
はじめる
学ぶ 学習パス コース

KCNA — Kubernetes・クラウドネイティブ入門

準備失敗と手動ロールバックが残すもの

TT Labで続きを見る

一言でいうと

進捗失敗の条件は自動復旧のコマンドではなく、Deploymentのロールバックは、外部の設定やデータまで元に戻すトランザクションではありません。

なぜ必要なのか

新しいv3アプリは、プロセスも生きていて、ポートも開きます。しかし、readinessと業務パスが503を返します。新バージョンだけを残して古いPodを先に削除していたら、ユーザーはエラーを受け取っていたでしょう。今回の実験は、正常なv2を2つ維持したまま、準備のできていないv3を1つだけ追加します。「新バージョンを素早く増やすこと」と「現在のユーザーのリクエストを守ること」が衝突する場面です。

サービスがv2を転送し続ければ、運用者は少し息をつけます。しかし、待つだけで必ず直ると仮定してはいけません。プローブが正しく失敗している状況で、probeを削除して緑のランプを作るのも、復旧ではありません。必要なのは、どのバージョンと設定に戻すかを判断し、実際のリクエストがその状態に戻ったかを確認することです。

どう動くのか

このDeploymentは、レプリカ2つ、maxSurge 1、maxUnavailable 0を使います。ローリングアップデート中は、望ましい数より1つ多く追加できますが、アップデートが既存の利用可能なレプリカを勝手に減らす余裕は与えません。新しいPodの準備ができなければ、コントローラーは、正常な古いPod2つを維持し続けられます。したがって、desiredは2なのに、実際のPodは3で、availableは2という状態がありえます。整数の設定を使う実験であり、パーセントの丸めルールまで、ここの数字で一般化しません。

readinessは、リクエストを受ける準備ができているかを判断します。この擬似アプリのlivenessは、ずっと正常なので、v3の準備の失敗だけでコンテナを繰り返し再起動させることはありません。Pod UID・コンテナID・再起動回数と、直接のHTTPレスポンスをあわせて読めば、「実行中だが準備ができていない」ことを確認できます。Serviceは、準備のできたv2にリクエストを転送し、v3は除外するはずです。maxUnavailable 0も、外部の障害、ノードの障害、誤ったプローブまで、すべて防ぐ無停止の保証ではありません。

progressDeadlineSecondsは、デプロイが進行できない状況を判別するためのバジェットです。この実験は、観測時間を短くするために20秒を使いますが、本番の適切な値は、イメージのダウンロード・アプリの起動・最小の準備時間など、実際のバジェットに応じて決める必要があります。期限を超えると、Progressing条件がFalseで、reasonがProgressDeadlineExceededの状態を観測できます。これは、新バージョンが正常に変わったという意味でも、Kubernetesが自動的に古いテンプレートに戻したという意味でもありません。

失敗の条件が現れたあとも、spec.templateがv3なのか、正常なv2のUIDとコンテナはそのままなのか、新しいv3がまだ準備できていないのかを確認します。最後の正常なrevisionを調べて手動で元に戻すのは、そのあとの判断です。ラボでは、すでに観測したv2のrevisionを選び、単に最も小さい番号や最も新しい番号を暗記したりはしません。

kubectl -n kcna-delivery rollout history deployment/web
kubectl -n kcna-delivery describe deployment web
# 조사한 정상 번호를 사용합니다. 아래 N은 그대로 실행하는 값이 아닙니다.
kubectl -n kcna-delivery rollout undo deployment/web --to-revision=N

このコードブロックの韓国語コメントは、調べた正常な番号を使うという意味で、下のNはそのまま実行する値ではないと述べています。

ロールバックは、以前のテンプレートに戻る新しい変更です。履歴番号が過去の数字にそのまま減ると期待しないでください。また、この実験では、残っていた正常なv2のReplicaSetとPodを再利用できます。すべてのロールバックが新しいPodを作らなければならないとか、常に既存のPodを維持するとか、一般化してはいけません。どのReplicaSetが残っていて、何個のレプリカが生きているかによって、実際の遷移が変わります。

現場での姿

コードのロールバックが成功しても、事故が終わらない理由の1つは、外部の状態です。この実験では、v3をデプロイする前にConfigMapをpurpleに変えます。既存のv2プロセスは、環境変数greenを保持していますが、設定オブジェクト自体はpurpleです。Deploymentをv2に戻しても、ConfigMapはpurpleのまま残ります。今のところ応答がgreenだから問題ないと見過ごすと、あとで代替のPodが作られるときに、purpleを受け取ることがあります。そのため、ロールバックのあとは、宣言された設定と実行中の設定もあわせて調べます。

データベースのスキーマ、外部サービスの設定、すでに送信したメッセージは、さらに大きな境界です。Deploymentの履歴は、これらを原子的に巻き戻しません。以前のコードと新しいスキーマが一緒に存在しなければならないローリングアップデートなら、互換性の設計が先に必要です。新しい列の追加、コードの移行、不要な列の削除を、段階的にデプロイするアプローチが必要な理由です。この実験は、データベースマイグレーションの安全性までは証明しません。

GitOpsで管理する本番環境では、望ましい復旧状態もGitの宣言に反映する必要があります。手動の変更だけを行ってGitをそのままにしておくと、Reconcilerが再び適用することがあります。ここの個人用k3sにはArgoCDをインストールしていないので、実際にself-healが元に戻す場面を見たとは主張しません。まず、Deploymentの動作の境界を切り分けて学び、GitOpsのラボで、望ましい状態の原本を加えます。

次のラボですること

正常なv2に変わったあと、準備に失敗するv3を入れ、期限を超過したあとも自動でロールバックされなかったことを記録します。正常なrevisionに手動で復旧したあと、ConfigMapがpurpleのまま残っているかを確認し、greenに別途復元します。ポリシーを削除したり、正常な比較群に手を加えたりせず、実際のレスポンス・オブジェクトの身元・設定という3つの証拠を比較します。

公式の根拠: Deploymentのロールバックと進捗条件・ConfigMapの消費方式