Liveness/Readiness プローブ

Kubernetes がコンテナの生存状態と受信準備状態を判定するためのヘルスチェック機構

Kubernetes可用性

Liveness/Readiness プローブとは

Kubernetes のプローブは、コンテナの状態を定期的にチェックし、異常を検知したら自動的に対処する仕組みである。プローブを正しく設定しないと、デッドロックしたコンテナが放置されたり、起動中のコンテナにトラフィックが流れたりする。

3 種類のプローブ

どのプローブも、ノード上の kubelet が Pod の IP に対して直接実行する。Service やクラスター DNS を経由しないため、Service の設定不備とプローブの失敗は別の問題として切り分ける。

プローブ判定すること失敗時の動作実行される期間
Livenessプロセスが処理を進められているかコンテナを再起動起動後から定期的に
Readinessトラフィックを受けられるかService の EndpointSlice から Pod の IP を除外コンテナのライフサイクル全体
Startup初期化が完了したかコンテナを再起動 (再起動ポリシーに従う)起動時のみ (成功後は再実行されない)

Startup プローブを設定すると、それが成功するまで Liveness と Readiness は実行されない。この「他プローブを止める」働きと失敗時の動作は別物で、Startup プローブが許容回数を超えて失敗すれば、そのコンテナは kill されて再起動ポリシーに従う。

設定例

起動に時間のかかるアプリケーションで 3 種類を併用する例を示す。Startup プローブが許す起動時間は failureThresholdperiodSeconds の積で決まり、この例では 60 秒である。

apiVersion: v1
kind: Pod
metadata:
  name: api-server
spec:
  containers:
    - name: app
      image: myapp:1.0
      ports:
        - containerPort: 3000
      startupProbe:
        httpGet:
          path: /healthz
          port: 3000
        failureThreshold: 30
        periodSeconds: 2          # 最大60秒待つ
      livenessProbe:
        httpGet:
          path: /healthz
          port: 3000
        periodSeconds: 10
        failureThreshold: 3       # 3回連続失敗で再起動
      readinessProbe:
        httpGet:
          path: /ready
          port: 3000
        periodSeconds: 5
        failureThreshold: 3       # 3回連続失敗でトラフィック停止

/healthz と /ready の実装

エンドポイント側は、Liveness を軽く、Readiness を依存先まで見る形に分けて実装する。HTTP プローブは 200 以上 400 未満のステータスコードを成功、それ以外を失敗と判定する。

// /healthz (Liveness): プロセスが生きていれば 200
app.get('/healthz', (req, res) => {
  res.status(200).json({ status: 'alive' });
});

// /ready (Readiness): 全依存先に接続できれば 200
app.get('/ready', async (req, res) => {
  try {
    await db.query('SELECT 1');           // DB 接続確認
    await redis.ping();                    // Redis 接続確認
    res.status(200).json({ status: 'ready' });
  } catch (err) {
    res.status(503).json({ status: 'not ready', error: err.message });
  }
});

Liveness と Readiness の使い分け

この 2 つの取り違えが、プローブ絡みの事故で最も多い原因である。

Liveness: プロセス自体の生存確認

  • デッドロックや無限ループでプロセスが応答を返せなくなった場合に再起動する。メモリを使い切った場合は Liveness の判定を待たずに OOM で kill されるので、Liveness の役割ではない
  • 外部依存 (DB, Redis) のチェックを含めてはいけない
  • 軽量な処理にする (DB クエリなし)
  • Liveness は Readiness の成功を待たない。起動完了までの待ちを表現したいなら initialDelaySeconds か Startup プローブを使う

Readiness: トラフィックを受ける準備ができているか

  • 起動中の初期化処理 (キャッシュのウォームアップ、DB マイグレーション) が完了するまでトラフィックを流さない
  • 外部依存のチェックを含める
  • 一時的な障害 (DB 接続断) で Readiness が失敗しても、コンテナは再起動されない (Service から除外されるだけ)

よくある致命的な失敗

Liveness に外部依存を含める

# ❌ 危険: DB 障害時に全 Pod が再起動するカスケード障害
livenessProbe:
  exec:
    command: ['sh', '-c', 'pg_isready -h postgres-svc']

DB が一時的にダウンすると、全 Pod の Liveness が失敗し、全 Pod が同時に再起動する。再起動した Pod が一斉に DB に接続しようとし、DB がさらに過負荷になる。これがカスケード障害だ。

Liveness は「プロセスが生きているか」だけをチェックする。外部依存のチェックは Readiness に含める。

initialDelaySeconds が短すぎる

アプリの起動に 30 秒かかるのに initialDelaySeconds: 5 を設定すると、起動中に Liveness が失敗し、永遠に再起動ループする。Startup プローブを使えば、起動完了まで Liveness を無効化できる。

既定値がそのまま落とし穴になる

フィールドを省略したときの挙動は、いずれも「厳しめ」に寄っている。

フィールド省略時実務での注意
timeoutSeconds1 秒依存先を確認する Readiness では 1 秒で切れやすい。DB の応答がわずかに遅れただけで全 Pod が同時にトラフィックから外れる
periodSeconds10 秒検知の遅れは failureThreshold との積になる。既定のままなら異常から再起動まで 30 秒前後かかる
failureThreshold31 まで下げると一過性の失敗で再起動する。応答時間のばらつきを見てから決める
successThreshold1Liveness と Startup では 1 以外を指定できない。復帰をゆっくり判定したい場合に引き上げられるのは Readiness だけ
initialDelaySeconds待たずに開始起動待ちを Liveness の遅延で吸収すると、遅延の見積もりを外した瞬間に再起動ループになる

プローブ側にも terminationGracePeriodSeconds を書ける。プローブ失敗で kill するときの猶予だけを Pod 全体の設定より短くしたい場合に使う。

チェックの実行方式

3 種類のプローブは、いずれも次の 4 方式のどれかでチェックを行う。

方式内容選ぶときの注意
httpGet指定パスへ HTTP GET リクエスト (最も一般的)200 以上 400 未満が成功。判定条件をアプリ側のコードで細かく書ける
tcpSocketTCP ポートへの接続確認接続が確立すれば成功なので、受け付けたリクエストを処理できない状態は検知できない
execコンテナ内でコマンドを実行コンテナ内でプロセスを起動するため、短い間隔で回すと他方式より負荷が大きい
grpcgRPC ヘルスチェックプロトコル (Kubernetes 1.27 で正式版)名前付きポートは指定できず、ポート番号を直接書く

理論と実装の両面から学ぶなら関連書籍が参考になる。

この記事は役に立ちましたか?

関連用語

関連する記事