Every Kubernetes troubleshooting conversation starts the same way: someone runs kubectl get pods, reads the STATUS column, and says “the Pod is in CrashLoopBackOff” or “the Pod is Terminating”. Both statements feel precise. Neither names a Pod phase. Kubernetes has exactly five phases, and CrashLoopBackOff and Terminating are not among them. The STATUS column is a convenience that kubectl assembles from three different parts of the Pod’s status object, and the KCNA exam likes to test whether you know which part is which.
This guide is about that status object. It sits between the Kubernetes architecture guide, which explains who writes the status (the kubelet, the scheduler, the controllers), and the workloads and controllers guide, which explains who reads it (ReplicaSets, Jobs, Services). Probes and lifecycle hooks have their own deep dives for the CKAD (probes, lifecycle hooks and graceful shutdown); here we cover them only as far as they change what you see in kubectl get and kubectl describe. Everything below follows the Kubernetes v1.37 documentation.
Where This Sits in the KCNA Curriculum
The KCNA curriculum was refreshed in late 2025 and now weights Kubernetes Fundamentals at 44%, Container Orchestration at 28%, Cloud Native Application Delivery at 16% and Cloud Native Architecture at 12%. Pod status is tested in three of those four domains:
| Domain | How Pod status appears |
|---|---|
| Kubernetes Fundamentals | ”Which phase means all containers exited successfully?”, “Which component sets the phase?”, “What does restartPolicy: OnFailure do?” |
| Container Orchestration | Troubleshooting items: “A Pod shows ImagePullBackOff. What is its phase?”, “Why is a Pod Running but 0/1 READY?” |
| Cloud Native Application Delivery | Debugging items: “Which command shows why a container restarted?”, “What happens to Service traffic while a Pod terminates?” |
The exam is multiple choice, so you will never be asked to fix a Pod. You will be asked to interpret output, to pick the component responsible for a transition, and to spot the distractor that confuses a kubectl display string with an API field. That is why the first thing to learn is the shape of the object itself.
The Three Layers of a Pod’s Status
Run kubectl get pod web -o yaml and look at the status: block. Trimmed to the fields that matter, it looks like this:
status:
phase: Running # layer 1: one coarse word
conditions: # layer 2: a list of true/false checkpoints
- type: PodReadyToStartContainers
status: "True"
- type: Initialized
status: "True"
- type: Ready
status: "False"
reason: ContainersNotReady
message: 'containers with unready status: [web]'
- type: ContainersReady
status: "False"
- type: PodScheduled
status: "True"
containerStatuses: # layer 3: one entry per container
- name: web
ready: false
restartCount: 4
started: true
state:
running:
startedAt: "2026-10-30T08:12:41Z"
lastState:
terminated:
exitCode: 1
reason: Error
finishedAt: "2026-10-30T08:12:30Z"
hostIP: 10.0.1.12
podIP: 10.244.3.17
qosClass: Burstable
startTime: "2026-10-30T08:09:02Z"
The three layers are:
phase: a single word summarising where the Pod is in its lifecycle. Five possible values, nothing else.conditions: an array of named checkpoints, eachTrue,FalseorUnknown, with areason, amessageand alastTransitionTime.containerStatuses(plusinitContainerStatusesandephemeralContainerStatuses): per-container detail, including the container’s currentstate, itslastState, how many times it has restarted and whether it isready.
kubectl get pods compresses all three into one STATUS word and one READY fraction. The rest of this guide takes the layers in turn and then explains how the compression works, because that is where the exam distractors live.
Layer 1: The Five Pod Phases
The documentation is unusually strict here: “The number and meanings of Pod phase values are tightly guarded. Other than what is documented here, nothing should be assumed about Pods that have a given phase value.”
| Phase | Documented meaning | Typical causes |
|---|---|---|
Pending | The Pod has been accepted by the cluster, but one or more containers has not been set up and made ready to run. This includes time spent waiting to be scheduled and time spent downloading images. | No node fits the requests, a PersistentVolumeClaim is unbound, the image is still pulling or cannot be pulled, a ConfigMap or Secret the Pod references is missing |
Running | The Pod has been bound to a node and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting. | Normal operation, and also a container stuck in a crash loop |
Succeeded | All containers in the Pod have terminated in success and will not be restarted. | A Job or a one-shot Pod with restartPolicy: Never or OnFailure that exited 0 |
Failed | All containers have terminated, and at least one terminated in failure, meaning a non-zero exit or termination by the system, and is not set for automatic restart. | A Job Pod that exited non-zero under restartPolicy: Never, an evicted Pod, a Pod on a node that was lost |
Unknown | The state of the Pod could not be obtained, typically because of an error communicating with the node where the Pod should be running. | The kubelet stopped reporting; the node is unreachable |
Four facts about phases turn up in questions repeatedly:
Pendingcovers more than scheduling. A Pod that has been scheduled and is pulling a 2 GB image is stillPending. So is a Pod whose image name is wrong. If no container has been created yet, the phase isPending, whateverkubectlprints beside it.Runningdoes not mean healthy. A Pod whose only container crashes every ten seconds isRunning, because the container has been created and is “in the process of starting or restarting”. Healthy is what theReadycondition says, not what the phase says.SucceededandFailedare terminal. Nothing moves a Pod out of them. A controller that wants the work redone creates a new Pod. That is also why a Deployment can never be allowed to userestartPolicy: Never: its Pods are supposed to run forever, and a terminal phase would strand the ReplicaSet.- A Pod is scheduled once. The documentation puts it directly: “A given Pod (as defined by a UID) is never ‘rescheduled’ to a different node; instead, that Pod can be replaced by a new, near-identical Pod.” If a node dies, Kubernetes “applies a policy for setting the phase of all Pods on the lost node to Failed”, and the owning controller replaces them. The node failure lifecycle guide covers the timers behind that.
One more transition is recent enough to be a fresh question. Since Kubernetes 1.27, when a Pod is deleted the kubelet moves it to a terminal phase (Failed or Succeeded, depending on the containers’ exit statuses) before the API object disappears, so that a watcher always sees the final state. The exceptions are static Pods and force-deleted Pods without finalizers.
What kubectl Shows Instead of the Phase
Here is the part that catches candidates. Terminating, CrashLoopBackOff, ImagePullBackOff, ContainerCreating, Completed, Error, Evicted and Init:0/2 all appear in the STATUS column of kubectl get pods, and none of them is a phase. The documentation adds a warning note for exactly this reason: “Make sure not to confuse Status, a kubectl display field for user intuition, with the pod’s phase.”
kubectl builds the display string from the three layers in a fixed order of precedence. Simplified:
- If the Pod has a
deletionTimestamp, printTerminating(unless the node is lost, which prints the Pod’sstatus.reasoninstead). - Otherwise, if
status.reasonis set (for exampleEvicted), print that. - Otherwise, if any init container is not finished, print its progress or problem:
Init:0/2,Init:Error,Init:CrashLoopBackOff. - Otherwise, if any app container is
Waitingwith a reason, print the reason:ContainerCreating,PodInitializing,ImagePullBackOff,ErrImagePull,CreateContainerConfigError,CrashLoopBackOff. - Otherwise, if a container is
Terminatedwith a reason, print it:Completed,Error,OOMKilled. - Otherwise, print the phase:
Pending,Running,Succeeded,Failed,Unknown.
That ordering produces the mapping the KCNA tests most often:
STATUS shown | Actual phase | Which layer it came from | What it means |
|---|---|---|---|
Pending | Pending | phase | Not yet scheduled, or scheduled but no container created and no reason recorded yet |
ContainerCreating | Pending | container Waiting reason | Scheduled; the kubelet is pulling the image, mounting volumes, creating the sandbox |
ImagePullBackOff / ErrImagePull | Pending | container Waiting reason | The image cannot be pulled (wrong name, tag, registry auth); the kubelet backs off between attempts |
CreateContainerConfigError | Pending | container Waiting reason | A referenced ConfigMap or Secret key does not exist, or runAsNonRoot is set and the image runs as root |
Init:0/2 | Pending | init container progress | Init containers are running; zero of two have finished |
Init:Error / Init:CrashLoopBackOff | Pending | init container state | An init container exited non-zero and is being retried |
PodInitializing | Pending | container Waiting reason | Init containers finished; app containers are about to start |
Running | Running | phase | Containers created and at least one running; look at READY to see whether it is serving |
CrashLoopBackOff | Running | container Waiting reason | A container keeps exiting; the kubelet is waiting out the backoff before the next restart |
Completed | Succeeded | container Terminated reason | All containers exited 0 and will not restart |
Error | Failed (or Running if other containers are up) | container Terminated reason | A container exited non-zero and will not be restarted under the current policy |
OOMKilled | depends on restartPolicy | container Terminated reason | The kernel killed the container for exceeding its memory limit |
Evicted | Failed | status.reason | The kubelet evicted the Pod under node pressure |
Terminating | Running (usually) | deletionTimestamp | Deletion requested; the grace period is running |
Unknown | Unknown | phase | The node stopped reporting |
Two of those rows are worth memorising as a pair, because they are the classic distractor: ImagePullBackOff is a Pending Pod, CrashLoopBackOff is a Running Pod. In the first case the container was never created; in the second it was created, ran, exited and is being restarted. If a question asks “which phase is a Pod in CrashLoopBackOff?”, the answer is Running.
The READY column is simpler: it is the count of containers whose ready field is true over the total number of app containers (native sidecars are counted too). 1/1 Running is the healthy steady state; 0/1 Running means the container is up but its readiness probe is failing, or it has no probe and has not finished starting.
Layer 3: Container States
Each entry in containerStatuses has a state with exactly one of three keys. The documentation defines them as follows:
| State | Definition | Fields you see |
|---|---|---|
Waiting | ”If a container is not in either the Running or Terminated state, it is Waiting. A container in the Waiting state is still running the operations it requires in order to complete start up: for example, pulling the container image from a container image registry, or applying Secret data.” | reason, message |
Running | ”The Running status indicates that a container is executing without issues. If there was a postStart hook configured, it has already executed and finished.” | startedAt |
Terminated | ”A container in the Terminated state began execution and then either ran to completion or failed for some reason.” | exitCode, reason, message, startedAt, finishedAt, signal |
Three details matter for the exam:
Runningis only entered afterpostStartcompletes. ApostStarthook that hangs keeps the container inWaitingforever, which is one reason the lifecycle hooks guide callspostStarta trap.lastStateis where the evidence lives. When a container is restarting,stateshowsWaitingwith reasonCrashLoopBackOff, andlastState.terminatedshows the exit code and reason from the previous run.kubectl describe podprints both under “Last State”. For the logs of that previous run, usekubectl logs web --previous; the monitoring and logs guide explains why plainkubectl logsoften shows nothing for a crashing container.restartCountis per container, cumulative, and reset only when the Pod is replaced. It is the quickest signal that something has been wrong for a while, even if the Pod currently showsRunning.
Exit codes follow Unix convention: 0 is success, 1 to 127 are application-defined failures, 137 is 128 + 9 (killed by SIGKILL, the signature of an OOM kill or a hard grace-period expiry) and 143 is 128 + 15 (SIGTERM). If a question shows exitCode: 137 and reason: OOMKilled, the fix is a memory limit or a memory leak, not a probe.
Layer 2: Pod Conditions
Conditions are the structured layer. Each has a type, a status of True, False or Unknown, and usually a reason, a message and a lastTransitionTime. The current set:
| Condition | True when… | Set by | Notes |
|---|---|---|---|
PodScheduled | the Pod has been scheduled to a node | kube-scheduler | False with reason Unschedulable is the “0/3 nodes are available” case; see the scheduler guide |
PodReadyToStartContainers | the Pod sandbox has been created, networking configured, storage volumes mounted and any dynamic resources allocated | kubelet | Stable since v1.37; was called PodHasNetwork in its early alpha |
Initialized | all init containers have completed successfully | kubelet | With native sidecars, Initialized becomes True once each sidecar has started |
ContainersReady | all containers in the Pod are ready | kubelet | Reflects readiness probes |
Ready | the Pod is able to serve requests and should be added to the load balancing pools of all matching Services | kubelet | Requires ContainersReady plus every readiness gate |
DisruptionTarget | the Pod is about to be terminated due to a disruption such as preemption, eviction or garbage collection | kubelet, scheduler, controllers | reason tells you which: PreemptionByScheduler, EvictionByEvictionAPI, DeletionByTaintManager, TerminationByKubelet, DeletionByPodGC |
PodResizePending | an in-place resize was requested but cannot be applied yet | kubelet | Companion to in-place resize, stable since v1.35; see the in-place resize guide |
PodResizeInProgress | the Pod is in the process of resizing | kubelet | — |
The order you normally see is the order of the lifecycle: PodScheduled, then PodReadyToStartContainers, then Initialized, then ContainersReady, then Ready. When a Pod is 0/1 Running, the two False conditions are ContainersReady and Ready, both with reason ContainersNotReady, and the message names the unready container. That message is the single most useful line in kubectl describe for a “why is my Pod not receiving traffic” question.
Ready is the condition Services care about. The EndpointSlice controller only includes a Pod’s IP as a ready endpoint while Ready is True, which is how a failing readiness probe silently removes a Pod from rotation without restarting it. The Services and networking guide covers the EndpointSlice side.
Readiness gates
Readiness gates (stable since v1.14) let something outside the Pod add its own requirement to Ready. The classic case is a cloud load balancer controller that does not want traffic sent to a Pod until the Pod is registered as a healthy target.
spec:
readinessGates:
- conditionType: "www.example.com/feature-1"
With a gate declared, the kubelet marks the Pod Ready only when both all containers are ready and every gate condition is True. A gate condition that has never been written defaults to False, so a declared gate with no controller behind it keeps the Pod unready forever. Controllers set the condition with a PATCH to the Pod’s status subresource; the documentation notes that kubectl patch does not support patching object status, which is why you will not do this by hand.
Init Containers, Sidecars and the Initialized Condition
Init containers run to completion, one after another, before any app container starts. While they run, kubectl shows Init:0/2, Init:1/2 and so on; if one fails, the Pod shows Init:Error and then Init:CrashLoopBackOff as the kubelet retries it. The Pod’s phase throughout is Pending, and the Initialized condition is False.
The Pod-level restartPolicy governs init container retries too. Under Always or OnFailure a failed init container is retried with the normal backoff; under Never the whole Pod goes straight to Failed.
Native sidecar containers, stable since Kubernetes 1.33, are init containers that declare their own restartPolicy: Always. They start in order with the other init containers but keep running for the life of the Pod, they are restarted independently of the Pod-level policy, and they are terminated after the app containers during shutdown. For the status object this has two consequences: Initialized turns True once a sidecar has started rather than exited, and sidecars appear in the READY count. The multi-container patterns guide covers the YAML; for the KCNA you need the concept and the version.
restartPolicy and the Backoff Timer
spec.restartPolicy is a Pod-level field with three values, and the documentation defines them tightly:
| Value | Behaviour | Allowed in |
|---|---|---|
Always (default) | “Automatically restarts the container after any termination.” | Deployments, ReplicaSets, StatefulSets, DaemonSets (required) |
OnFailure | ”Only restarts the container if it exits with an error (non-zero exit status).” | Jobs, CronJobs, bare Pods |
Never | ”Does not automatically restart the terminated container.” | Jobs, CronJobs, bare Pods |
The field applies to all app containers and regular init containers in the Pod; sidecars ignore it and always restart. Restarts are performed by the kubelet, on the same node, inside the same Pod; the Pod’s UID, IP and volumes are untouched. That is the difference between a restart (kubelet, same Pod) and a replacement (controller, new Pod), and the exam checks that you can tell them apart.
The restart is not immediate. The kubelet applies exponential backoff: ”10s, 20s, 40s, …” and “capped at 300 seconds (5 minutes)”. While the kubelet is waiting out that delay, the container’s state is Waiting with reason CrashLoopBackOff, which the documentation describes as indicating “that the backoff delay mechanism is currently in effect for a given container that is in a crash loop, failing and restarting repeatedly.” Once a container has run for 10 minutes without a problem, the kubelet resets its backoff timer.
So CrashLoopBackOff is not a state the container is in; it is a state the kubelet is in with respect to that container. The container itself is Terminated (see lastState), and in a few seconds it will be started again. The causes are almost always inside the container: a missing environment variable, a bad command, a dependency that is not reachable, a liveness probe killing a slow starter. The CKAD troubleshooting guide and the CKA troubleshooting guide walk through the diagnosis.
Three newer knobs change the numbers and are current enough to appear as “which is true in recent releases” questions:
KubeletCrashLoopBackOffMax(beta, enabled by default since v1.35) lets a cluster administrator setcrashLoopBackOff.maxContainerRestartPeriodin the kubelet configuration to anything from1sto300s, lowering the cap below five minutes for the whole node. The kubelet configuration guide shows where that field lives.ReduceDefaultCrashLoopBackOffDecay(alpha, disabled by default since v1.33) changes the default curve to start at 1 s and cap at 60 s.- Container restart rules (
ContainerRestartRules, beta and enabled by default since v1.35) add a container-levelrestartPolicyand arestartPolicyRuleslist, so one container in a Pod can be restarted only on specific exit codes while the Pod-level policy staysNever:
apiVersion: v1
kind: Pod
metadata:
name: restart-on-exit-codes
spec:
restartPolicy: Never
containers:
- name: worker
image: registry.k8s.io/busybox:1.27.2
command: ['sh', '-c', 'sleep 60 && exit 42']
restartPolicy: Never
restartPolicyRules:
- action: Restart
exitCodes:
operator: In
values: [42]
Rules are evaluated in order; if none matches, the container falls back to its own restartPolicy. The documentation requires that “If the restartPolicyRules field is specified, then container restartPolicy must also be specified.” A companion gate, RestartAllContainersOnContainerExits (beta since v1.36), adds a RestartAllContainers action that restarts every container in the Pod in place, keeping the Pod’s UID, IP, sandbox and volumes and re-running the init containers. For the KCNA, the takeaway is the direction of travel: restart behaviour is moving from one Pod-wide switch to per-container, per-exit-code policy.
How Probes Move a Pod Between States
Probes are the kubelet’s way of asking a container how it is doing, and each type changes a different layer of the status object:
| Probe | Question it answers | On failure | What changes in status |
|---|---|---|---|
startupProbe | ”Has the application in this container started?” | The kubelet kills the container and restarts it per restartPolicy; liveness and readiness probes do not run until startup succeeds | restartCount increments; container Waiting → Running cycle |
livenessProbe | ”Should this container be restarted?” | The kubelet kills and restarts the container | restartCount increments; lastState.terminated populated; possible CrashLoopBackOff |
readinessProbe | ”Should this container receive traffic?” | The container’s ready flips to false; the Pod leaves the Ready condition; the EndpointSlice controller removes the Pod’s IP from matching Services | READY shows 0/1; Ready and ContainersReady become False; no restart |
Every probe uses one of four mechanisms (exec, grpc, httpGet, tcpSocket) and returns Success, Failure or Unknown. A container with no readiness probe is considered ready as soon as it is running, and a container with no liveness probe is considered live as long as its process is up.
The exam asks this as a contrast question: “A Pod shows 0/1 READY and Running, and restartCount is 0. Which probe is failing?” Readiness. “A Pod’s restartCount keeps climbing and it alternates between Running and CrashLoopBackOff, but the application logs look healthy.” Liveness, probably too aggressive. The CKAD probes guide covers the timing fields and anti-patterns.
The Termination Sequence
Deleting a Pod is a negotiated shutdown, not an instant removal, and the documentation lays out the sequence step by step. With the default grace period of 30 seconds:
- You delete the Pod (
kubectl delete pod web, or a controller does it for you during a rolling update or scale-down). The API server records the deletion timestamp and the deadline. - The Pod shows as
Terminatinginkubectl getandkubectl describe. Its phase is unchanged. The kubelet on the node sees the update and begins local shutdown:- If any container has a
preStophook andterminationGracePeriodSecondsis not 0, the kubelet runs the hook. If the hook is still running when the grace period expires, the kubelet “requests a small, one-off grace period extension of 2 seconds.” - The kubelet then “triggers the container runtime to send a TERM signal to process 1 inside each container.” If a container defines a custom stop signal (
ContainerStopSignals, alpha since v1.33), that signal is sent instead.
- If any container has a
- The control plane removes the Pod from EndpointSlices. This happens in parallel with step 2. Endpoints are “not immediately removed”; they are marked terminating, and “Terminating endpoints always have their ready status as false”, so new connections stop arriving while in-flight ones complete.
- When the grace period expires, the kubelet forces shutdown. “The container runtime sends SIGKILL to any processes still running.” The kubelet transitions the Pod into a terminal phase, requests forcible removal from the API server by setting the grace period to 0, and the API server deletes the Pod object.
Two implications matter for status questions. First, Terminating can persist for the full grace period if the application ignores SIGTERM, which is normal and not an error; a Pod stuck in Terminating beyond that usually has a finalizer that is not being removed, or lives on a node that stopped responding. Second, because EndpointSlice removal and SIGTERM race each other, a Pod can receive a request a few hundred milliseconds after it starts shutting down. That is what preStop sleeps are for, as the lifecycle hooks guide explains.
Force deletion skips the negotiation:
kubectl delete pod web --grace-period=0 --force
The documentation is explicit that “Immediate deletion does not wait for confirmation that the running resource has been terminated.” The API object disappears, but the process may still be running on the node for a while. For StatefulSet Pods, where identity uniqueness matters, the documentation sends you to a dedicated procedure before force deleting, because a second Pod with the same name could start while the first is still alive.
Pod Garbage Collection
Terminal Pods are not deleted automatically just because they finished. A Succeeded Pod from a Job stays visible as Completed until something removes it, which is why kubectl get pods on a busy cluster shows a tail of finished Pods. Three mechanisms clean them up:
- The owning controller. A Job deletes its Pods when the Job itself is deleted, or when
ttlSecondsAfterFinishedexpires; the Jobs and CronJobs guide covers that field. A Deployment deletes old Pods as part of rollouts. - The PodGC controller in kube-controller-manager. It deletes terminated Pods (
SucceededorFailed) only “when the number of Pods exceeds the configured threshold (determined byterminated-pod-gc-thresholdin the kube-controller-manager)”. The default threshold is 12,500 terminated Pods cluster-wide, so on a small cluster PodGC effectively never runs for this reason. - PodGC’s special cases, which it cleans up regardless of the threshold: orphan Pods “bound to a node which no longer exists”, unscheduled terminating Pods, and terminating Pods “bound to a non-ready node tainted with
node.kubernetes.io/out-of-service”. When PodGC removes a Pod that is not yet terminal, it first marks itFailedand, for orphan Pods, adds aDisruptionTargetcondition with reasonDeletionByPodGC.
The exam angle is the ownership question: who removes a finished Pod. Not the kubelet (it only reports), not the scheduler, and not PodGC on a normal-sized cluster; it is the controller that created the Pod, or you.
Reading Status in Practice
The commands that expose each layer, in the order you would use them:
# The compressed view: STATUS, READY, RESTARTS, AGE, and with -o wide the node and IP
kubectl get pods -o wide
# The uncompressed view: Conditions block, per-container State / Last State / Reason / Exit Code, and Events
kubectl describe pod web
# Just the phase and the Ready condition, across a namespace
kubectl get pods -o custom-columns='NAME:.metadata.name,PHASE:.status.phase,READY:.status.conditions[?(@.type=="Ready")].status'
# Everything in a particular phase
kubectl get pods --field-selector=status.phase=Pending -A
# Block until a Pod is Ready (or time out), handy in scripts
kubectl wait --for=condition=Ready pod/web --timeout=60s
# The previous container's logs after a crash
kubectl logs web --previous
In kubectl describe, read bottom-up: the Events section tells you what the scheduler and kubelet did and when (Scheduled, Pulling, Pulled, Created, Started, BackOff, Unhealthy, Killing); the Conditions block tells you which checkpoint is False; the Containers block tells you the state, last state and exit code. The kubectl debugging guide picks up from there with exec, port-forward and ephemeral debug containers.
Scenario Drill
| Scenario | Answer |
|---|---|
kubectl get pods shows ImagePullBackOff. What is the Pod’s phase? | Pending. No container has been created. |
kubectl get pods shows CrashLoopBackOff. What is the Pod’s phase? | Running. The container was created and is being restarted after exiting. |
A Pod shows 1/1 Running but users get errors. Which layer would show the problem? | None of them, directly; the Pod is ready. Check application logs and the Service. |
A Pod shows 0/1 Running, RESTARTS 0. What is failing? | The readiness probe (or the container has not finished starting). The liveness probe is not failing, or restarts would climb. |
A Pod shows 0/1 Running, RESTARTS 12, lastState.terminated.exitCode: 137. What happened? | The container was SIGKILLed, most likely OOMKilled; raise the memory limit or fix the leak. |
A Job Pod shows Completed. What is its phase, and will it restart? | Succeeded; no, terminal phases never restart. |
A Pod has been Terminating for two minutes. Is that an error? | Not necessarily; the default grace period is 30 s plus a 2 s preStop extension, so two minutes suggests a long custom grace period, a stuck finalizer or an unresponsive node. |
| Which component restarts a crashed container inside a Pod? | The kubelet on that node, in place, without changing the Pod’s UID or IP. |
| Which component replaces a Pod whose node was lost? | The owning controller (ReplicaSet, StatefulSet, DaemonSet, Job), by creating a new Pod; the old one is marked Failed. |
A Deployment manifest sets restartPolicy: OnFailure. What happens? | The API server rejects it; Deployment Pods must use Always. |
A Pod declares a readiness gate but no controller sets the condition. What is its Ready status? | False, forever; unset gate conditions default to False. |
| Which condition tells you the Pod sandbox and network are ready but containers have not started? | PodReadyToStartContainers (stable since v1.37). |
| After how long of clean running does the kubelet reset the crash backoff timer? | 10 minutes. |
| What is the default maximum delay between crash restarts? | 300 seconds (5 minutes), configurable per node since v1.35 via crashLoopBackOff.maxContainerRestartPeriod. |
What is the default terminated-pod-gc-threshold? | 12,500 terminated Pods cluster-wide. |
Common Mistakes
- Calling
CrashLoopBackOfforTerminatinga phase. They arekubectldisplay strings derived from container state and the deletion timestamp. There are five phases. - Assuming
Runningmeans healthy. Read theREADYcolumn and theReadycondition; a crash-looping container lives in aRunningPod. - Confusing restart with replacement. The kubelet restarts containers in place; controllers replace Pods. A Pod is never rescheduled to another node.
- Expecting a readiness failure to restart the container. It only removes the Pod from Service endpoints. Only liveness and startup failures restart.
- Expecting finished Pods to vanish.
SucceededandFailedPods persist until their controller, a TTL or PodGC (default threshold 12,500) removes them. - Reading exit code 137 as an application bug. It is
128 + 9: the process was SIGKILLed, usually by the OOM killer or a grace-period expiry. - Treating
--forcedeletion as safe. It deletes the API object without waiting for the process to stop; dangerous for StatefulSets.
Frequently Asked Questions
What are the five Pod phases in Kubernetes?
Pending, Running, Succeeded, Failed and Unknown. Pending includes scheduling and image-pull time; Running means all containers are created and at least one is running or restarting; Succeeded and Failed are terminal; Unknown means the node is not reporting.
Is CrashLoopBackOff a Pod phase?
No. It is the reason on a container’s Waiting state while the kubelet waits out the restart backoff, and kubectl promotes it to the STATUS column. The Pod’s phase during a crash loop is Running.
What is the difference between Pending and ContainerCreating?
Both are Pending-phase Pods. Plain Pending usually means the Pod has not been scheduled yet; ContainerCreating is the container’s Waiting reason once the kubelet has started pulling the image and setting up the sandbox.
Why does a Pod show Running but 0/1 READY?
Its readiness probe is failing, or the container has not passed its first readiness check. The Ready and ContainersReady conditions are False with reason ContainersNotReady, and the Pod’s IP is excluded from Service endpoints. No restart happens; that is the readiness probe’s defining behaviour.
How long does Kubernetes wait between container restarts?
The kubelet uses exponential backoff starting at 10 seconds, doubling each time, capped at 300 seconds. The timer resets after the container runs for 10 minutes without failing. Since v1.35 administrators can lower the cap per node with crashLoopBackOff.maxContainerRestartPeriod.
Which restartPolicy values can a Deployment use?
Only Always. OnFailure and Never are for Jobs, CronJobs and bare Pods, where a terminal phase is the expected end of the work.
What happens when I delete a Pod?
The API server records a 30-second deadline by default and the Pod shows Terminating. The kubelet runs any preStop hooks, sends SIGTERM to each container, and the control plane removes the Pod from EndpointSlices. When the grace period expires, remaining processes get SIGKILL, the Pod moves to a terminal phase and the API object is deleted.
Who deletes Completed Pods?
Usually the controller that created them (for Jobs, on Job deletion or when ttlSecondsAfterFinished expires). The PodGC controller only deletes terminated Pods when the cluster-wide count exceeds terminated-pod-gc-threshold, which defaults to 12,500, though it always cleans up orphan Pods on deleted nodes.
Conclusion
A Pod’s status is three layers: a coarse phase with exactly five values, a list of conditions that act as lifecycle checkpoints, and per-container state and lastState with the exit codes that explain what happened. kubectl get pods compresses all of it into one STATUS word, and most status confusion comes from mistaking that word for a phase. Know that ImagePullBackOff is Pending and CrashLoopBackOff is Running; that readiness failures remove endpoints while liveness failures restart containers; that the kubelet restarts containers in place with a 10 s to 5 min backoff while controllers replace Pods; that deletion is a 30-second negotiation ending in SIGKILL; and that finished Pods wait for their owner, a TTL or a 12,500-Pod threshold before disappearing. With that model, every kubectl get pods line becomes a sentence you can read rather than a word you have to look up.
If you want to test whether the model holds under exam pressure, Sailor.sh’s KCNA Certification-Ready Mock Exam Bundle includes Pod lifecycle, status interpretation and troubleshooting questions across five timed mock exams with explanations that spell out why each distractor is wrong, so the phase-versus-status trap is one you fall into in practice rather than on the day. Pair it with the KCNA exam guide, the KCNA study guide and the free KCNA practice questions.
Continue with the workloads and controllers guide for who creates and replaces Pods, the scheduling and resource management guide for why a Pod stays Pending, and the Services and networking guide for what the Ready condition means to a Service.