三つの事件を復旧し、報告する
一言でいうと
ロールバックのコマンドが成功しても、復旧が終わったわけではありません。戻る先の正常なバージョンを確認し、実際のリクエストをもう一度送る必要があります。
なぜ必要なのか
コンテナのコマンドの小さな変更が、アプリを起動した直後に終了させました。新しいPodは再起動を繰り返し、担当者は直前のバージョンに戻そうとしています。ところが、「以前のバージョン」は本当に正常だったのでしょうか。直前の実験でreadinessが誤ったテンプレートを作っていたとしたら、単に1つ前に戻ることが、別の障害へ戻る道になりかねません。復旧の目標は、記憶や順番ではなく、確認された正常な状態で決める必要があります。
このラボでは、正常なreadinessの復旧を確認したあと、そのDeploymentのリビジョンを記録します。次に、コマンドを、意図的に終了コード17を出す短いシェルに変えます。17は、この教育用シナリオの目印であり、Kubernetesが定めた共通のエラーコードではありません。終了コードが異なる場合や、ImagePullBackOffの場合は、今回意図した障害とは別の原因なので、同じ答えとしては扱いません。
どう動くのか
Deploymentのリビジョンは、Podテンプレートが変わってロールアウトが起きたときに更新されます。Serviceのセレクターの変更は、Deploymentのテンプレートの変更ではありません。レプリカ数だけを変えることも、新しいPodテンプレートを作ることとは異なります。したがって、「kubectlのコマンドを1回実行するたびに、リビジョンが1つ増える」というルールを作って暗記すると、間違います。rollout historyと各リビジョンの内容を取得して、何が変わったのかを確認してください。
정상 템플릿 확인 → 정상 revision 기록
명령 변경 → 프로세스 종료 → 재시작과 backoff
증거 보존 → 원인·복구 목표 선택
정상 revision 지정 rollback
현재 Pod·Ready Endpoint·실제 HTTP 다시 확인
CrashLoopBackOffは、再起動を待っている状態を示す手がかりです。その単語だけでは、OOMなのか、誤ったコマンドなのか、設定ファイルの欠落なのかはわかりません。lastState.terminatedのexitCodeとreason、restartCount、以前のコンテナのログを、一緒に読みます。今回のコマンドは、stderrにintentional-exit-17を残して、17で終了します。以前の実行のログにその目印があり、終了コードも合っていて初めて、今回の実験を正確に再現したことになります。
現在のコンテナのログが空だからといって、アプリが何も出力しなかったと断定しないでください。再起動の直後なら、関心のあるログは、以前の実行にあることがあります。kubectl logs --previousは、この違いを確認するときに使われます。ただし、ログは永続的に保存される監査ストレージではありません。Podの入れ替えやログの保持ポリシーのせいで消えることがあるので、復旧の前に、必要な部分を観測ファイルに残しておくのです。
ロールバックするリビジョンがわかっているなら、--to-revisionで指定できます。正常なPodテンプレートに戻ったとしても、Serviceは別のオブジェクトです。Serviceのターゲットポートが依然として9999なら、PodがReadyに戻っても、Serviceへのリクエストは失敗し続けることがあります。そのため、最後の採点は、レポートファイルやDeploymentの状態だけを検査しません。実際のPod IPとService IPにリクエストを2回送って、決められたレスポンスを確認します。
復旧の成功を確認するリクエストも、何を検証したのかが明確である必要があります。このコースのGET /は、データベースや外部決済を使わない、小さなHTTPレスポンスです。運用での復旧の判定では、代表的な業務パス、エラー率、レイテンシ、依存関係、データの整合性を、一緒に確認する必要がある場合があります。私たちの成功レスポンスは、この小さなサービスの接続経路が回復したという根拠であり、すべての顧客業務の正常化を保証するものではありません。
現場での姿
障害レポートは、コマンドの実行日誌ではありません。どのような影響があったのか、どの層を疑って何で絞り込んだのか、何を変更してどのリクエストで復旧を確認したのかが、つながっている必要があります。「Podを再起動したら解決」という記録は、次の障害のときに同じ行動を繰り返させますが、セレクターの不一致だったという証拠があれば、デプロイ前にセレクターとラベルを比較する予防の検査を作れます。
今回のレポートは、selector・readiness・crashの3つの事件について、cause・prevention・evidenceを結び付けるJSONです。自由な文章の文体を機械が採点することはせず、学習すべき原因の区別と根拠の結び付きを、明示的に検査します。service-selectorにはcompare-selector-labels、readiness-pathにはprobe-real-endpoint、process-commandにはsmoke-test-commandという、予防のコードを使います。指示文にコードの意味が書かれているので、文字列を推測する課題ではありません。
だからといって、レポートのコードが合っていれば、実験を行ったことの強い証明になるわけではありません。学習者は、自分のVMでrootであり、観測JSONを編集できます。保存された観測は、教育用の実験ノートであり、偽造できない証明書ではありません。最後のステップの現在のHTTP検証は、少なくとも、ファイルだけを正常に見せかけて、サービスを修正していない場合を拒否するためのものです。試験の信頼境界を正直に説明することも、運用ドキュメントの品質です。
同じサービスが時間の経過とともに、正常→故障→復旧を行き来するので、すべてのステップが現在の状態だけを見ると、問題が生じます。復旧後に「全体採点」を押すと、「故障状態を作れ」という過去のステップが失敗してしまうのです。このコースは、前の7ステップの観測を、それぞれファイルとして保存し、最後のステップで、その結び付きと現在の復旧を一緒に見ます。観測コマンドは学習者が実行する記録ツールであり、採点ツールは、そのファイルを変更したり障害を注入したりしません。
予防策も、テストで確認する必要があります。ポートが誤ったServiceをわざと入れたのに、正常の判定がそのまま通過するなら、検査は何も守れていません。正常な例が1つ通過するという事実は、「無条件に通過する」検査でも真です。作成者は、正常な正解だけでなく、セレクターだけを直してプローブが間違っている状態、終了コードが異なる状態、ReadyだがServiceのHTTPが失敗する状態を、拒否するかどうかも確認する必要があります。
次のラボですること
8つのステップを通して、正常な基準と、3種類の障害・復旧を観測し、最後に、原因・予防・根拠をまとめます。最後に成功したあと、全体採点をもう一度実行して、過去の証拠が保存されているかを確認してください。ラボは約50分で、一時的なVMです。時間がさらに必要なら、セッションの期限が切れる前に延長し、重要な観測は、セッションが終了する前に別に保管してください。このコースの実験を、本番クラスターにそのままコピーしないでください。