KubernetesのLiveness Probeは、kubeletがコンテナに定期的なヘルスチェックを送り、決められた回数続けて失敗したらそのコンテナを再起動する仕組みです。プロセスは残っているのにデッドロックで応答しない、という「落ちてはいないが壊れている」状態を回復させるのが役目で、トラフィックの出し入れを決めるReadiness Probe、起動中の保護を担うStartup Probeとは失敗時の動きが違います。この記事では3種の違い、initialDelaySeconds・failureThresholdなどの既定値と再起動までの秒数の計算、4つのチェック方式、kube-apiserver v1.37.0で実測した検証ルール、失敗イベントの読み方までを扱います。
まとめ:Liveness Probe設定の要点と既定値
- 失敗したときの動きで選ぶ。Livenessはコンテナを再起動、ReadinessはServiceの宛先から外すだけ、Startupは成功するまで他の2つを止める。
- 既定値は
initialDelaySeconds=0、periodSeconds=10、timeoutSeconds=1、successThreshold=1、failureThreshold=3。0を書いても「無効」にはならず既定値に置き換わる。 - 既定値のLivenessでは、通常運転中に継続して失敗する場合、失敗検知までの概算は20〜31秒。その後に終了処理があり、Podの終了猶予の既定値は30秒。
- 起動が遅いアプリは
initialDelaySecondsを延ばさず、Startup ProbeでfailureThreshold×periodSecondsの猶予を取る。 - Livenessにデータベースなど外部依存の確認を入れない。依存先の障害で全Podが同時に再起動する。
Liveness Probeとは:kubeletがコンテナを再起動する条件
Liveness Probeはコンテナごとに livenessProbe フィールドで定義し、各ノードのkubeletが実行します。結果が failureThreshold 回続けて失敗すると、kubeletはそのコンテナを停止し、Podの restartPolicy に従って起動し直します。Pod Lifecycleの公式ドキュメントは、Livenessが捕まえる典型として「動いているが処理が進まない」デッドロックを挙げています。
プロセスがクラッシュして終了した場合は、Probeが無くても再起動ポリシーがコンテナを立ち上げ直します。Livenessが必要になるのは、終了せずに応答だけが止まるケースです。
Liveness Probeを設定しない判断が成り立つ条件
Livenessは「付けておけば安全」な設定ではありません。致命的なエラーで自分から終了するよう作られたアプリなら、再起動ポリシーだけで回復でき、Livenessを足しても誤検知で健全なコンテナを落とす経路が増えるだけです。逆に、スレッドの枯渇やデッドロックで固まりうるアプリ(スレッドプール型のJavaサーバーなど)では、Livenessを使って応答停止を検知し、再起動による回復を試みられます。判断の基準は「そのアプリは壊れたときに自分で終了するか」です。言語やロードバランサーを問わないヘルスチェック全般の設計は、ヘルスチェックとは?LivenessとReadinessの分離と閾値設計を実装目線で解説で扱っています。
Liveness・Readiness・Startup Probeの違い
3つのProbeは書き方がほぼ同じで、違うのは失敗したときの動きと実行される期間です。
| Probe | 失敗したとき | 実行される期間 | successThreshold |
|---|---|---|---|
| Liveness | コンテナを再起動 | 起動後ずっと | 1のみ |
| Readiness | Serviceの宛先から外す | 起動後ずっと | 1以上を指定可 |
| Startup | コンテナを再起動 | 成功するまで | 1のみ |
LivenessとReadinessは互いの成功を待ちません。ただし、Startupを設定した場合は、その成功まで両方とも実行されません。公式のProbe設定手順も、Readinessの前に待ちたいなら initialDelaySeconds かStartup Probeを使うよう注意しています。LivenessとReadinessの両方を同じコンテナに付けるのは普通の構成です。
Readiness Probe:Serviceの宛先制御と失敗時の動作
Readinessが失敗すると、そのPodはServiceの宛先(EndpointSlice)で準備未完了の扱いになり、新しいリクエストが届かなくなります。コンテナは再起動されず、successThreshold で指定した回数だけ連続して成功し、Podのほかの準備完了条件も満たすと宛先に戻ります。公式ドキュメントの注記どおりReadinessはコンテナの生存期間中ずっと動くため、起動直後だけでなく、運用中に一時的に受け付けを止めたい場面にも使えます。終了処理中のPodの宛先は通常 ready: false として公開されます。ただし、Serviceで publishNotReadyAddresses: true を指定している場合は例外です。停止時にReadinessを先に落としてから受け付けを止める順序は、グレースフルシャットダウンとは?SIGTERM受信後の停止順序と猶予時間の設計を実装者目線で解説で説明しています。
Startup Probe:成功までのLiveness・Readinessの実行抑止
Startup Probeを設定すると、それが1回成功するまでkubeletはLivenessとReadinessを実行しません。failureThreshold 回失敗するとLivenessと同じくコンテナが停止され、再起動ポリシーに従います。Kubernetes 1.20で正式機能(GA)になりました。
initialDelaySeconds・failureThresholdなど5つのパラメータと既定値
Probeの動きは5つの数値フィールドで決まります。既定値と最小値は、v1.37.0のcore/v1の型定義(types.go)のコメントと、後述の実測で確かめた値です。
Probeパラメータの既定値と最小値
| フィールド | 既定値 | 最小値 | 意味 |
|---|---|---|---|
| initialDelaySeconds | 0 | 0 | 起動から最初のProbeまでの秒数 |
| periodSeconds | 10 | 1 | Probeの間隔(秒) |
| timeoutSeconds | 1 | 1 | 1回の応答を待つ秒数 |
| successThreshold | 1 | 1 | 成功と判定する連続成功回数 |
| failureThreshold | 3 | 1 | 失敗と判定する連続失敗回数 |
| terminationGracePeriodSeconds | Podの値 | 1 | Probe失敗で停止するときの猶予 |
最後の terminationGracePeriodSeconds はProbe単位で停止の猶予を上書きするフィールドで、1.28で正式機能になりました。指定しなければPodの terminationGracePeriodSeconds(既定30秒)が使われます。LivenessとStartupにだけ書けます。
kube-apiserver v1.37.0で実測した検証ルール
Probeの値はPodの作成時にAPIサーバーが検証し、既定値を補います。controller-toolsが配布するenvtest v1.37.0のkube-apiserverを手元で起動し、kubectl create --dry-run=server で次の結果を得ました。検証対象はAPIサーバーによる既定値補完と入力検証であり、kubeletによるProbe実行や再起動時間の実測ではありません。
| 書いた内容 | 結果 |
|---|---|
| httpGetだけを書く | timeout 1・period 10・success 1・failure 3が補われる |
| timeout・period・failureに0 | エラーにならず1・10・3に置き換わる |
| initialDelaySeconds: -1 | must be greater than or equal to 0 |
| Livenessに successThreshold: 2 | Invalid value: 2: must be 1 |
| Readinessに successThreshold: 2 | 受理される |
| Readinessに terminationGracePeriodSeconds | must not be set for readinessProbes |
| httpGetとexecを両方書く | may not specify more than 1 handler type |
| 方式を書かない | must specify a handler type |
落とし穴は2行目です。timeoutSeconds: 0 を「タイムアウトなし」のつもりで書いても、実際は1秒になります。failureThreshold: 0 も3に戻ります。値を緩めたいときは、必ず1以上の具体的な数を書いてください。
initialDelaySecondsの決め方とStartup Probeへの置き換え
initialDelaySeconds は、コンテナの起動からその秒数が過ぎるまでProbeを実行しないための値です。起動に毎回15秒かかると分かっているなら、15〜20秒を入れれば足ります。困るのは起動時間がばらつく場合です。最悪値に合わせて大きく取ると、Livenessで再起動した後も毎回その秒数だけ監視が空き、それでも最悪値を超えて起動が長引いた回には再起動ループが起きます。起動時間が読めないならStartup Probeを足し、initialDelaySeconds は0のままにします。
再起動までの秒数を計算する:periodSeconds×failureThresholdとtimeoutSeconds
Livenessの失敗検知時間の計算条件と目安
以下は、Startupと初期待機が終了し、直前まで正常だったコンテナが継続して失敗する場合の概算です。timeoutSeconds が periodSeconds 以下で、Probeが予定どおり実行されることを前提とします。kubeletの処理遅延などは含まないため、実時間の最長値を保証する式ではありません。
kubeletは periodSeconds ごとにProbeを実行し、失敗が failureThreshold 回続いた時点で再起動を決めます。コンテナが壊れた瞬間が次のProbeの直前なら最短で(failureThreshold−1)×periodSeconds、直後なら最長で failureThreshold×periodSeconds+timeoutSeconds です。
| 設定(period/failure/timeout) | 失敗検知までの概算 | 終了猶予30秒を加えた概算 |
|---|---|---|
| 既定(10/3/1) | 20〜31秒 | 約61秒 |
| 5/3/2 | 10〜17秒 | 約47秒 |
| 10/6/3 | 50〜63秒 | 約93秒 |
「終了猶予30秒を加えた概算」は、失敗検知の概算に終了猶予の既定30秒を足した値です。preStopがある場合、その処理も猶予に含まれ、通常は完了後にSIGTERMが送られます。猶予の延長や処理遅延、再起動のバックオフは含みません。アプリがSIGTERMで即座に終了すれば、この30秒はほぼかかりません。逆に終了処理が遅いアプリで素早く入れ替えたいなら、Liveness側の terminationGracePeriodSeconds だけを短くできます。
Startup Probeの猶予枠は failureThreshold×periodSeconds
Startup Probeでは、failureThreshold×periodSeconds が起動に使える最大の秒数です。公式手順の例は failureThreshold: 30・periodSeconds: 10 で、最大300秒の起動を待ちます。Startupが成功した後はLivenessの短い間隔に切り替わるため、起動の猶予と運用中の検知速度を別々に決められます。
timeoutSeconds:負荷時のp99応答時間を基準にした設定
既定の timeoutSeconds=1は、ピーク時にヘルスチェックの応答が1秒を超えただけで失敗を数えます。負荷試験で測ったヘルスチェック用エンドポイントのp99応答時間に余裕を足した値を下限にしてください。タイムアウトで失敗する場合は、最後の1回の結果が出るまで timeoutSeconds だけ判定が遅れます。上の表の最長側に足しているのがこの分です。
チェック方式4種の書き方:httpGet・exec・tcpSocket・grpc
1つのProbeに書けるチェック方式は1つだけです(2つ書くと前述のとおり弾かれます)。
httpGet:200〜399が成功、別ホストへのリダイレクトは警告
指定パスへGETを送り、ステータスが200以上400未満なら成功です。v1.37.0のkubeletのHTTP Probe実装を読むと、次の動きが分かります。
- リクエストには
User-Agent: kube-probe/1.37(kubeletのメジャー.マイナー)とAccept: */*が付く。httpHeadersで上書きできる。 - 同じホスト内のリダイレクトは最大10回までたどる。別ホストへのリダイレクトはたどらず、成功扱いのまま
ProbeWarningイベントを出す。 - レスポンス本文は10KBまでしか読まない。失敗時のメッセージは
HTTP probe failed with statuscode: 500の形で、本文は載らない。
接続先は既定でPodのIPアドレスです。仮想ホストで振り分けるサーバーに Host ヘッダーを渡したいときは、host フィールドではなく httpHeaders に書きます。ヘルスチェック用のパスは、DB問い合わせのような重い処理を含めない専用のもの(/healthz など)にします。
exec:コマンドの終了コード0が成功
コンテナ内でコマンドを実行し、終了コードが0なら成功です。HTTPを持たないバッチやデーモン向けです。exec方式で timeoutSeconds が守られるようになったのは1.20からで(ExecProbeTimeout)、このゲートは1.35で無効化できなくなりました。
tcpSocket:TCP接続の確認範囲と検知の限界
指定ポートにTCP接続できれば成功です。HTTPを話さないデータベースやメッセージキューに向きますが、接続できてもアプリが処理を返せるとは限りません。Livenessに使うと、ポートは開いたまま固まる障害を見逃します。
grpc:1.27でのGA化と数値ポートの指定制約
gRPC Health Checking Protocolを実装したサーバーなら、grpc 方式で直接確認できます。1.27でGAになり、それ以前のように grpc-health-probe バイナリを同梱する必要はありません。service フィールドでヘルスチェック対象のサービス名を指定できます。port は数値だけで、httpGetやtcpSocketのように port: http と名前で書くと、実測ではPodの読み込みの段階で cannot unmarshal string ... of type int32 エラーになりました。kubeletはPodのIPアドレスに接続するので、サーバーはlocalhostだけでなくPodのIPで待ち受けてください。
v1.37のalpha機能:gRPCのTLSとhttpGetのHTTP/2(h2c)
Kubernetes 1.37で、Probeに2つのフィールドがalphaとして入りました。どちらも既定では無効で、kube-apiserverとkubeletの両方で機能ゲートを有効にする必要があります。
| フィールド | 機能ゲート | 内容 |
|---|---|---|
| grpc.mode: TLS | GRPCContainerProbeTLS | TLSで接続(証明書は検証しない) |
| httpGet.protocol: HTTP2 | H2CContainerProbe | 平文のHTTP/2(h2c)で接続 |
v1.37.0のkube-apiserverで試すと、ゲートが無効のままこれらを書いてもエラーは出ず、フィールドだけが消えてPodが作られました。TLS専用のgRPCサーバーに mode: TLS を書いたつもりで平文のProbeが動き、失敗し続ける、という事故になります。ゲートを有効にすると protocol の既定値 HTTP1 が補われ、protocol: HTTP2 と scheme: HTTPS の組み合わせは is only supported with HTTP (H2C) で弾かれました。マネージドKubernetesではalphaのゲートを有効にできないことが多く、本番で使える段階ではありません。いま使えるKubernetesの版とサポート期限はKubernetesの最新バージョンは1.37|確認方法・EOL一覧とアップグレード手順にまとめています。
Liveness・Readiness・Startupを組み合わせたマニフェスト例
httpGet方式で3つのProbeを併用するDeploymentの例です。agnhostは動作確認用のイメージであり、5分の起動待ちを再現するものではありません。実アプリではイメージと各パスの判定処理を置き換え、起動時間に合わせてStartupの猶予を設定します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: probe-demo
spec:
replicas: 3
selector:
matchLabels:
app: probe-demo
template:
metadata:
labels:
app: probe-demo
spec:
containers:
- name: app
image: registry.k8s.io/e2e-test-images/agnhost:2.40
args: ["netexec", "--http-port=8080"]
ports:
- name: http
containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 10
failureThreshold: 30
livenessProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
terminationGracePeriodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: http
periodSeconds: 5
failureThreshold: 2
Startupの30×10で最大300秒の起動を待ち、その後はLivenessが10秒間隔で見ます。Liveness失敗時の停止猶予だけを10秒に縮め、通常の削除やローリングアップデートではPodの既定30秒を使います。Readinessの /readyz を別パスにしているのは、受け付けを止めたい状態(依存先の一時的な不通など)と再起動したい状態を分けるためです。ReadinessがローリングアップデートでいつPodを入れ替えるかに効く仕組みは、ローリングアップデートとは?仕組みとKubernetes・ECSの設定値・採用判断を解説で説明しています。
サイドカーにProbeを書く条件
通常の初期化コンテナ(initContainers)にはProbeを書けません。実測では may not be set for init containers without restartPolicy=Always で弾かれ、restartPolicy: Always を付けたサイドカーにすると受理されました。サイドカーコンテナは1.33でGAになった機能で、ログ転送やプロキシなどのサイドカーもLiveness・Readinessで監視できます。
Probe失敗の確認と切り分け:kubectl describeのイベント
kubectl describe pod <Pod名> のEventsと、kubectl get pod のRESTARTS列で確認します。kubeletが出すイベントは次のとおりです(v1.37.0のkubeletのソースで確認した書式)。
| Reason | メッセージの例 | 意味 |
|---|---|---|
| Unhealthy | Liveness probe failed: HTTP probe failed with statuscode: 500 | 1回の失敗 |
| Killing | Container app failed liveness probe, will be restarted | 再起動を決めた |
| ProbeWarning | Readiness probe warning: Probe terminated redirects, … | 別ホストへのリダイレクト |
| Unhealthy | Readiness probe failed: … | Readinessの1回の失敗 |
Unhealthyは1回の失敗ごとに出るイベントで、Readinessの失敗でも記録されます。Livenessが再起動まで進んだかは、Killingイベントの有無と RESTARTS 列の増え方で確かめます。タイムアウトで落ちている場合、メッセージにはGoのHTTPクライアントのエラー文(context deadline exceeded など)がそのまま入ります。Killingのメッセージに「will be restarted」が付かないのは、restartPolicy: Never などで再起動しない場合です。再起動が繰り返されているなら、kubectl logs <Pod名> --previous で停止前のコンテナのログを読み、停止直前に応答が遅くなっていないかを確かめます。
Liveness Probeのアンチパターン:再起動が障害を広げる設定
Livenessが見てよいのは「このコンテナ自身が処理を続けられるか」だけです。それ以外を見ると、再起動が障害を広げます。
Livenessの外部依存チェックによる一斉再起動のリスク
Livenessのエンドポイントでデータベースや別サービスへの疎通を確かめると、依存先が数十秒止まっただけで、そこにつながる全Podのプローブが同時に失敗し、一斉に再起動します。依存先の復旧後も、再起動したアプリの初期化や再接続が集中し、回復が遅れるおそれがあります。依存先の状態は、再起動しないReadinessに任せるか、アプリ側のリトライで吸収します。
LivenessとReadinessの判定共通化による不要な再起動
同じパス・同じ閾値をLivenessとReadinessの両方に付けると、Readinessで宛先から外れる前後にLivenessも失敗し、受け付けを止めるだけで済んだはずのPodまで再起動されます。Readinessは一時的な受付不可、Livenessは再起動で回復を試みる異常を判定します。まず判定内容を分け、そのうえでReadinessを先に失敗扱いにするなど、閾値とタイムアウトを調整してください。
高負荷時のtimeoutSeconds超過による再起動の連鎖
ピーク時に応答が timeoutSeconds を超えてLivenessが失敗すると、まだ処理できるコンテナが再起動され、その分の負荷が残りのPodに移ってさらに遅くなります。負荷が高いときほどキャパシティが減っていく形です。対策は、timeoutSeconds と failureThreshold を負荷試験の値から決め、ヘルスチェックのパスから重い処理を外すことです。EKS・GKE・AKS上の本番構成でProbeの値を含めて設計を見直したい場合は、インフラ構築(AWS・Google Cloud・Azure)の支援も行っています。
よくある質問
Liveness ProbeとReadiness Probeの違いは何ですか?
失敗したときの動きが違います。Livenessが失敗するとコンテナが再起動され、Readinessが失敗するとPodがServiceの宛先から外れてリクエストが届かなくなります。Readinessでは再起動されません。
initialDelaySecondsは何秒にすべきですか?
起動時間が毎回ほぼ一定なら、その秒数に少し足した値で構いません(既定は0秒)。起動時間がばらつくなら、initialDelaySeconds は0のままにしてStartup Probeを追加し、failureThreshold×periodSeconds で最悪の起動時間を覆います。
failureThresholdの既定値はいくつですか?
3です。periodSeconds の既定10秒と組み合わせると、通常運転中に継続して失敗する場合、Livenessの失敗検知までの概算は20〜31秒です。0を書くとエラーにならず3に置き換わります。
Startup ProbeとReadiness Probeはどう使い分けますか?
Startupは起動時に1回成功するまでだけ動き、失敗し続けるとコンテナを再起動します。Readinessは起動後ずっと動き、失敗しても再起動せず宛先から外すだけです。起動の遅さに備えるのがStartup、運用中の受け付け可否を表すのがReadinessです。
「Liveness probe failed」と出たら何を見ればよいですか?
kubectl describe pod のEventsでメッセージ(ステータスコードかタイムアウトか)と、Killingイベントが出ているかを確認します。タイムアウトなら timeoutSeconds と負荷時の応答時間、ステータスコードならヘルスチェック用エンドポイントの実装を疑います。停止前のログは kubectl logs --previous で読めます。