Running・Ready・業務の成功は別の問い
一言でいうと
RunningはPodのライフサイクルの要約で、Readyは今リクエストを任せてよいかどうかについての条件です。再起動回数と実際のHTTPレスポンスまであわせて見てはじめて、「プロセスが生きている」と「サービスが仕事をしている」を区別できます。
なぜ必要なのか
宅配の倉庫に従業員が出勤したからといって、出荷の準備が終わったわけではありません。従業員は生きて動いていても、送り状プリンターがつながっていないかもしれません。出勤しているかを確認する質問と、新しい注文を割り当てるかを決める質問は別です。サーバーも、プロセスが起動している間に、設定を読み込んだり、接続を復旧したりすることがあります。
運用者が画面のRunningだけを見て、障害がないと判断すると、ユーザーの失敗が説明できません。逆に、レスポンスが1回遅れたからといってプロセスを殺し続けると、まだ正常なインスタンスにリクエストが集中し、そのインスタンスもまた遅くなります。ヘルスシグナルは、緑のランプをたくさん作る機能ではなく、観測結果にどんな行動を結び付けるかを決める約束です。
どう動くのか
Podには、1つの「ヘルススコア」がありません。status.phase、status.conditions、コンテナごとの状態が、それぞれ異なる質問に答えます。kubectl get podsの短い表は要約なので、まず、どの列を見ているのかを確認する必要があります。再起動があったのに現在Runningだからといって、過去の失敗までなくなったわけではありません。
Runningの段階は、Podがノードに割り当てられ、コンテナが作成されたあと、少なくとも1つが実行中、または開始・再起動中の場合も含みます。すべてのコンテナの業務が正常だという意味ではありません。また、表のSTATUSに表示されるCrashLoopBackOffと、APIのstatus.phaseは、同じフィールドではありません。要約の文字列1つをヘルス判定として覚えるよりも、コンテナごとの状態まで展開して読んでください。
| 観測 | 答える質問 | これだけではわからないこと |
|---|---|---|
| phase=Running | Podが実行段階に入ったか | 業務リクエストが成功するか |
| Ready条件 | 現在トラフィックを受ける準備ができたか | すべてのユーザーシナリオが成功するか |
| restartCount | このコンテナが何回再起動されたか | どの障害が再起動の原因だったか |
| 実際のHTTPレスポンス | このパスの今回のリクエストが成功したか | ほかのパス・ほかの時点も成功するか |
readinessの検査はkubeletが実行し、その結果がPodの条件とサービスの転送先に反映されます。一般的なServiceでは、準備ができていないPodを、新しいリクエストの正常な対象としては使いません。このとき、EndpointSliceからアドレスが文字どおりなくなったかどうかだけを見ないでください。アドレスが残ったままconditions.ready=falseになっていることもあります。PodのUIDとアドレス、条件をあわせて照合してはじめて、同じ対象を見ていることになります。publishNotReadyAddresses=trueのServiceは別の動作なので、このラボでは明示的にfalseにしておきます。
PodのAとBが、同じServiceの背後にあるとしましょう。Aのreadinessだけを失敗させると、AはそれでもRunningのままのことがあります。Aに直接送ったリクエストは接続されるものの、業務レスポンスが失敗し、Service経由の新しいリクエストはBが処理する様子を比較できます。ここで重要な証拠は、「Bの応答を一度見た」ことだけではありません。AのReady=false、EndpointSliceのAの条件、Aの既存のコンテナIDと再起動回数の維持まで、あわせて確認する必要があります。
一方、livenessは、コンテナを生かし続けるべきかどうかについての検査です。設定した連続失敗の基準を超えると、kubeletが該当のコンテナを終了させ、再起動ポリシーに従います。同じPodの中でコンテナが再び起動した場合、PodのUIDは同じで、コンテナIDは変わります。DeploymentがPodを入れ替えた場合とは別の出来事です。この区別を見逃すと、「Podがそのままなので、再起動はなかった」という誤った結論を出すことになります。
現場での姿
1つ目の状況は、一時的な依存サービスの障害です。アプリケーション自体は生きていて、接続を再試行できるなら、リクエストの割り当てをしばらく止めることが適切な場合があります。依存サービスが復旧すれば、同じプロセスが再びReadyになります。プロセスを殺すことで、相手サービスの障害を直すことはできません。
2つ目の状況は、アプリケーション内部で処理が進まなくなる状態です。新しいリクエストを受けても処理がまったく前に進まず、プロセスの再起動で復旧できる状態なら、livenessが役に立つことがあります。ただし、このラボの故障マーカーは、実際のデッドロックではなく、復旧動作を比較するための擬似障害です。この結果で、運用アプリのデッドロックを検知したと主張することはありません。実際のアプリの検査パスが何を測るのかは、別途設計する必要があります。
次のレッスンへ
次の教材では、検査そのものが誤って設計されたときに生じる錯覚を見ます。TCP接続の成功とHTTPの業務の成功、遅い初期化と復旧不可能な失敗を区別します。あとのラボでは、Pod・コンテナの身元を記録し、readinessの失敗とlivenessの失敗をそれぞれ作ってから、正常な比較群が影響を受けていないかを確認します。