Kubernetes Pod phases at a glance
Every Kubernetes Pod has a single high-level status.phase value summarising
where it is in its lifecycle. The kubelet on the node owning the Pod sets it
from the aggregate state of all containers. This reference lists the five phase
values, when each is assigned, and which container states they imply.
How it works
The phase is derived, not configured. After scheduling, a Pod starts in
Pending while images pull and init containers run. Once at least one
container is started it moves to Running. Terminal phases depend on the
restartPolicy:
Pending -> Running -> Succeeded (all containers exit 0, no restart)
-> Failed (a container exits non-zero, no restart)
-> Unknown (node/kubelet unreachable)
With restartPolicy: Always (the Deployment default) a crashed container is
restarted and the Pod stays Running — you will see container reasons like
CrashLoopBackOff in kubectl get pod even though the phase is still
Running. Only Never and OnFailure policies let a Pod reach Succeeded
or Failed.
All five phases in detail
Pending
The Pod has been accepted by the cluster but is not yet running. Common reasons:
- Images are being pulled from a registry
- Init containers are running (they must complete before app containers start)
- The scheduler has not yet found a node (resource pressure, taints, affinity rules)
- PersistentVolumeClaims are waiting to be bound
Diagnose with kubectl describe pod POD and look at the Events section.
Running
At least one container is running. This does not mean the application is healthy —
a container can be in its restart backoff inside a Running Pod. The Running phase
persists for the entire lifetime of a Pod with restartPolicy: Always.
Succeeded
All containers have terminated with exit code 0 and will not restart. This is the
terminal state for Job Pods with restartPolicy: Never or OnFailure.
Failed
At least one container exited with a non-zero exit code, or the Pod was terminated
by the system. Like Succeeded, this requires a restartPolicy that allows permanent
exit (Never or OnFailure where failure exhausts retries).
Unknown
The Pod’s state cannot be determined, typically because the node is unreachable. The control plane marks the Pod Unknown when it cannot communicate with the kubelet. If the node recovers quickly, the Pod may return to Running; if the node stays unreachable, the Pod is typically evicted and replaced.
kubectl STATUS versus the phase field
The STATUS column shown by kubectl get pod does not always match the phase
field. The column is a derived human-readable string that includes container
reasons:
| kubectl STATUS | Underlying phase | Meaning |
|---|---|---|
| Running | Running | Container(s) running normally |
| CrashLoopBackOff | Running | Container crashing repeatedly, backoff wait |
| ImagePullBackOff | Pending | Image pull failing, retry backoff |
| Completed | Succeeded | All containers exited 0 |
| Error | Failed | Container exited non-zero |
| Terminating | Running → deletion | Pod is being gracefully stopped |
Useful commands
# Read the raw phase field
kubectl get pod POD -o jsonpath='{.status.phase}'
# See per-container state
kubectl get pod POD -o jsonpath='{.status.containerStatuses[*].state}'
# Events chronologically (useful for Pending diagnosis)
kubectl get events --sort-by=.lastTimestamp -n NAMESPACE
Tips and notes
- The
STATUScolumn inkubectl get podmixes phases and container reasons — treatCrashLoopBackOff,ImagePullBackOffandCompletedas container or derived states, not as thephasefield. - A Pod stuck in
Pendingusually means it cannot be scheduled (no node fits resource requests, taints, or unbound PVCs) — checkkubectl describe pod. Unknownis rare and node-level; the Pod’s real state is unknowable until the kubelet reconnects.- Use
kubectl get pod -o jsonpath='{.status.phase}'to read the raw phase.