
2026/08/20 1:25
Kubernetes プロブの動作原理
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
本稿の核心的なメッセージは、Kubernetes が起動中のアプリケーション故障を防ぐために健康チェックプローブに依存しているという点にあります。これらの設定が欠落すると、コンテナが即座に「準備完了」と見なされ、トラフィックが拒否されてしまいます。具体的には、
startupProbe はリクエストを受け入れる前にアプリケーションがリッスンしているかを確認し、これを設定せずに incoming データが機能しないサービスに直ちに到達してしまいます。readinessProbes はロードバランシングを管理し、livenessProbes はクラッシュを処理しますが、これらが誤設定されるとシステム不安定化や、ロールアウト中に「サンダー・ハーッド」というカスケードを引き起こします。「webernetes」(大規模な TypeScript ベースの Kubernetes ポート)を用いた広範なテストに基づき、専門家は明確に区別された起動時と準備完了時の構成をペアリングすることを推奨しています。このアプローチは、初期化時のスパイクを処理しつつステイディステート負荷を増加させることなく、データベース接続の洪水のような共有依存関係の問題を防ぎます。したがって、開発者は最悪ケースの初期化時間に合わせるように終了グレースペリオドを調整する必要があります。結局のところ、業界は保守的で安価な読み込みエンドポイントを採用すべきです。RollingUpdate デプロイメント中にプローブ間隔を厳格に制御することで、企業はアプリケーションを更新しながら可用性を維持でき、トラフィックが古いインスタンスから新しいインスタンスへシフトする前に新しいポッドが完全に機能していることを確保できます。本文
Kubernetes におけるプローブ(Probe)の仕組みとベストプラクティス
本稿では、Kubernetes における**プローブ(Probe)の仕組みを詳しく解説します。プローブがどのようにアプリケーションの回復力(レジリエンス)**を高め、かつ避けるべきミスを未然に防ぐのかを実例とともに紹介します。
具体的には、「数時間かかるリカバリからの再起動ループ」や「ロールアウト中のリクエスト損失」といった問題の原因と対策を明らかにします。
注記: 本稿のインタラクティブデモでは、Kubernetes の一部機能を TypeScript でシミュレーションするツール **「webernetes」**を使用しています。ブラウザ上で動作させつつ、実際のクラスター(k3s)での挙動も検証しており、バグ発見にも寄与しました。
学習目標
- プロブなしの Pod の挙動
- スタートアッププロブ(Startup Probe)
- リアディネスプロブ(Readiness Probe)
- ライブネスプロブ(Liveness Probe)
- Deployments とプロブの関係
1. プローブのない Pod:なぜ問題が起きるのか
単一コンテナを含む Pod を起動したとします。以下にそのマニフェストを示します。
# pod-a.yaml apiVersion: "v1" kind: "Pod" metadata: name: "pod-a" spec: containers: - name: "app" image: "my-app:latest"
の特徴:my-app:latest
- ポート 8080 を監視する前に、数秒間初期化を行います。
問題の発生メカニズム
コンテナを「再起動」ボタンでクラッシュさせた場合、以下の現象が起きます。
- 初回クラッシュ後: コンテナは即座に再起動します。
- 2 回目以降: Kubernetes は
を適用し、起動を遅らせてから再開します(デフォルトでは 10 秒開始、最大 5 分まで)。CrashLoopBackOff
致命的な問題点
Kubernetes はコンテナが起動するやいなやそれを**「Ready(準備完了)」**と見なしてしまいます。 しかし実際には、初期化作業仍在行中であり、ポート 8080 を監視していない状態です。
これにより、外部からのトラフィック(リクエスト)が到達した際、以下のような失敗が起きます。
- 進行中のリクエストが失敗: コンテナは再起動直後でも Ready と判断され、Service からトラフィックを受け付けます。
- 結果: クライアントはタイムアウトまたはエラーを返すことになります。
Kubernetes はコンテナの「準備状況」を知りたいため、**プローブ(Probe)**という機能を提供します。
3 つのプローブタイプ
- スタートアッププロブ: アプリケーションが起動し終わったかを確認。
- リアディネスプロブ: アプリケーションがトラフィックを受け付けられる状態になったかを確認。
- ライブネスプロブ: アプリケーションが停滞していないか(再起動が必要か)を確認。
本稿ではまず、スタートアッププロブから解説を進めます。
2. スタートアッププロブ(Startup Probe)
以下の
pod-a.yaml にスタートアッププロブを追加しました。
apiVersion: "v1" kind: "Pod" metadata: name: "pod-a" spec: containers: - name: "app" image: "my-app:latest" startupProbe: httpGet: path: "/startup" port: 8080 periodSeconds: 1 failureThreshold: 5
仕組みの解説:
- タイプ:
で、ポート 8080 のhttpGet
エンドポイントを 1 秒おきにチェックします。/startup - 成功条件: ステータスコード 200〜399 を返した場合。
- 失敗判定: 連続して
(5 回) 失敗すると、Kubernetes はコンテナを停止(キル)します。failureThreshold - 効果: 私の例では、約 5 秒のスタートアップ時間を確保できました。
Pod の状態変化
デモで
pod-a を再起動すると:
- プロブが開始され、NotReady ステータスになります(初期化中)。
エンドポイントが正常に返したら初めて Ready となります。/startup
補足: 厳密には Kubernetes に「NotReady」という条件はなく、
という状態ですが、ここでは簡略化して表現しています。ready=True/False
リプリケーションとサービスとの連携
単一 Pod では不十分なため、複数のリプリカ(2 つ)を作成し、Service で負荷分散するように構成します。
# replica-set-a.yaml (要約) apiVersion: "apps/v1" kind: "ReplicaSet" spec: replicas: 2 selector: matchLabels: app: "pod-a" template: spec: containers: - name: "app" image: "my-app:latest" startupProbe: httpGet: path: "/startup" port: 8080 periodSeconds: 1 failureThreshold: 5 # service-a.yaml (要約) apiVersion: "v1" kind: "Service" spec: selector: app: "pod-a" ports: - port: 80 targetPort: 8080
Kubernetes は、
ステータスが Ready
の Pod に対してのみトラフィックを転送します。
これにより、起動中のコンテナへのリクエスト流入を防ぐことができます。True
Grace Period(終了優待期間)の活用
Pod を削除(Delete)する際にも同様の効果が得られます。
- Grace Period: デフォルトでは 30 秒ですが、本稿では 2 秒に設定しています。
- 挙動: Pod は
状態となり、Service から除外されます。Terminating - 利点: 新規リクエストが到達せず、新しい Pod がすぐに作成されるため、ユーザー体験への影響を最小限に抑えられます。
重要:
startupProbe と gracePeriod の組み合わせにより、起動中・停止中のコンテナへの不要なトラフィック流入を防止できます。
スタートアッププロブの誤設定例
failureThreshold を小さく設定すると、コンテナがクラッシュループに陥ります。
- 設定例:
など(初期化時間が足りない場合)。failureThreshold: 1, 2 - 結果: コンテナは数回の再起動後、
状態になり安定しません。CrashLoopBackOff - 対策: 最悪のケースでの起動時間を考慮し、適切な値を設定してください。
3. リアディネスプロブ(Readiness Probe)
スタートアッププロブが成功した後、リアディネスプロブはコンテナの残りのライフサイクルを通じて監視を続けます。失敗すると、Service からトラフィックを受け付ける資格を失います(NotReady)。
マニフェスト例
apiVersion: "v1" kind: "Pod" metadata: name: "pod-a" spec: containers: - name: "app" image: "my-app:latest" readinessProbe: httpGet: path: "/ready" port: 8080 periodSeconds: 3 failureThreshold: 2 successThreshold: 1
設定のポイント
- 頻繁なチェックは避け: 一時的な失敗で Pod を除外しないよう、
は適切に設定してください(例:デフォルトの 3 など)。failureThreshold - 依存関係の扱い: データベースやサードパーティ API の一時的な障害を理由にリアディネスを失敗させるのは避けてください。共有リソースが原因で Pod を除外すると、カスケード故障を引き起こす可能性があります。
なぜ両方のプローブが必要なのか?
スタートアッププロブとリアディネスプロブは役割が異なります。
- 開始タイミング: スタートアッププロブがあることで、初期化完了までの間、リアディネス/ライブネスプロブの送信を遅延させられます。
- 独立性: スタートアップには独自の
とperiodSeconds
を設定でき、初期化検出に頻繁なチェックを当てられます。一方、安定状態ではリソースを節約するためにリアディネスは間引きます。failureThreshold - コンテナの停止判定: スタートアップの失敗はコンテナを停止(キル)しますが、リアディネスの失敗はそうしません(再起動ではなくトラフィック遮断のみ)。
マニフェスト例:両方を併用
apiVersion: "v1" kind: "Pod" spec: containers: - name: "app" startupProbe: httpGet: path: "/startup" port: 8080 periodSeconds: 1 failureThreshold: 5 readinessProbe: httpGet: path: "/ready" port: 8080 periodSeconds: 5
4. ライブネスプロブ(Liveness Probe)
ライブネスプロブは、リアディネスとは異なり、失敗カウントが閾値を超えた際に**コンテナをキル(再起動)**します。これにより、メインスレッドのデッドロックやバグによる停滞からの自動回復を図ります。
マニフェスト例
apiVersion: "v1" kind: "Pod" metadata: name: "pod-a" spec: containers: - name: "app" image: "my-app:latest" # ... (他は省略) livenessProbe: httpGet: path: "/live" port: 8080 periodSeconds: 2 failureThreshold: 1
注意点:不適切な使用例
共有リソースの状態に基づいてライブネスを失敗させるのはNG です。
- データベースの停止など: データベースが一時的に障害(blip)を起こしても、すべてのコンテナがクラッシュループに陥り、システム全体がダウンします。
- 再試行(Retry)の問題: クライアント側で失敗したリクエストを自動再試行する場合(Thundering Herd)、復旧途中のコンテナに対して大量のリクエストが殺到し、再びクラッシュさせる可能性があります。
適切なライブネスプローブの設計
- 単一コンテナの状態のみを監視する: システム全体の健康状態ではなく、その Pod のプロセスが正しく動作しているかを確認してください。
- 共有リソースを基準にしない: DB や API の可用性は、Pod を再起動させる理由にしてはいけません。
- 過剰な負荷への対応: CPU/Memory 使用率が高いことだけを理由に起動を停止するのは避け、サービス全体のクラッシュを招かないよう設計してください。
代替案:
- トラフィックの一部のみを通過させ、回復する時間を確保する。
- クライアント側に再試行のバックオフ遅延を追加する。
5. プローブと Deployments:ロールアウトの影響
Kubernetes の Pod 規格(Spec)は不変(Immutable)であり、更新には新しい Pod の作成が必要です。Deployment はこのプロセスを管理します。
ロールアウト戦略
以下の設定では、段階的な更新(RollingUpdate)を行います。
apiVersion: "apps/v1" kind: "Deployment" spec: replicas: 3 strategy: type: "RollingUpdate" rollingUpdate: maxUnavailable: "25%" # 利用できない Pod の上限(floor(3*0.25)=0) maxSurge: "25%" # 追加で作成する Pod の上限(ceil(3*0.25)=1)
- 動作: 古い Pod をスケールダウンし、新しい Pod をスケールアップします。
- 影響: 新しい Pod はスタートアッププロブを通過するまで Ready になりません。そのため、ロールアウトはプローブの周期数分ほど遅延します。
プロブなしでのロールアウトのリスク
スタートアッププロブがない場合、コンテナが起動した直後に
Ready とみなされ、初期化完了前のトラフィックを受け付けてしまいます。これによりリクエスト失敗が発生します。
6. 良いプローブエンドポイントの設計に関するヒント
スタートアップ(Startup)
- 目的: 初期化中の検出。
- 設定: 頻繁にチェックし (
を小さく)、最悪のケースでも失敗しないようperiodSeconds
を大きくしてください。failureThreshold - エンドポイント:
など、初期化完了専用エンドポイントを推奨します。なければ健康チェック用で OK です。/startup
リアディネス(Readiness)
- 目的: トラフィック受信可否の確認。
- 設定: 失敗すると Service から除外されますが、共有リソース障害を理由にはしません。
- 保守性: チェックコストは低く保ち、Pod を除外することがシステム全体にメリットになる場合にのみ失敗させてください。
ライブネス(Liveness)
- 目的: 停滞しているコンテナの再起動。
- 設定: 「確実に戻ってこない」と判断できる場合のみ失敗させます。少し不安な場合は成功を返してください。
- 禁忌: データベース接続など共有リソースの状態はチェック対象にしません。
一般的なアドバイス
- コスト: プローブはクラスタリソースを消費します。必要以上に複雑にはしないよう、有界かつ安価に保ってください。
- デフォルト値:
のデフォルトは 3 です。即座の介入が必要でない限り変更しないでください。failureThreshold
7. まとめ
プローブの正しい設定は技術的に難易度が高いですが、以下の点を理解することで意思決定が可能になります。
- スタートアッププロブ: 初期化完了までの保護に必須。
- リアディネスプロブ: Service へのトラフィック制御用。共有リソース状態を直接チェックしないこと。
- ライブネスプロブ: アプリケーションの停滞検出用。共有リソース状態を基準にしないこと。
- ロールアウト時: プローブの設定はデプロイメントの更新速度を左右します。
これらの知識を活かし、より回復力のある Kubernetes クラスターを構築しましょう。