kubectl で Pod を表示した場合、Running や Terminating などのステータスが表示されます。しかし、このステータスは Pod オブジェクトの単一フィールドを表示しているわけではなく、いくつかのフィールドと条件によって表示が分けられています。
この記事ではよく見る Pod のステータス表記について整理してみます。
kubectl のステータスの出し分け
ご存じの通りkubectl で Pod を表示したとき、下記のように STATUS カラムで Pod のステータスを見ることができます。
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
myapp 0/1 Pending 0 0s
myapp 0/1 ContainerCreating 0 0s
myapp 1/1 Running 0 1s
myapp 1/1 Terminating 0 8s
Pod の状態は主に pod.status フィールドにて PodStatus というオブジェクトで管理されています。PodStatus には Phase というフィールドがありますが、kubectl は単純にこれを表示しているわけではありません。
kubectl の Pod のステータス表示のロジックは主に printers.go の printPod() という関数になります。
この関数では下記の Pod のフィールドを参照して Pod のステータスを出しています。より詳細な情報があればそれを優先して表示されるようになっています。例えば、pod.status.phase が pending で containerStatuses.state.waiting.reason が ContainerCreating の場合は、ContainerCreating が表示されます。
-
pod.statusPodStatus オブジェクト-
phasePod のフェーズ。Pending,Running,Succeede,Failed,Unknownの値が入る -
reasonPod の今の状態に至った理由
-
-
pod.status.initContainerStatusesinitContainer 用の ContainerStatus の配列-
restartCount再起動した階数 -
state.waiting.reason処理を待っている理由 (CrashLoopBackoffなど) -
state.terminated.exitCode終了した場合の終了コード -
state.terminated.reason終了した場合の理由 -
state.terminated.signal終了した場合のシグナル
-
-
pod.status.containerStatuses通常のコンテナ用の ContainerStatus の配列-
restartCount再起動した階数 -
state.waiting.reason処理を待っている理由 (CrashLoopBackoffなど) -
state.terminated.exitCode終了した場合の終了コード -
state.terminated.reason終了した場合の理由 -
state.terminated.signal終了した場合のシグナル -
state.running動作中かどうか -
readyready 状態かどうか
-
-
pod.metadataObjectMeta オブジェクト-
deletionTimestamp削除が始まったときに入る時間
-
また Pod は複数のコンテナ(通常のコンテナ + initContainers) から構成されるので、エラーがあるコンテナの情報が優先的に表示されたりといった工夫をしているため注意が必要です。コンテナすべての情報を見たい場合は、kubectl describe か kubectl get pod -o yaml でオブジェクト全体を見たほうが良いでしょう。
代表的な Pod のステータス表記
ステータス表示のもととなるフィールドで分類して、代表的な kubectl の Pod のステータス表記を以下にまとめました。
pod.status.phase
-
PendingPod オブジェクトが作成され、まだ全てのコンテナが起動していない状態。フィールドの値としてはコンテナの起動中なども含むが、ContainerCreatingなどの表記が優先されて表示されるため、kubectl ではコンテナ起動を行う前までがこの表記となる。 -
Runningすべてのコンテナが起動している状態
pod.status.reason
-
UnknownPod の削除前 (deletionTimestampが入る前)にノードが未応答 (NodeLost)になったもの -
NodeLostPod の削除中 (deletionTimestampが入っている)にノード未応答になったもの -
EvictedPod が退避 (Evict)対象となった。Evict はノードのリソースが足りなくなった場合に行われる。
metadata.deletionTimestamp
-
TerminatingPod の削除時間 (deletionTimestamp) が入っていて、reasonがNodeLostではないもの。終了処理 (preStop やシグナルハンドリング)中の Pod。終了処理が終わると Pod オブジェクト自体が削除される
initContainerStatuses.state.terminated.exitCode
-
Init:0/3initContainers のうち処理が終わった(終了コードが0)コンテナ数 -
Init:ErrorinitContainers のコンテナのいずれかエラーが発生した
containerStatuses.state.waiting.reason
-
ContainerCreatingすべてのコンテナが起動するのを待っている状態。コンテナイメージの pull もここに含まれる。(initContainer がない場合) -
PodInitializingすべてのコンテナが起動するのを待っている状態。コンテナイメージの pull もここに含まれる。 (initContainer がある場合) -
CreateContainerErrorいずれかのコンテナの作成時にコンテナランタイム側で処理に失敗した。kubectl describeで詳細を確認する必要がある。 -
PostStartHookErrorいずれかのコンテナの postStart フックが異常終了した -
CrashLoopBackOffコンテナのいずれかが再起動を待っている状態 (後述) -
ErrImagePullコンテナのいずれかが pull に失敗した -
ImagePullBackOffコンテナのいずれかが再 pull を待っている状態 (後述)
containerStatuses.state.terminated.reason
-
CompletedrestartPolicyがnever(コンテナを再起動しない設定)ですべてのコンテナが正常終了した -
Errorコンテナのいずれかが異常終了 (終了ステータスが 0 以外)した -
OOMKilledメモリが足りず OOM (Out of Memory) Killer によって kill された。resources の limit のメモリが足りているか要確認
BackOff について
CrashLoopBackoff や ImagePullBackOff の BackOff はリトライの間隔を Exponential Backoff というアルゴリズムで、間隔を指数関数的に増やしていくことを意味しています。
Kubernetes 1.12.3 の実装では CrashLoopBackoff と ImagePullBackOff のリトライ間隔(backoff)は以下のようになっています。
例えばコンテナが起動時に異常終了した(終了コードが 0 以外) 場合は、下記のように Error と CrashLoopBackoff のステータスが交互に現れることになります。
$ kubectl get pods -w
myapp 1/2 Error 0 7s
myapp 1/2 Error 1 11s
myapp 1/2 CrashLoopBackOff 1 12s
myapp 1/2 Error 2 27s
myapp 1/2 CrashLoopBackOff 2 38s
myapp 1/2 Error 3 52s
myapp 1/2 CrashLoopBackOff 3 63s
myapp 1/2 Error 4 100s
まずコンテナが異常終了したため、終了理由 containerStatuses.state.terminated.reason に Error が入り、次に BackOff の時間を待っている間、待ち理由 containerStatuses.state.waiting.reason に CrashLoopBackoff が入ります。再度コンテナが起動して異常終了し、これを繰り返すためこのような表示になります。
Pod のステータスの例
initContainer を持たない場合
initContainer を持たない Pod の場合、下記のようにステータスが変化していきます。
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
# Pod オブジェクトが作成された時点で Pending になる
myapp 0/1 Pending 0 0s
# Pod がスケジュールされ kubelet でこの状態になる
myapp 0/1 ContainerCreating 0 0s
# すべてのコンテナが立ち上がると Running になる
myapp 1/1 Running 0 6s
# 終了処理中は Terminating となる
myapp 1/1 Terminating 0 10s
myapp 0/1 Terminating 0 10s
initContainer を持つ場合
initContainer を持つ Pod の場合、少しステータスの変化が異なります。以下の例では initContainer 3 つ、コンテナ 3つの Pod の起動例です。
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
# Pod オブジェクトが作成された時点で Pending になる
myapp 0/3 Pending 0 0s
# initContainers の初期化が始まる (3つ分)
myapp 0/3 Init:0/3 0 0s
myapp 0/3 Init:1/3 0 4s
myapp 0/3 Init:2/3 0 8s
# initContainers の初期化が終わると、PodInitializing の表記になる。
myapp 0/3 PodInitializing 0 12s
# コンテナが起動していく (3つ分)
myapp 0/3 Running 0 23s
myapp 1/3 Running 0 34s
myapp 2/3 Running 0 49s
myapp 3/3 Running 0 55s
# 終了中は Terminating の表記となる
myapp 3/3 Terminating 0 69s
myapp 0/3 Terminating 0 99s
まとめ
kubectl のステータスは様々なフィールドを参照して表示しています。kubectl get pods -w で遷移をウォッチしてみるとステータスの遷移がわかりデバッグ時にも役立ちます。
このエントリは、弊社 Z Lab のメンバーによる Z Lab Advent Calendar 2018 の3日目として業務時間中に書きました。4日目は @watawuwu の担当です。