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.status
PodStatus オブジェクト-
phase
Pod のフェーズ。Pending
,Running
,Succeede
,Failed
,Unknown
の値が入る -
reason
Pod の今の状態に至った理由
-
-
pod.status.initContainerStatuses
initContainer 用の 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
動作中かどうか -
ready
ready 状態かどうか
-
-
pod.metadata
ObjectMeta オブジェクト-
deletionTimestamp
削除が始まったときに入る時間
-
また Pod は複数のコンテナ(通常のコンテナ + initContainers) から構成されるので、エラーがあるコンテナの情報が優先的に表示されたりといった工夫をしているため注意が必要です。コンテナすべての情報を見たい場合は、kubectl describe
か kubectl get pod -o yaml
でオブジェクト全体を見たほうが良いでしょう。
代表的な Pod のステータス表記
ステータス表示のもととなるフィールドで分類して、代表的な kubectl の Pod のステータス表記を以下にまとめました。
pod.status.phase
-
Pending
Pod オブジェクトが作成され、まだ全てのコンテナが起動していない状態。フィールドの値としてはコンテナの起動中なども含むが、ContainerCreating
などの表記が優先されて表示されるため、kubectl ではコンテナ起動を行う前までがこの表記となる。 -
Running
すべてのコンテナが起動している状態
pod.status.reason
-
Unknown
Pod の削除前 (deletionTimestamp
が入る前)にノードが未応答 (NodeLost
)になったもの -
NodeLost
Pod の削除中 (deletionTimestamp
が入っている)にノード未応答になったもの -
Evicted
Pod が退避 (Evict)対象となった。Evict はノードのリソースが足りなくなった場合に行われる。
metadata.deletionTimestamp
-
Terminating
Pod の削除時間 (deletionTimestamp
) が入っていて、reason
がNodeLost
ではないもの。終了処理 (preStop やシグナルハンドリング)中の Pod。終了処理が終わると Pod オブジェクト自体が削除される
initContainerStatuses.state.terminated.exitCode
-
Init:0/3
initContainers のうち処理が終わった(終了コードが0)コンテナ数 -
Init:Error
initContainers のコンテナのいずれかエラーが発生した
containerStatuses.state.waiting.reason
-
ContainerCreating
すべてのコンテナが起動するのを待っている状態。コンテナイメージの pull もここに含まれる。(initContainer がない場合) -
PodInitializing
すべてのコンテナが起動するのを待っている状態。コンテナイメージの pull もここに含まれる。 (initContainer がある場合) -
CreateContainerError
いずれかのコンテナの作成時にコンテナランタイム側で処理に失敗した。kubectl describe
で詳細を確認する必要がある。 -
PostStartHookError
いずれかのコンテナの postStart フックが異常終了した -
CrashLoopBackOff
コンテナのいずれかが再起動を待っている状態 (後述) -
ErrImagePull
コンテナのいずれかが pull に失敗した -
ImagePullBackOff
コンテナのいずれかが再 pull を待っている状態 (後述)
containerStatuses.state.terminated.reason
-
Completed
restartPolicy
が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 の担当です。