TL

ヘルスチェックの設計(liveness/readiness/startup)

プローブを一つにまとめると、再起動ループや連鎖障害で本番が落ちます。生存・受付可否・起動完了を3種に分け、依存先をどこまで見るかを正しく設計すれば、無駄な再起動と巻き込み事故を防げます。

応用ヘルスチェックKuberneteslivenessreadiness信頼性SRE最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.liveness は『プロセスが直っていないか=再起動すべきか』、readiness は『今トラフィックを受けてよいか=LBに載せるか』、startup は『起動が完了したか=他の2つを始めてよいか』を判定する。役割が違うので混ぜてはいけない。
  • 2.liveness に依存先(DBや下流API)のチェックを入れるのは設計ミス。依存先の一時障害でプロセスが再起動ループに陥り、復旧をかえって遅らせ連鎖障害を増幅する。依存先は readiness 側で、それも慎重に扱う。
  • 3.失敗閾値・周期・タイムアウト・起動猶予の4パラメータが再起動とルーティングの挙動を決める。startup を分けることで、起動の遅いアプリを liveness が誤って殺す事故を防げる。

3種のプローブは「問い」が違う

ヘルスチェック(プローブ)を「アプリが生きているか確かめる仕組み」と一言でまとめると、設計を誤ります。Kubernetes が3種類を持つのは、それぞれが別の問いに答え、別のアクションを引き起こす からです。問いとアクションの対応を取り違えると、健全なPodを殺したり、壊れたPodにトラフィックを流し続けたりします。

プローブ問い失敗時のアクション誰のための情報か
livenessプロセスは生存しているか(デッドロック等で詰まっていないか)コンテナを再起動するkubelet(自Pod)
readiness今この瞬間トラフィックを受けてよいかEndpoints から外す(再起動はしない)Service/LB(振り分け側)
startup起動シーケンスが完了したか(完了まで)liveness と readiness を抑止するkubelet(自Pod)

決定的な違いは 「失敗したら何が起きるか」 です。liveness が失敗するとコンテナは殺されて再起動します。readiness が失敗してもコンテナは生き続け、ただ振り分け先から外れるだけです。この非対称性が、後述する設計判断のすべての根拠になります。「再起動で直る問題か、待てば直る問題か」を取り違えると、対処が逆効果になるのです。

liveness:プロセスが「自力では直らない」状態の検出

liveness プローブが答えるべき問いは、「再起動以外に回復手段がない状態に陥っていないか」 です。典型例はデッドロック、無限ループ、メモリ枯渇でイベントループが進まない、といった プロセス内部の不可逆な詰まり です。これらは外から SIGKILL→再起動するしか直しようがありません。

逆に言えば、再起動で直らないものを liveness に入れてはいけません。最も多い失敗が、liveness のエンドポイントでDB接続や下流APIを叩いてしまうことです。下流が一時的に落ちている間、liveness は失敗し続け、kubelet は健全なアプリプロセスを 延々と再起動します。再起動してもDBは復旧していないので、また失敗する——これが再起動ループ(CrashLoopBackOff)の温床です。

liveness に依存先を入れると連鎖障害を増幅する

DBが瞬間的に詰まったとします。全レプリカの liveness が同時に失敗し、kubelet は全Podを一斉に再起動します。再起動直後は接続プールが空・JITウォームアップ前・キャッシュが冷えた状態で、復旧したDBに殺到して再び過負荷——という メタステーブル障害 を自分で作り出します。依存先の一時障害という「待てば直る」問題に、再起動という「劇薬」を処方した結果です。liveness は自プロセスの内部状態だけを見るのが鉄則です。

実装上、liveness のチェックは軽量・自己完結であるべきです。HTTPなら「リクエストを受けてイベントループが回り、200を返せること」を確認する程度——つまり「ハンドラが応答できる」こと自体がイベントループ生存の証明になります。下流呼び出しもロック取得も含めません。

readiness:受付可否は刻一刻と変わる

readiness が答えるのは、「今、この瞬間、新規リクエストを処理できる状態か」 です。失敗してもPodは殺されず、Service の Endpoints から一時的に外れるだけで、状態が戻れば自動的に復帰します。これは liveness のような不可逆な判定ではなく、可逆なゲート です。

readiness を落とすべき正当なケースは、起動直後でキャッシュ温め中、設定リロード中、ローカルのワーカープールが飽和して新規を捌けない、そしてグレースフルシャットダウンの開始時です。終了時に readiness を落としてルーティングから外す流れは グレースフルシャットダウン の起点になります。

ここで最大の設計判断が 「readiness に依存先を含めるか」 です。これは liveness と違って一概に禁止ではありませんが、含めると連鎖障害のリスクがある ため慎重さが要ります。

readiness に共有依存先を入れると全滅する

全レプリカが同じDBを readiness でチェックしているとします。DBが瞬間的に遅延すると、全Podが同時に readiness 失敗→全員 Endpoints から除外され、Service の振り分け先がゼロになります。結果、DBの一時的な揺らぎがサービス全体の完全停止に増幅されます。本来なら、各Podは「受けられるリクエストだけでも受ける」べきだったのに、共有依存先を全員で見たせいで同時に自滅したのです。共有依存先は readiness から外し、依存先障害は各リクエストの中で サーキットブレーカ やタイムアウトで個別に扱うのが定石です。

判断の指針はこうです。そのPod固有のローカルな受付可否(プール飽和、ウォームアップ)は readiness に入れてよい。一方、全レプリカで共有する外部依存(共通DB、共通キャッシュ)は readiness に入れない。前者は外せば負荷が他Podに逃げて意味があるが、後者は全員同時に外れて逃げ場がなくなるからです。

startup:起動の遅さで liveness に殺されない

startup プローブは比較的新しい仕組みで、答える問いは 「起動シーケンスが完了したか」 です。失敗してもアクションは「待つ」だけ。重要なのは、startup が成功するまで liveness と readiness を一切作動させない 点です。

これが解決するのは典型的な事故です。起動に40秒かかるアプリ(巨大なヒープ確保、マイグレーション、JITウォームアップ等)に対し、liveness を initialDelaySeconds だけで調整しようとすると、安全側に倒して初期遅延を長くすればするほど、本当に詰まったときの検出も遅れるというジレンマに陥ります。短くすれば、まだ起動中のPodを liveness が「死んでいる」と誤判定して殺し、永遠に起動が終わらない再起動ループになります。

startup と liveness は時間軸で役割分担する

startup は「起動中は猶予を長く(例:周期10秒×失敗閾値30回=最大300秒まで待つ)」、liveness は「起動後は周期を短く(例:10秒)して詰まりを素早く検出」という二段構えを可能にします。startup が一度成功すれば、以降は liveness が短い周期で番をする。これにより『起動は気長に待つが、定常時の詰まりは即座に殺す』という、本来両立しにくい二つの要求を同時に満たせます。

4つのパラメータが挙動を決める

各プローブの実際の挙動は、次の4パラメータの組み合わせで決まります。これらを理解せずにデフォルト値で運用すると、誤検知(フラッピング)と検出遅延のどちらかに偏ります。

periodSeconds        … チェック周期(何秒ごとに叩くか)
timeoutSeconds       … 1回のチェックの応答待ち上限
failureThreshold     … 連続何回失敗したらアクション発動か
successThreshold     … 連続何回成功したら復帰とみなすか(readinessで重要)

最悪検出時間 ≈ periodSeconds × failureThreshold + timeoutSeconds

failureThreshold を 1 にすると、たった1回のタイムアウト(GCの瞬間的ストップ・ザ・ワールド等)でPodが殺されます。逆に大きすぎると、本当の詰まりの検出が遅れる。一過性のノイズは閾値で吸収し、持続的な異常だけをアクションに繋げるのが設計の勘所です。timeoutSeconds の既定はしばしば短すぎ(1秒など)、負荷時のGCで簡単に超過するため、定常レイテンシのテール(パーセンタイル)を踏まえて余裕を持たせます。

liveness のタイムアウトは「自分の処理時間」より十分長く

liveness のチェック自体は軽量でも、プロセスが高負荷で詰まっていると応答が遅れます。ここで timeoutSeconds を短くしすぎると、負荷が高いだけで死んでいないPodを殺し、残ったPodへ負荷が集中して次々と殺される——負荷スパイクを再起動の波に変換してしまいます。liveness のタイムアウトと失敗閾値は、定常負荷のテールレイテンシより十分に大きく取るのが安全です。

設計判断のまとめ

3種のプローブを正しく使い分ける核心は、「失敗時のアクションから逆算する」 ことです。

そのチェックが失敗したとき、再起動すべきか?
  → YES(再起動で直る・自プロセス内部の詰まり)  : liveness
  → NO、でもトラフィックは止めたい(待てば直る)  : readiness
  → 起動が終わるまで上2つを待たせたいだけ       : startup
設計レビューの定番論点

(1) liveness に下流依存(DB・外部API)を含めていないか——含めると依存先障害で再起動ループになり連鎖障害を増幅する。(2) readiness に全レプリカ共有の依存先を入れていないか——全員同時に外れてサービス全停止を招く。(3) 起動の遅いアプリで startup を使わず liveness の initialDelay だけで凌いでいないか。(4) timeoutSeconds/failureThreshold がGCやテールレイテンシを吸収できる値か。(5) 「再起動で直る問題か/待てば直る問題か」でプローブを選び分けられているか。

まとめ

  • liveness=再起動すべきか、readiness=受付可否、startup=起動完了か。問いとアクションが異なるので、決して一つのエンドポイントに混ぜない。
  • liveness は自プロセス内部の不可逆な詰まりだけを軽量に見る。依存先を入れると再起動ループでメタステーブル障害を自作する。
  • readiness はローカルな受付可否(プール飽和・ウォームアップ・終了開始)に使う。全レプリカ共有の依存先を入れると全員同時に外れて全停止する。依存先障害はサーキットブレーカ等で個別に扱う。
  • startup を分ければ「起動は気長に、定常時の詰まりは即座に殺す」を両立できる。
  • periodSeconds/timeoutSeconds/failureThreshold は一過性ノイズを吸収しつつ持続的異常を検出する観点で、テールレイテンシを踏まえて調整する。

DevOps/インフラ Article

ヘルスチェックの設計(liveness/readiness/startup)を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

ヘルスチェック

比較で見る軸

難易度: advanced / カテゴリ: DevOps/インフラ / タグ数: 6

導入後に効く点

liveness に依存先(DBや下流API)のチェックを入れるのは設計ミス。依存先の一時障害でプロセスが再起動ループに陥り、復旧をかえって遅らせ連鎖障害を増幅する。依存先は readiness 側で、それも慎重に扱う。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
DevOps/インフラ
タグ数
6

判断チェックリスト

  • 自社の用途が「ヘルスチェック / Kubernetes」に近いか確認する。
  • 強みである「liveness は『プロセスが直っていないか=再起動すべきか』、readiness は『今トラフィックを受けてよいか=LBに載せるか』、startup は『起動が完了したか=他の2つを始めてよいか』を判定する。役割が違うので混ぜてはいけない。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

ヘルスチェックKuberneteslivenessreadiness信頼性ヘルスチェックKubernetesliveness