Runningなのに、なぜサービスは失敗するのか
目標
Running・Ready・HTTPレスポンス・再起動を、実際のkubeletの動作で区別し、検査の意味が誤っているときの錯覚を説明します。
なぜ重要なのか
ポートが開いているという事実は、業務の成功を保証しません。しばらくリクエストを受けるべきではないアプリと、再起動すべきアプリを混同すると、自動復旧が障害を大きくします。 正常な比較群を維持しながら、準備の失敗、プロセスの再起動、TCP/HTTP検査の違い、遅い初期化を、それぞれ観察します。 すべての実験は、個人用のk3s VM上の擬似的なアプリに限定します。本番のkubeconfig・実際のシークレット・外部サーバーを持ち込まないでください。 55分のラボで、準備に数分かかることがあります。もっと必要なら、セッションの期限が切れる前に延長してください。終了するとVMとファイルは回収されます。
用意されている環境とヘルパー
ネームスペースkcna-healthのweb-aとweb-bは、healthy Serviceの背後にあります。比較用のlying Serviceは、最初は対象がありません。 2つのServiceはClusterIP:8080で、publishNotReadyAddresses=falseです。アプリのイメージは、digest固定・Always pull、 non-root・cap drop ALL・seccomp RuntimeDefault・読み取り専用ルート・ServiceAccountトークンの非マウントで実行されます。 /stateの1Mi emptyDirだけを、擬似障害のマーカーに使います。workloadのセキュリティや正常な比較群を変えて課題を解決しないでください。
ヘルパーコマンドは、python3 /opt/fixtures/kcna_health_lab.pyのあとに、act・capture・observe・grade・prepareとステップ番号を付けたものです。 actは、入力JSONを検証したうえで、指定された実験上の変更だけを行います。captureは、実際の観測を待って、/root/kcna-healthに保存します。 observeは、現在の観測を出力します。gradeは、リソースや受講生のファイルを変更しません。 受講生が作るのは、change/probeの入力JSONです。観測JSONの成功・UID・状態の値を、自分で作り上げて入れないでください。 /opt/fixtures/kcna-health-context.json・kcna-health-lab-context.json・kcna-health-warming.jsonは、ヘルパーが管理する内部の記録です。
ステップ
- capture 1で/root/kcna-health/baseline.jsonを保存してください。kcna-healthのweb-a・web-bのPod UID、containerID、restartCount、Ready、healthy ServiceとEndpointSliceの条件、実際のHTTP 200を調べます。Podはnon-root・cap drop ALL・読み取り専用ルート・トークンの非マウントで、正常な比較群Bを最後まで保存します。
- /root/kcna-health/not-ready-change.jsonに、pod=web-a、flag=not-ready、present=trueのJSONを作成してください。act 2とcapture 2でnot-ready.jsonを保存します。AはRunningのままReady=false・直接のHTTP 503・EndpointSliceのready=falseになり、コンテナと再起動回数はそのままである必要があります。Serviceへのリクエスト6件が正常なBに転送されるかもあわせて確認します。
- /root/kcna-health/restored-change.jsonに、pod=web-a、flag=not-ready、present=falseを作成してください。act 3とcapture 3でrestored.jsonを保存します。同じPod・コンテナ・再起動回数のまま、Readyと正常なHTTPレスポンスが戻る必要があります。
- /root/kcna-health/restarted-change.jsonに、pod=web-a、flag=unhealthy、present=trueを作成してください。act 4とcapture 4でrestarted.jsonを保存します。同じPod UIDで、コンテナIDとアプリのboot_idが変わり、再起動回数が増える必要があります。このマーカーは、新しいプロセスが起動すると消える擬似障害です。
- /root/kcna-health/tcp-probe.jsonに、tcpSocket.port=8080、periodSeconds=2、timeoutSeconds=1、failureThreshold=2、successThreshold=1を作成してください。act 5は、この設定でliar Podを作成し、準備失敗のマーカーを入れます。capture 5でtcp-lie.jsonを保存してください。TCP Ready=trueと、lying ServiceのHTTP 503が同時に観測される必要があります。
- /root/kcna-health/http-probe.jsonでは、tcpSocketの代わりにhttpGet.path=/readyz、httpGet.port=8080を使用し、残りの4つの数字はステップ5と同じにしてください。act 6は、元のliar UIDを確認して、新しいHTTPプローブのPodに入れ替えます。capture 6でhttp-excluded.jsonを保存します。直接のHTTP 503、Ready=false、EndpointSliceのready=false、Serviceからの正常なHTTPレスポンスがないこと、そして変更されたPod UIDを比較してください。
- /root/kcna-health/startup-probe.jsonに、httpGet.path=/startupz、httpGet.port=8080、periodSeconds=1、timeoutSeconds=1、failureThreshold=45を作成してください。act 7は、20秒初期化のアプリslowを作成し、起動直後のstarted=false・Ready=false・再起動0・/livez 503を記録します。capture 7でwarming.jsonを保存します。captureを遅れて実行しても、実際の初期の観測は保たれます。
- capture 8で/root/kcna-health/started.jsonを保存してください。slowは、ステップ7と同じPod・コンテナで、再起動なしにstarted=true・Ready=true・HTTP 200である必要があります。Aの復旧、HTTPプローブで除外したliar、元のBの身元・コンテナ・正常なレスポンスも保存されている必要があります。
参考
失敗したら、同じVMでobserveとkubectl -n kcna-health get pods -o jsonを読んで、原因を調べてください。 新しい状態を待つ間、actを繰り返し呼び出さないでください。完了した変更と観測は保存し、過去の状態を現在の値として作り直さないでください。 初期化は時間が経てば終わるので、ステップ7の採点は、実際の初期の観測と、現在の同一コンテナ・再起動0をあわせて見ます。 ステップ8では、実際に起動が完了したことまで追加で確認します。通常の採点は60秒、ステップの準備全体は90秒のバジェットを維持します。 準備は、ない前のステップだけを実行します。現在の入力・観測を代わりに作ることはなく、誤って作成した既存の入力も上書きしません。 実験のlivenessのマーカーは、再起動時に消える擬似障害であり、実際のデッドロックの検知器でも、すべての障害の復旧方法でもありません。 liarの独立したPodの入れ替えを、本番のDeploymentの無停止デプロイ手順として、そのまま使用しないでください。 観測ファイルは学習用の資料であり、rootを統制するリモート証明や、不正行為を防ぐ装置ではありません。 公式の根拠: プローブの役割・EndpointSliceの条件・プローブの設定
緑のランプのベースライン調査
capture 1で/root/kcna-health/baseline.jsonを保存してください。kcna-healthのweb-a・web-bのPod UID、containerID、restartCount、Ready、healthy ServiceとEndpointSliceの条件、実際のHTTP 200を調べます。Podはnon-root・cap drop ALL・読み取り専用ルート・トークンの非マウントで、正常な比較群Bを最後まで保存します。
Runningの表記だけを見ず、UID・コンテナID・条件・レスポンスを、それぞれ読んでください。
実行中のアプリをリクエストの割り当てから除外する
/root/kcna-health/not-ready-change.jsonに、pod=web-a、flag=not-ready、present=trueのJSONを作成してください。act 2とcapture 2でnot-ready.jsonを保存します。AはRunningのままReady=false・直接のHTTP 503・EndpointSliceのready=falseになり、コンテナと再起動回数はそのままである必要があります。Serviceへのリクエスト6件が正常なBに転送されるかもあわせて確認します。
準備の失敗は、終了の命令ではありません。EndpointSliceにアドレスが残っていても、ready条件がfalseのことがあります。
再起動なしに準備状態を復旧する
/root/kcna-health/restored-change.jsonに、pod=web-a、flag=not-ready、present=falseを作成してください。act 3とcapture 3でrestored.jsonを保存します。同じPod・コンテナ・再起動回数のまま、Readyと正常なHTTPレスポンスが戻る必要があります。
新しいPodを作る復旧ではありません。readinessのマーカーだけを消して、元のプロセスを維持してください。
同じPod内でのコンテナの再起動
/root/kcna-health/restarted-change.jsonに、pod=web-a、flag=unhealthy、present=trueを作成してください。act 4とcapture 4でrestarted.jsonを保存します。同じPod UIDで、コンテナIDとアプリのboot_idが変わり、再起動回数が増える必要があります。このマーカーは、新しいプロセスが起動すると消える擬似障害です。
Pod名が同じであることよりも、Pod UIDとコンテナIDがどう変わったかを比較してください。
ポートは開いているのにHTTPは503
/root/kcna-health/tcp-probe.jsonに、tcpSocket.port=8080、periodSeconds=2、timeoutSeconds=1、failureThreshold=2、successThreshold=1を作成してください。act 5は、この設定でliar Podを作成し、準備失敗のマーカーを入れます。capture 5でtcp-lie.jsonを保存してください。TCP Ready=trueと、lying ServiceのHTTP 503が同時に観測される必要があります。
接続を受け付けることと、業務のレスポンスは、別の質問です。HTTP 503もTCP接続の上で伝達されます。
業務の準備を検査するHTTPプローブ
/root/kcna-health/http-probe.jsonでは、tcpSocketの代わりにhttpGet.path=/readyz、httpGet.port=8080を使用し、残りの4つの数字はステップ5と同じにしてください。act 6は、元のliar UIDを確認して、新しいHTTPプローブのPodに入れ替えます。capture 6でhttp-excluded.jsonを保存します。直接のHTTP 503、Ready=false、EndpointSliceのready=false、Serviceからの正常なHTTPレスポンスがないこと、そして変更されたPod UIDを比較してください。
プローブを無視したり、準備のできていないアドレスを公開したりしないでください。独立したPodのprobeを入れ替えるには、新しいPodが必要です。
遅い初期化を保護して記録する
/root/kcna-health/startup-probe.jsonに、httpGet.path=/startupz、httpGet.port=8080、periodSeconds=1、timeoutSeconds=1、failureThreshold=45を作成してください。act 7は、20秒初期化のアプリslowを作成し、起動直後のstarted=false・Ready=false・再起動0・/livez 503を記録します。capture 7でwarming.jsonを保存します。captureを遅れて実行しても、実際の初期の観測は保たれます。
startupとlivenessのバジェットを混ぜないでください。観測ヘルパーが初期の状態を保管するので、クリックの速さを競う必要はありません。
再起動なしに起動完了を立証する
capture 8で/root/kcna-health/started.jsonを保存してください。slowは、ステップ7と同じPod・コンテナで、再起動なしにstarted=true・Ready=true・HTTP 200である必要があります。Aの復旧、HTTPプローブで除外したliar、元のBの身元・コンテナ・正常なレスポンスも保存されている必要があります。
現在のReadyだけでなく、初期の観測のコンテナIDと再起動回数を照合してください。