基準: Kubernetes v1.35 (kind
kindest/node:v1.35.8でコマンド・YAML を確認)
目次
- Pod phase
- Pod conditions
- Container state
- restartPolicy
- Probe の種類
- Probe のハンドラ
- タイミングのフィールド
- 例
- probe と init container
- 試験のポイント
- 参考ドキュメント
Pod phase
status.phase は、Pod が lifecycle のどのあたりにいるかを示す要約値。コンテナ・Pod の状態をすべて表す state machine ではない、と公式ドキュメントもはっきり書いている。
| phase | 意味 |
|---|---|
Pending | クラスタは Pod を受け付けたが、コンテナの一つ以上がまだ実行準備前。スケジューリング待ち、イメージのダウンロード時間を含む |
Running | ノードに bind され、コンテナがすべて作成された。少なくとも一つが実行中、または起動・再起動中 |
Succeeded | すべてのコンテナが正常終了し、再起動しない |
Failed | すべてのコンテナが終了し、一つ以上が失敗 (non-zero exit またはシステムによる終了)、自動再起動の対象でもない |
Unknown | Pod の状態を取得できない。普通はノードとの通信の問題 |
kubectl get pod の STATUS 列に出る CrashLoopBackOff や Terminating は phase ではない。kubectl が見せる表示用の値で、phase は Pod API のフィールド。
Pod conditions
status.conditions は、Pod が通過した、またはまだ通過していない条件のリスト。kubelet が管理するもののうち probe と直接関係するもの:
| condition | True になるタイミング |
|---|---|
PodScheduled | ノードにスケジュールされた |
PodReadyToStartContainers | sandbox の作成とネットワーク設定が完了 (beta、デフォルト有効) |
Initialized | init container がすべて正常終了 |
ContainersReady | Pod のすべてのコンテナが ready |
Ready | リクエストを受けられる。マッチする Service の load balancing pool に入る |
各 condition には status (True/False/Unknown)、lastTransitionTime、reason、message などが付く。readinessGates でカスタム condition を足すと、コンテナがすべて ready で、かつ gate の condition もすべて True のときだけ Pod が ready になる。
Container state
コンテナごとの state は Waiting、Running、Terminated の三つ。kubectl describe pod <name> で確認する。
Waiting:RunningでもTerminatedでもない状態。イメージの pull や Secret の適用など、起動に必要な作業の途中。Reasonフィールドが一緒に表示されるRunning: 問題なく実行中。postStarthook があったなら、それはもう終わっているTerminated: 実行を始めて、完了したか失敗した状態。reason、exit code、開始・終了時刻が見える。preStophook はこの状態に入る前に実行される
restartPolicy
Pod の spec.restartPolicy。値は Always (デフォルト)、OnFailure、Never。app コンテナと通常の init container に適用される。
| exit code | Always | OnFailure | Never |
|---|---|---|---|
| 0 (成功) | 再起動 | 再起動しない | 再起動しない |
| non-zero (失敗) | 再起動 | 再起動 | 再起動しない |
- 再起動の間隔は exponential backoff: 10s、20s、40s … 最大 300s (5 分)。10 分間問題なく動くと backoff はリセット
- backoff がかかっている間、kubectl に表示されるのが
CrashLoopBackOff - liveness/startup probe の失敗も
CrashLoopBackOffの原因になりうる - sidecar container (
initContainersの中でコンテナ単位のrestartPolicy: Alwaysを指定したもの) は Pod のrestartPolicyを無視して常に再起動 - ワークロードごとの制約: Deployment は
Alwaysのみ、Job はOnFailureかNeverのみ
Probe の種類
| startup probe | liveness probe | readiness probe | |
|---|---|---|---|
| 確認するもの | アプリケーションの起動が終わったか | コンテナを生かし続けるべきか | トラフィックを受けてよいか |
| 実行タイミング | 起動時のみ。成功したら終わり | 定期的にずっと (startup probe があればその成功後) | コンテナの lifecycle の間ずっと定期的に (startup probe があればその成功後) |
| 失敗時 | kubelet がコンテナを kill、restartPolicy を適用 | kubelet がコンテナを kill、restartPolicy を適用 | コンテナを not ready にし、Pod の Ready condition が False、EndpointSlice から Pod IP を外す。再起動なし |
| 主な用途 | 起動が遅いコンテナ | deadlock のように動いてはいるが先に進めない状態 | ウォームアップ、一時的な過負荷、バックエンド依存の確認 |
startup probe があると何が変わるか
startup probe が成功するまで liveness と readiness の probe は実行されない。liveness・readiness の initialDelaySeconds も startup probe の成功後から数える。
起動にかかる時間が initialDelaySeconds + failureThreshold × periodSeconds より長いなら startup probe を使う、というのが公式ドキュメントの推奨。liveness probe と同じ endpoint を見るようにして、failureThreshold を多めに取る。liveness 側のデフォルト値はいじらない。
liveness probe は readiness を待つのか
待たない。二つの probe は互いの成功に依存しない。liveness を遅らせて始めたいなら initialDelaySeconds か startup probe を使う。
probe を定義しなかったら
その probe の結果は常に Success とみなされる。ただし readiness probe は、定義されていれば initial delay が過ぎるまで Failure。だから readiness probe がある Pod はトラフィックなしで起動し、probe が成功してからトラフィックを受け始める。
liveness probe を間違って設定すると
公式ドキュメントが caution で警告している部分。liveness probe は本当に復旧不能な状態 (deadlock など) のときだけ失敗するべき。負荷が高いときに liveness が失敗すると、コンテナが次々に再起動し、残った Pod に負荷が集中する cascading failure につながる。
問題があるとプロセスが自分で落ちる作りなら、liveness probe がなくても kubelet が restartPolicy どおりに処理する。よくあるパターンは、readiness と同じ軽い HTTP endpoint を使いつつ liveness 側の failureThreshold を高めにすること。そうすると kill の前に not ready の状態がしばらく続く。
Probe のハンドラ
一つの probe に次の四つのうちちょうど一つを指定する。
| ハンドラ | 成功の条件 | メモ |
|---|---|---|
exec | コンテナ内でコマンドを実行し、exit code 0 | 実行のたびにプロセスを fork する。Pod の密度が高く周期が短いとノードの CPU の負担に |
httpGet | Pod IP に GET し、ステータスコードが 200 以上 400 未満 | path のデフォルトは /、scheme のデフォルトは HTTP。HTTPS は証明書を検証しない |
tcpSocket | 指定ポートへの TCP 接続が成立 | 接続はノードから行う。host に Service 名を入れても kubelet は名前解決できない |
grpc | gRPC Health Checking Protocol の応答の status が SERVING | v1.27 で stable。port 必須、named port は不可 |
結果は Success、Failure、Unknown。Unknown は診断自体が失敗した場合なので、何もせず次のチェックに進む。
named port
container のポートに名前を付けておき、ほかの場所では番号の代わりにその名前で参照する方法。httpGet と tcpSocket の port で使える。
ports:
- name: http # 8080 に "http" という名前を付ける
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: http # 番号の代わりに名前で指定
- ポート番号は
containerPortの 1 か所だけで管理する。8080 が 9090 に変わっても probe はそのまま - 同じ名前は Service の
targetPort、NetworkPolicy のports.portからも参照できる。Service は Pod ごとにその名前のポートを探すので、Pod 間で番号が違っても 1 つにまとめられる - 命名規則: 最大 15 文字、小文字・数字・
-、英字を 1 文字以上含む、-で始まったり終わったりしない。1 つの Pod 内で重複不可 grpcハンドラは named port を受け付けない。数字のみ
タイミングのフィールド
| フィールド | デフォルト | 最小値 | 意味 |
|---|---|---|---|
initialDelaySeconds | 0 | 0 | コンテナ起動から最初の probe までの待ち時間 |
periodSeconds | 10 | 1 | probe の周期 |
timeoutSeconds | 1 | 1 | probe のタイムアウト |
successThreshold | 1 | 1 | 失敗の後に成功とみなすための連続成功回数。liveness・startup は必ず 1 |
failureThreshold | 3 | 1 | 連続失敗がこの回数に達するとチェック全体が失敗 |
terminationGracePeriodSeconds | Pod の値を継承 (未指定なら 30) | 1 | probe の失敗でコンテナを落とすとき、SIGKILL までの待ち時間。readiness probe には設定不可 (API server が拒否) |
startup probe が許す最大の起動時間は failureThreshold × periodSeconds。failureThreshold: 30、periodSeconds: 10 なら 300 秒。
例
三つの probe を一緒に使う Pod
apiVersion: v1
kind: Pod
metadata:
name: probe-demo
spec:
containers:
- name: app
image: registry.k8s.io/e2e-test-images/agnhost:2.40
args: ["liveness"]
ports:
- name: http
containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: http
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 10
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 8080
periodSeconds: 5
- 起動後最大 300 秒まで startup probe が
/healthzを見る。一度成功すると liveness・readiness に引き継がれる - イメージと
argsは公式ドキュメントの HTTP liveness の例から持ってきたもの。このイメージの/healthzは最初の 10 秒だけ 200 を返し、その後は 500 を返す。だからこの Pod が probe の失敗で再起動を繰り返すのは正常。v1.35 の kind クラスタで動かすと、約 40 秒後に最初の liveness 失敗による再起動が出て、再起動後は startup probe が最初の 10 秒を逃すのでStartup probe failed ... statuscode: 500のイベントがたまっていく
exec、grpc
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"]
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
grpc:
port: 2379
initialDelaySeconds: 10
確認コマンド
kubectl describe pod probe-demo # Events に Unhealthy / Killing、Liveness probe failed のメッセージ
kubectl get pod probe-demo # READY 0/1、RESTARTS が増えるか
kubectl get pod probe-demo -o jsonpath='{.status.phase}'
kubectl get pod probe-demo -o jsonpath='{.status.conditions}'
kubectl get pod probe-demo -o jsonpath='{.status.containerStatuses[0].state}'
kubectl explain pod.spec.containers.livenessProbe
RESTARTS は、失敗したコンテナが再び running 状態に戻った瞬間に増える。
probe と init container
入門記事で例に挙げた「アプリが立ち上がる前に DB への接続を確認したい」という要件は、どちらでも解決できそうに見えて紛らわしい。動くタイミングと失敗したときの結果が違う。
| init container | startup probe | readiness probe | |
|---|---|---|---|
| 定義する場所 | spec.initContainers | app コンテナの startupProbe | app コンテナの readinessProbe |
| 実行タイミング | app コンテナの起動前、順番に一つずつ | app コンテナの起動後、成功するまで | app コンテナの lifecycle の間ずっと |
| 成功の基準 | 最後まで実行して exit 0 | ハンドラが 1 回成功 | 連続 successThreshold 回成功 |
| 失敗時 | Pod の restartPolicy どおりに再試行 (Always なら OnFailure として動作)。Never なら Pod 全体が失敗 | コンテナを kill、restartPolicy を適用 | トラフィックから外す、コンテナは動き続ける |
| 関連する condition | Initialized | - | ContainersReady、Ready |
| probe 対応 | なし (livenessProbe、readinessProbe、startupProbe フィールド不可) | - | - |
- 依存先の準備ができるまでアプリのプロセス自体を立ち上げないなら: init container
- アプリは動かしたまま、依存先が切れたらトラフィックだけ外したいなら: readiness probe。公式ドキュメントも、バックエンドへの依存が強いアプリは liveness でアプリ自身の健全性を、readiness でバックエンドの可用性まで見るように勧めている
- sidecar container は
initContainersに入るが、動き続けて probe にも対応する
試験のポイント
- probe には imperative なフラグがない。
kubectl run app --image=nginx --dry-run=client -o yaml > pod.yamlで骨組みを作って、probe は YAML で足す - フィールドの場所は
spec.containers[].livenessProbe。specの直下ではない - フィールド名は
livenessProbe、readinessProbe、startupProbeと camelCase。ハンドラはhttpGet、tcpSocket、exec、grpc - liveness・startup の
successThresholdに 1 以外を入れてはいけない - readiness の失敗では再起動は起きない。
RESTARTSが増えているなら liveness か startup の方を見る restartPolicy: Neverの Pod で liveness が失敗すると、コンテナは kill されて二度と起動しないSTATUS列のCrashLoopBackOffは phase ではない。phase を聞かれたら-o jsonpath='{.status.phase}'で確認
kubectl explain
kubectl explain pod.spec.containers.livenessProbe # 共通フィールド: periodSeconds、failureThreshold など
kubectl explain pod.spec.containers.livenessProbe.httpGet # path、port、httpHeaders
kubectl explain pod.spec.containers.startupProbe
kubectl explain pod.spec.containers.lifecycle # postStart、preStop
kubectl explain pod.spec.terminationGracePeriodSeconds
kubectl explain pod.spec.restartPolicy # Always / OnFailure / Never