Pod Startup Conditions
When a Pod is not Ready, which of its conditions are still False? Five conditions climb in roughly this order, PodScheduled then PodReadyToStartContainers then Initialized then ContainersReady then Ready, and each one is written by a different act, while status.phase moves once on that whole climb. The Kubelet pulls images only once the sandbox behind the second condition is up, and Ready can lag ContainersReady whenever a readinessGate has not agreed.
Play the animation 5 steps, animated, best on a wide screen
Pod Startup Conditions, step by step
-
The Scheduler picks Node-1 and posts a Binding, so the API writes spec.nodeName and adds PodScheduled=True to status.conditions. The Kubelet on that Node sees the bound Pod arrive on its watch and admits it. Nothing is running yet and status.phase is still Pending, which is why the phase field cannot tell you where a slow start is stuck.
Play from step 1 -
The Kubelet has the container runtime create the Pod sandbox, and the runtime calls the CNI plugin to configure its network. With volumes already mounted, the Kubelet then marks PodReadyToStartContainers True and goes on to pull images and create containers without waiting for that status write. The condition has been beta and on by default since 1.29 and goes stable in 1.37.
Play from step 2 -
The init containers run in order and exit 0, so the Kubelet sets Initialized to True. On a Pod that declares no init container at all this rung is True before the sandbox even exists, so the climb is a rough order and not a fixed sequence. Even so, status.phase stays Pending until the app container is created and starts.
Play from step 3 -
The app container starts, and that start, not readiness, is what moves status.phase to Running, its single transition on the whole climb. Its readinessProbe then passes, so every container is ready and the Kubelet sets ContainersReady. A container that starts and never passes that probe leaves the Pod Running with ContainersReady still False.
Play from step 4 -
Ready is not a copy of ContainersReady. The Kubelet computes it as ContainersReady AND every condition in spec.readinessGates, so this Pod held Ready at False until a controller set its gate True. With no gate the two flip together. The Pod IP already sits in the EndpointSlice of every matching Service, and Ready flipping turns that endpoint ready=true.
Play from step 5