デプロイが実際に無停止か測ってみる
このラボは実際にPodが起動して終了するクラスターで行います
VMの中に本物のk3sが起動しています。ローリングアップデートが実際に1台ずつ入れ替わり、失敗したロールアウトは実際に止まり、kubectl drainはPodDisruptionBudgetに実際にブロックされます。
CKADコースの他のロールアウトのラボが動く疑似クラスターではPodが実行されないため、「無停止だったか」を測る方法がありません。
最初の起動には2分ほどかかります。
所要時間は約70分です。セッションの既定は60分なので、期限が切れる前に「+時間」で延長してください(最大180分)。セッションが終わるとVMとファイルは回収されるため、必要な結果は別に保存してください。
目標
デプロイの入れ替えの前・最中・後にリクエストを送り続けてHTTPの失敗を実際に数え、失敗したロールアウトがどのように止まるのか、ロールバックが何を元に戻すのかを確認します。
なぜ重要なのか
「無停止デプロイ」は、戦略の名前を選ぶことではなく、複数の設定が噛み合って初めて成り立つ結果です。1つでも欠けると、静かに壊れます。
readinessProbeがないと、新しいPodは起動した直後からトラフィックを受けます。まだ準備ができていないのに、です。maxUnavailableが大きいと、一度にたくさん落ちて容量が不足します。- 終了の猶予(
terminationGracePeriodSeconds)が短いと、処理中だったリクエストが切れます。
そして、壊れたかどうかは測ってみないとわかりません。デプロイが終わってから確認すると、いつも正常に見えます。
ステップ
すべてのリソースはネームスペース(crol)に作成します。
- Deployment(
web、レプリカ3、nginx、readinessProbe付き)を作成し、maxSurgeとmaxUnavailableを明示してください(保存先:/root/crol/rolling.txt)。 - replicas=3、maxSurge=1、maxUnavailable=0とreadinessProbeを設定したwebで、
python3 /opt/fixtures/ckad_rollout_observer.py captureを使って実際の2回のロールアウトを観測してください。最初のPodにはpreStopがあってはいけません。/root/crol/nodowntime.txtにtotal、failed、total_before_prestop、failed_before_prestopをkey=value形式で書き、scope=single-vm-rollout-sampleとhook_not_retroactive=yesも一緒に書いてください。失敗数は観測のとおりに記録します。 - 存在しないイメージで更新して、ロールアウトが止まることを確認し、その間に古いPodが生きていることも一緒に記録してください(保存先:
/root/crol/stuck.txt)。 rollout undoで元に戻し、結果を記録してください(保存先:/root/crol/undo.txt)。revisionHistoryLimitも明示します。rollout pauseとresumeで一部だけ入れ替わった状態を作り、記録してください(保存先:/root/crol/pause.txt)。- PodDisruptionBudget(
web-pdb)を作成し、今いくつまで中断できるかと、PDBが防げないものを記録してください(保存先:/root/crol/pdb.txt)。 - Deployment(
legacy)をRecreate戦略で作成し、なぜそのような戦略が必要なのかを記録してください(保存先:/root/crol/recreate.txt)。 - レポートファイル(
/root/crol/report.md)に、downtime_requests_failed=、recreate_causes_downtime=、pdb_min_available=の3行と説明を書いてください。
参考
- ステップ2のヘルパーは、同じイメージでテンプレートのアノテーションを変えて、実際のロールアウトを起こします。フックなしのロールアウト → フックのインストール完了 → フックありのPodによる別のロールアウト、という順序です。新しいテンプレートのフックを古いPodに遡って適用したと解釈してはいけません。
rollout-observation.jsonは、実際のリクエストと、入れ替え前後のPod UIDおよびフックの印を保存します。HTTP 500・リダイレクト・誤った本文・送信エラーは失敗として数えます。レポートの値を合わせるために観測ファイルを書き換えないでください。完了したcaptureは再デプロイせず、既存の観測を保存します。- 失敗が2回とも0でも、差がなくても、観測のとおりに書いてください。このサンプルだけでは、フックの効果や、外部ロードバランサー・長い接続まで含めたサービス全体の無停止を証明することはできません。中断された観測は自動では上書きされず、新しいセッションでやり直します。
- ロールアウトの状態は
kubectl -n crol rollout status deploy/webで確認し、止まった理由は.status.conditionsにあります。正解例では、正常な起動には60秒、意図的なイメージ失敗の実験にだけ15秒の期限を使い、復旧後は60秒に戻します。これは本番サービスの推奨値ではなく、短い教育用の実験のための選択です。 - 正解表示とステップの準備は、既存の回答を上書きしません。すでにある回答が間違っている場合は、失敗の理由を見て自分で直してください。2つの機能を同時に実行すると、先に実行中のコマンドを待ってからやり直します。
rollout undoは--to-revisionで特定のリビジョンを選べます。残っているリビジョンはrollout historyで確認します。- PDBの現在の余裕は
.status.disruptionsAllowedです。Podの数が足りないと0になり、drainがブロックされます。 - よくある間違い1:
readinessProbeなしで無停止を期待してしまうことです。新しいPodは起動した直後にエンドポイントへ入り、まだ準備ができていない状態でトラフィックを受けます。 - よくある間違い2: PDBがノード障害も防いでくれると思ってしまうことです。自発的な中断(drain、eviction)だけを防ぎます。ノードが突然死ぬのは防げません。
2つの数字が入れ替えの速度を決める
Deployment(web、レプリカ3、nginx、readinessProbe付き)を作成し、maxSurgeとmaxUnavailableを明示してください(保存先: /root/crol/rolling.txt)。
maxSurgeは目標より何個多く起動できるか、maxUnavailableは何個まで足りなくてもよいか、です。
無停止かどうかを数字で測る
webにreplicas=3、maxSurge=1、maxUnavailable=0、readinessProbeを用意してください。最初のPodにはpreStopがあってはいけません。観測コマンド(python3 /opt/fixtures/ckad_rollout_observer.py capture)で実際の2回のロールアウトを観測したあと、結果ファイル(/root/crol/nodowntime.txt)にtotal、failed、total_before_prestop、failed_before_prestopをkey=value形式で書いてください。scope=single-vm-rollout-sample、hook_not_retroactive=yesも一緒に書き、結果を説明してください。失敗数は0と仮定せず、観測のとおりに記録します。
rollout-observation.jsonのtrialsは、without_hook、with_hookの順です。それぞれのrequestsについて、HTTPステータス200とnginxの本文、errorの有無を一緒に確認します。フックを設置するロールアウトは測定とは別に終わらせ、2回目の測定のbefore Podにフックがあるかを確認してください。
失敗したロールアウトは止まる
存在しないイメージで更新して、ロールアウトが止まることを確認し、その間に古いPodが生きていることも一緒に記録してください(保存先: /root/crol/stuck.txt)。
存在しないイメージで更新すると、新しいPodが起動せず、progressDeadlineSecondsが過ぎると止まります。その間の古いPodを確認してください。
元に戻すと何が戻るのか
rollout undoで元に戻し、結果を記録してください(保存先: /root/crol/undo.txt)。revisionHistoryLimitも明示します。
rollout undoは直前のリビジョンに戻します。残るリビジョンの数はrevisionHistoryLimitで決まります。
一部だけ入れ替えた状態で観察する
rollout pauseとresumeで一部だけ入れ替わった状態を作り、記録してください(保存先: /root/crol/pause.txt)。
rollout pauseのあとにイメージを変えても、何も起きません。複数の変更をまとめて一度に進めたいときに使います。
一度に落ちないようにする
PodDisruptionBudget(web-pdb)を作成し、今いくつまで中断できるかと、PDBが防げないものを記録してください(保存先: /root/crol/pdb.txt)。
PDBは自発的な中断だけを防ぎます。disruptionsAllowedが、今いくつまで許容されるかを教えてくれます。
あえて停止させる戦略
Deployment(legacy)をRecreate戦略で作成し、なぜそのような戦略が必要なのかを記録してください(保存先: /root/crol/recreate.txt)。
Recreateは古いものをすべて落としてから、新しいものを起動します。2つのリビジョンが絶対に共存してはいけないときに使います。
何を学んだのか
レポートファイル(/root/crol/report.md)に、downtime_requests_failed=、recreate_causes_downtime=、pdb_min_available=の3行と説明を書いてください。
downtime_requests_failed=、recreate_causes_downtime=、pdb_min_available=の3行と説明を書いてください。