犯人は自分のYAML — 三つの障害ノート
目標
実際のk3sの中で、セレクターの不一致・誤ったreadinessのパス・プロセスの終了を起こし、観測の根拠を保存したうえで、最小限の変更で復旧します。kubectl get/applyとYAMLの基本構造を知っている中級の学習者のための、50分の実験です。
なぜ重要なのか
Runningと、Readyと、ユーザーリクエストの成功は、それぞれ別の事実です。正常なPodがあっても、Serviceのセレクターやポートが間違っていれば、顧客は失敗を経験します。逆に、プロセスは生きていても、準備の条件を満たせず、転送先から除外されることもあります。1回に1つのフィールドだけを変えて前後を比較すれば、再起動を繰り返す代わりに、原因を説明できます。3つの事件を区別したうえで、確認した正常なリビジョンに戻ることが、このラボの範囲です。
安全の範囲
一時VM内のAPI(https://127.0.0.1:6443과)とlabhub-mysteryネームスペースだけを使います。本番クラスターや、ほかの受講生の環境では実行しないでください。提供されるアプリは、単一のレプリカとRecreateを使って、以前の正常なPodが障害を覆い隠さないようにしています。無停止運用の推奨設定という意味ではありません。アプリはイメージのdigestで固定されています。セッションが終了すると、VMと観測ファイルは消えます。必要なら、期限が切れる前に時間を延長し、観測を別に保管してください。観測ファイルは、編集可能な実験ノートであり、偽造できない証拠ではありません。
ステップ
- 提供された/opt/fixtures/k8s-mystery-app.jsonを、kubectl applyで適用してください。labhub-mysteryネームスペースのparcel DeploymentとServiceを取得し、PodとServiceの両方で、ポート8080の/パスが本文labhub-mystery-v1を返す正常な状態を、baselineとして記録してください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe baseline /root/k8s-mystery/01-baseline.json。 - parcel Serviceのselectorだけを、app=missingに変更してください。Podのラベルと、Deploymentは維持します。PodはReadyで直接応答するが、Serviceの選択されたendpointが0で、リクエストは失敗する状態を、selector-brokenとして記録してください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe selector-broken /root/k8s-mystery/02-selector.json。 - Serviceのselectorを、app=parcelに復旧してください。選択されたReadyなendpointが1個で、PodとServiceの両方で正常なHTTPであることを確認し、selector-restoredとして記録してください。Deploymentを削除して作り直さないでください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe selector-restored /root/k8s-mystery/03-selector-fixed.json。 - Deploymentのparcelコンテナの、readinessProbe.httpGet.pathだけを、/missingに変更してください。新しいPodはRunningで、/に直接応答するが、Ready=false、再起動0、現在のPodの404イベント、Readyなendpointが0である状態を、readiness-brokenとして記録してください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe readiness-broken /root/k8s-mystery/04-readiness.json。 - 同じreadinessのパスを、/に復旧してください。プローブを削除したり、常に成功するexecに置き換えたりしないでください。PodとServiceの正常なHTTPと、Readyなendpoint1個を、readiness-restoredとして記録してください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe readiness-restored /root/k8s-mystery/05-readiness-fixed.json。 - 正常なDeploymentのリビジョンを取得して、Deploymentのannotation labhub.io/known-good-revisionに保存してください。そのあと、parcelのcommandを["sh","-ec","echo intentional-exit-17 >&2; exit 17"]に置き換えます。CrashLoopBackOff・直前の終了コード17・再起動1以上・直前のログのintentional-exit-17を確認し、crashとして記録してください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe crash /root/k8s-mystery/06-crash.json。 - rollout historyと、保存したlabhub.io/known-good-revisionを確認し、そのリビジョンにrollout undoしてください。既存のDeploymentを維持したまま、正常なコマンド・プローブ/・Serviceのselector app=parcel・targetPort 8080、および両方のHTTPが復旧した状態を、rollbackとして記録してください。記録コマンド:
python3 /opt/fixtures/k8s_mystery.py observe rollback /root/k8s-mystery/07-rollback.json。 - 前の7つの観測ファイルを維持したまま、/root/k8s-mystery/report.jsonに、selector・readiness・crashの事件ごとに、cause・prevention・evidenceを結び付けてください。原因/予防のコードは下の参考にあり、evidenceは障害発生時のファイル名です。現在のServiceも正常である必要があります。最後に、「全体採点」を押して、過去の観測と現在の復旧を一緒に確認してください。
参考
観測ツールのobserveは、取得とファイルの保存だけを行います。要求された障害を代わりに注入したり、復旧したりしません。45秒以内に条件が見られなければ、値とイベントを確認して、もう一度観測してください。前の7つのステップの採点は、保存した記録を読み取るので、復旧後も過去のステップが取り消されません。最後の採点は、同じDeploymentの記録の結び付きと、現在のPodとServiceのHTTPを、2回確認します。
- セレクターの事件: service-selector / compare-selector-labels(セレクターとPodのラベルの事前照合)。
- プローブの事件: readiness-path / probe-real-endpoint(実際に提供しているヘルスチェックのパスの検査)。
- 終了の事件: process-command / smoke-test-command(コンテナの起動コマンドの小さな実行テスト)。
kubectl -n labhub-mystery get pods,svc,endpointslices -o wideで、対象と状態を分けて見てください。kubectl -n labhub-mystery describe pod <이름>のイベントは、現在のPodのUIDと結び付けてください(プレースホルダーはPod名です)。kubectl -n labhub-mystery logs <이름> --previousは、直前のコンテナのログです(プレースホルダーはPod名です)。- プローブの削除、Deploymentの再作成、数字を暗記したロールバックは、問題の契約を避ける行動です。
宅配便が正常に届く基準線
提供された/opt/fixtures/k8s-mystery-app.jsonを、kubectl applyで適用してください。labhub-mysteryネームスペースのparcel DeploymentとServiceを取得し、PodとServiceの両方で、ポート8080の/パスが本文labhub-mystery-v1を返す正常な状態を、baselineとして記録してください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe baseline /root/k8s-mystery/01-baseline.json。
Runningの表示だけを見ずに、Ready、EndpointSlice、実際のHTTPを区別してください。観測ツールは、望ましい状態を作りません。
配送車は生きているのに、配送先がない
parcel Serviceのselectorだけを、app=missingに変更してください。Podのラベルと、Deploymentは維持します。PodはReadyで直接応答するが、Serviceの選択されたendpointが0で、リクエストは失敗する状態を、selector-brokenとして記録してください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe selector-broken /root/k8s-mystery/02-selector.json。
Serviceのselectorと、Podのlabelsを比較してください。選択条件を変えても、既存のPodのラベルが一緒に変わるわけではありません。
配送リストだけを正す
Serviceのselectorを、app=parcelに復旧してください。選択されたReadyなendpointが1個で、PodとServiceの両方で正常なHTTPであることを確認し、selector-restoredとして記録してください。Deploymentを削除して作り直さないでください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe selector-restored /root/k8s-mystery/03-selector-fixed.json。
アプリを再起動する根拠はありますか。誤って変更したオブジェクトのフィールドだけを元に戻して、実際のリクエストで効果を確認してください。
存在しない健康診断室のせいで、配達が止まる
Deploymentのparcelコンテナの、readinessProbe.httpGet.pathだけを、/missingに変更してください。新しいPodはRunningで、/に直接応答するが、Ready=false、再起動0、現在のPodの404イベント、Readyなendpointが0である状態を、readiness-brokenとして記録してください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe readiness-broken /root/k8s-mystery/04-readiness.json。
livenessではなく、readinessのパスを変えます。イベントの対象UIDが現在のPodと同じかどうかも見てください。
健康診断の契約を、実際のパスに合わせる
同じreadinessのパスを、/に復旧してください。プローブを削除したり、常に成功するexecに置き換えたりしないでください。PodとServiceの正常なHTTPと、Readyなendpoint1個を、readiness-restoredとして記録してください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe readiness-restored /root/k8s-mystery/05-readiness-fixed.json。
実際のリクエストとプローブが、同じ健全性を表現するようにします。このケースはパスのタイプミスであり、実際の依存関係の障害を無視するケースではありません。
宅配ドライバーがメモ17を残して退勤する
正常なDeploymentのリビジョンを取得して、Deploymentのannotation labhub.io/known-good-revisionに保存してください。そのあと、parcelのcommandを["sh","-ec","echo intentional-exit-17 >&2; exit 17"]に置き換えます。CrashLoopBackOff・直前の終了コード17・再起動1以上・直前のログのintentional-exit-17を確認し、crashとして記録してください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe crash /root/k8s-mystery/06-crash.json。
リビジョンを1のような数字で暗記しないでください。正常だと確認した直後に保存し、logs --previousで、直前の終了の根拠を読みます。
記憶ではなく、確認したリビジョンに戻る
rollout historyと、保存したlabhub.io/known-good-revisionを確認し、そのリビジョンにrollout undoしてください。既存のDeploymentを維持したまま、正常なコマンド・プローブ/・Serviceのselector app=parcel・targetPort 8080、および両方のHTTPが復旧した状態を、rollbackとして記録してください。記録コマンド: python3 /opt/fixtures/k8s_mystery.py observe rollback /root/k8s-mystery/07-rollback.json。
Deploymentのロールバックは、Serviceを修正しません。履歴の番号と実際のリクエストを、一緒に確認してください。
緑のランプではなく根拠で、事件を終結させる
前の7つの観測ファイルを維持したまま、/root/k8s-mystery/report.jsonに、selector・readiness・crashの事件ごとに、cause・prevention・evidenceを結び付けてください。原因/予防のコードは下の参考にあり、evidenceは障害発生時のファイル名です。現在のServiceも正常である必要があります。最後に、「全体採点」を押して、過去の観測と現在の復旧を一緒に確認してください。
セレクター・プローブのパス・プロセスのコマンドを、互いに区別してください。現在のサービスが失敗していると、JSONだけを書き換えても通過しません。