Troubleshooting Kubernetes: Pod Status, Events, Logs, and Probes
Troubleshooting Kubernetes follows one repeatable sequence: check state with kubectl get, find the reason with kubectl describe and its Events section, read what the application said with kubectl logs, and look inside a running container with kubectl exec. Almost every diagnosis on the KCNA exam maps a visible symptom - a Pod stuck in Pending, an ImagePullBackOff, a CrashLoopBackOff, a Service that returns no responses - to one of those commands and one underlying cause. The exam does not ask you to fix a live cluster; it asks you to recognize what a status means, which command reveals the next clue, and what a failing liveness, readiness, or startup probe does to a Pod. This lesson walks through the Pod phases, the common waiting reasons and how to tell them apart, the diagnostic commands and their key flags, probe behavior, and the failure modes of Services and nodes, ending with a worked scenario that ties the sequence together.
On this page8 sections
- The four commands that solve most problems
- Pod phases: the five states of a Pod
- Decoding waiting reasons: image problems versus crash loops
- kubectl describe and the Events section
- Reading logs and getting inside a container
- Probes: liveness, readiness, and startup
- When the Pod is fine: Services with no endpoints and unhealthy nodes
- A worked scenario: from symptom to root cause
- Name the five Pod phases and explain what each one indicates
- Distinguish ImagePullBackOff, ErrImagePull, ErrImageNeverPull, CrashLoopBackOff, and OOMKilled and identify the cause of each
- Choose the right diagnostic command - kubectl get, describe, logs, or exec - for a given symptom
- Read the Events section of kubectl describe and interpret common event reasons
- Explain what happens when a liveness, readiness, or startup probe fails
- Recognize why a Service has no endpoints and what a NotReady node means
The four commands that solve most problems
Kubernetes troubleshooting is not guesswork; it is a fixed escalation path through four commands, each answering one question. kubectl get answers what state things are in: it lists objects with their status columns, so you can spot a Pod that is Pending, a Deployment showing 2/3 ready replicas, or a node that is NotReady. kubectl describe answers why: it prints the full object detail and, crucially, ends with the Events section, where the scheduler, the kubelet, and controllers record what they tried and why it failed. kubectl logs answers what the application itself said: the stdout and stderr of a container, which is where crashes, stack traces, and configuration errors show up. kubectl exec answers what it looks like from inside: it runs a command in a running container so you can inspect files, environment variables, or connectivity.
The KCNA exam tests this mapping directly. A question describes a symptom and asks which command you would run first, so anchor the pairs now.
| Symptom | First command | What it reveals |
|---|---|---|
| Pod stuck in Pending | kubectl describe pod | Scheduling events such as insufficient CPU or memory |
| Pod in CrashLoopBackOff | kubectl logs with --previous | Why the last container instance exited |
| Image will not pull | kubectl describe pod | Pull events: bad name, bad tag, missing registry credentials |
| App runs but misbehaves | kubectl logs, then kubectl exec | Application errors, then live inspection inside the container |
| Service returns nothing | kubectl describe service and kubectl get endpoints | Whether any Pods back the Service |
| Many Pods failing on one node | kubectl get nodes, then kubectl describe node | Node conditions such as NotReady or resource pressure |
Everything in the rest of this lesson hangs off this table: the phases and reasons you will see in kubectl get output, and the events and log patterns that explain them.
Pod phases: the five states of a Pod
Every Pod has a phase, a single high-level summary of where it is in its lifecycle. There are exactly five, and the exam expects you to know all of them.
| Phase | Meaning | Typical situation |
|---|---|---|
| Pending | Accepted by the cluster, but at least one container is not yet running | Waiting for scheduling, or pulling images |
| Running | Bound to a node; all containers created, at least one running or starting | Normal operation |
| Succeeded | All containers exited with success and will not restart | A completed Job Pod |
| Failed | All containers terminated and at least one exited with failure | A Job Pod whose process returned a non-zero exit code |
| Unknown | The Pod state cannot be obtained | The node running it stopped reporting to the API server |
Two clarifications keep you out of trap answers. First, Pending does not mean broken: a Pod is Pending for a moment on every normal start while the scheduler picks a node and the kubelet pulls images. It only signals a problem when it persists, most often because no node has enough free CPU or memory, which shows up as a FailedScheduling event. Second, the STATUS column of kubectl get pods is not the phase. That column shows a more specific reason when one exists: a Pod in phase Pending may display ContainerCreating or ImagePullBackOff, and a Pod in phase Running may display CrashLoopBackOff because its container keeps restarting. Succeeded and Failed apply to run-to-completion workloads; a long-running server that dies does not move to Failed, its container is simply restarted inside the still-Running Pod.
So read kubectl get pods output as symptom, phase as lifecycle stage, and kubectl describe as the explanation.
Decoding waiting reasons: image problems versus crash loops
The reasons in the STATUS column split into two families that the exam loves to contrast: the container image cannot be obtained, or the container runs and then dies.
ErrImagePull means the kubelet just tried to pull the image and failed: the image name is misspelled, the tag does not exist, or the registry is private and the Pod has no valid image pull credentials. After repeated failures the kubelet backs off between retries and the status becomes ImagePullBackOff - same root cause, now with an increasing delay between attempts. ErrImageNeverPull is the odd sibling: the Pod's image pull policy is set to Never, the image is not already present on the node, and the kubelet is forbidden from fetching it. ContainerCreating is not an error at all, just the normal setup step; it only matters when a Pod is stuck there, which usually points at a volume that cannot be mounted or attached, visible as FailedMount events.
CrashLoopBackOff is the other family entirely. The image pulled fine and the container started, but it exited, was restarted by the kubelet, exited again, and Kubernetes is now waiting an exponentially increasing backoff before the next restart. The cause lives inside the container: a bad configuration value, a missing dependency, a failing database connection, or a command that finishes immediately in a Pod meant to run forever. OOMKilled is a specific terminal reason: the container exceeded its memory limit and the kernel killed it, classically with exit code 137; if it keeps happening, it becomes a crash loop too.
| Reason | Did the image pull? | Did the container start? | Where to look |
|---|---|---|---|
| ErrImagePull / ImagePullBackOff | No | No | Events from kubectl describe; check image name, tag, registry credentials |
| ErrImageNeverPull | Not allowed to | No | Image pull policy Never and image absent on the node |
| CrashLoopBackOff | Yes | Yes, then exited repeatedly | kubectl logs --previous for the last exit |
| OOMKilled | Yes | Yes, killed for exceeding memory limit | Last state in kubectl describe; raise the limit or fix the leak |
kubectl describe and the Events section
kubectl describe pod checkout-7d9f prints everything the cluster knows about the Pod: its node, labels, IP, each container's state and last state with exit codes, its restart count, mounted volumes, and conditions. For troubleshooting, the payoff is the Events section at the bottom. Events are timestamped records emitted by the components that acted on the object - the scheduler saying where and whether it could place the Pod, the kubelet reporting image pulls, container starts, probe failures, and restarts.
A handful of event reasons cover most exam scenarios. FailedScheduling means the scheduler found no suitable node, and the message says why, typically insufficient CPU or insufficient memory on every candidate node. Failed or BackOff pull events accompany image problems and include the registry error message. FailedMount means a volume could not be attached or mounted, which is the classic cause of a Pod stuck in ContainerCreating. Unhealthy means a liveness or readiness probe failed, with the probe's error in the message. Killing follows repeated liveness failures, as the kubelet restarts the container.
Events are not only visible per object. kubectl get events lists them for a namespace, and sorting by creation time reconstructs the order in which things went wrong - useful when several objects are involved. Two properties matter for the exam: events are namespaced, and they are short-lived, retained for about an hour by default, so they explain recent history, not last week's incident. When a question says a Pod is Pending, or stuck creating, or being restarted and asks where to find the reason, the answer is the Events section of kubectl describe.
Reading logs and getting inside a container
kubectl logs checkout-7d9f streams the stdout and stderr of a Pod's container - which is precisely why the cloud native convention is that applications log to stdout instead of files. This is where application-level failures live: unhandled exceptions, refused database connections, missing environment variables, bad flags. Two flags carry most of the diagnostic weight. If the Pod has multiple containers, you must pick one with -c, as in kubectl logs checkout-7d9f -c payment-sidecar; without it, kubectl targets the single container or the default one. And for a crash-looping container the current instance may have produced nothing yet, so kubectl logs checkout-7d9f --previous shows the output of the previous, terminated instance - the one that actually crashed. That flag is the canonical answer to how do you see why a container in CrashLoopBackOff died. Add -f to follow logs live, and -l app=checkout to aggregate logs across Pods matching a label selector.
When logs are not enough, kubectl exec opens a live view: kubectl exec -it checkout-7d9f -- sh starts an interactive shell inside the running container (again, -c selects a container in a multi-container Pod). From there you can check whether a config file was mounted, print environment variables, or test whether the container can resolve and reach a dependency. Its limits define when it applies: exec requires a running container, so it cannot help with a Pod that never starts, and minimal images may lack a shell entirely.
Keep the division of labor straight: describe tells you what Kubernetes did to the container, logs tell you what the process did inside it, and exec lets you poke around while it runs.
Probes: liveness, readiness, and startup
The kubelet uses three kinds of health probes, and the exam's favorite question is what happens when each one fails. A liveness probe asks: is this container still functioning, or is it wedged? When a liveness probe fails repeatedly, the kubelet kills and restarts the container. A readiness probe asks: can this container serve traffic right now? When a readiness probe fails, the Pod is marked not ready and is removed from the endpoints of every Service that selects it - traffic stops flowing to it, but the container is not restarted. When the probe passes again, the Pod is added back. A startup probe exists for slow-starting applications: while it is running, the other two probes are suspended, so a legacy app that needs two minutes to boot is not killed by an impatient liveness probe; only if the startup probe exhausts its failure budget is the container restarted.
| Probe | Question it answers | On failure |
|---|---|---|
| Liveness | Is the container alive? | Container is restarted |
| Readiness | Can it accept traffic now? | Pod removed from Service endpoints; no restart |
| Startup | Has it finished booting? | Other probes held off; restart only if it never passes |
All three run the same mechanisms - an HTTP GET, a TCP connection attempt, an exec command graded by exit code, or a gRPC health check - so the difference is purely in the consequence. Probe failures surface as Unhealthy events in kubectl describe, and a rising restart count with liveness failures in the events is a hint that an overly aggressive liveness probe, not the application, may be the real problem. The distinction to burn in: liveness restarts, readiness gates traffic.
When the Pod is fine: Services with no endpoints and unhealthy nodes
Sometimes every Pod shows Running and the application still is not reachable. The next suspect is the Service. A Service forwards traffic only to Pods that match its label selector and are ready. If the selector does not match the Pods' labels - a typo like app: chekout, or labels changed in a new Deployment revision - the Service has no endpoints, and connections to it go nowhere. The same empty-endpoints symptom appears when the Pods exist but their readiness probes are failing. The check is direct: kubectl describe service checkout shows the selector and the current endpoints, and kubectl get endpoints checkout lists the backing addresses; an empty list is the tell. A subtler variant is a port mismatch, where the Service's target port does not match the port the container actually listens on - endpoints exist, but connections are refused.
The other above-Pod failure domain is the node. kubectl get nodes shows each node's status; NotReady means the node's kubelet has stopped reporting healthy to the control plane - the machine may be down, the kubelet stopped, or its network severed. Pods on a NotReady node cannot be managed, may show phase Unknown, and after a timeout are scheduled for replacement elsewhere by their controllers. kubectl describe node shows the node's conditions, including the pressure signals: MemoryPressure, DiskPressure, and PIDPressure. Under resource pressure the kubelet may evict Pods to protect the node, and the scheduler avoids placing new ones there. With the metrics server installed, kubectl top nodes and kubectl top pods show live CPU and memory usage, which is how you confirm a pressure or capacity theory with numbers.
A worked scenario: from symptom to root cause
Put the sequence together on a realistic case. A team ships a new version of the checkout service. Minutes later, users report errors. You run kubectl get pods and see the new Pods: one shows ImagePullBackOff, two show Running but with 0/1 in the READY column, and one older Pod is still Running and ready.
Take the image problem first. kubectl describe pod on the ImagePullBackOff Pod shows pull events failing with an authentication error against the private registry - the new Pod spec dropped the image pull secret. That is a spec fix, not an application fix. Next, the running-but-not-ready Pods: describe shows repeating Unhealthy events from the readiness probe, and because readiness gates traffic, those Pods have been removed from the Service's endpoints - which you confirm with kubectl get endpoints checkout, showing only the one old Pod. The readiness failures explain the user-facing errors: nearly all capacity is out of rotation. Why is readiness failing? kubectl logs on one of the new Pods prints a stack trace: the app cannot connect to the payments database because a required environment variable is empty in the new release. No amount of restarting will fix that; the Deployment needs its configuration corrected or the rollout rolled back.
Notice what made this fast: get surfaced three distinct symptoms, describe attributed each to a component action, endpoints confirmed the traffic impact, and logs found the application cause. No step was clever; each command answered exactly its own question. That chain - and knowing which link a question is pointing at - is the whole troubleshooting competency KCNA measures.
Tip. KCNA tests troubleshooting as symptom-to-cause recognition: expect questions that show a Pod status like ImagePullBackOff, CrashLoopBackOff, or a persistent Pending and ask what it means or which command to run next. Trigger words include Events section, kubectl describe, kubectl logs --previous, no endpoints, and NotReady. Probe questions hinge on one distinction: liveness failures restart the container, readiness failures only remove the Pod from Service endpoints. You will not be asked to fix a cluster, only to match statuses, commands, and probe behaviors to the situations they diagnose.
- The five Pod phases are Pending, Running, Succeeded, Failed, and Unknown; the STATUS column of kubectl get pods shows more specific reasons like CrashLoopBackOff.
- ImagePullBackOff means the image cannot be pulled (bad name, tag, or credentials); CrashLoopBackOff means the image ran but the container keeps exiting.
- OOMKilled means the container exceeded its memory limit and was killed, classically with exit code 137.
- kubectl describe ends with the Events section, where scheduling failures (FailedScheduling), mount failures (FailedMount), and probe failures (Unhealthy) are recorded.
- kubectl logs --previous shows output from the last terminated container instance, the key to diagnosing a crash loop; -c selects a container in multi-container Pods.
- A failing liveness probe restarts the container; a failing readiness probe only removes the Pod from Service endpoints; a startup probe delays both for slow-booting apps.
- A Service with no endpoints usually means its label selector matches no Pods or the matching Pods are not ready.
- A NotReady node means the kubelet stopped reporting healthy; describe node shows MemoryPressure, DiskPressure, and PIDPressure conditions.
Frequently asked questions
What is the difference between ImagePullBackOff and CrashLoopBackOff?
ImagePullBackOff means Kubernetes cannot obtain the container image at all, usually because the image name or tag is wrong or the registry requires credentials the Pod does not have; the container never starts. CrashLoopBackOff means the image pulled successfully and the container started, but it keeps exiting, so the kubelet restarts it with an increasing backoff delay. The first is fixed in the Pod spec or registry access; the second is diagnosed with kubectl logs --previous to see why the process died.
How do I see the logs of a crashed container in Kubernetes?
Run kubectl logs with the --previous flag, for example kubectl logs my-pod --previous. This prints the stdout and stderr of the last terminated instance of the container rather than the current one, which may have just restarted and logged nothing yet. If the Pod has more than one container, add -c with the container name to choose which container's logs to read.
What happens when a readiness probe fails in Kubernetes?
The Pod is marked not ready and is removed from the endpoints of every Service that selects it, so it stops receiving traffic. The container is not restarted; readiness failures only gate traffic. Once the probe starts passing again, the Pod is added back to the Service endpoints automatically. Restarting on failure is the behavior of the liveness probe, not the readiness probe.
Why is my Kubernetes Pod stuck in Pending?
Pending means the Pod has been accepted but its containers are not running yet, and when it persists the usual cause is that the scheduler cannot find a node with enough free CPU or memory, or with the required placement constraints. Run kubectl describe on the Pod and read the Events section: a FailedScheduling event states exactly why every node was rejected. Pods can also sit in Pending while waiting on storage that cannot be provisioned or attached.
Why does my Kubernetes Service have no endpoints?
A Service only forwards to Pods that match its label selector and pass their readiness probes. No endpoints means either the selector does not match any Pod's labels, often due to a typo or a label change in a new rollout, or the matching Pods exist but are failing readiness. Compare the selector shown by kubectl describe service with the Pods' labels, and check kubectl get endpoints for the Service to confirm whether any addresses are behind it.
What does a NotReady node status mean?
NotReady means the node's kubelet has stopped reporting a healthy status to the control plane, so the cluster cannot manage Pods on that node. Causes include the machine being down, the kubelet process failing, or network loss between the node and the API server. Pods on the node may show phase Unknown, and workload controllers will eventually replace them on healthy nodes. Use kubectl describe node to inspect the node's conditions and recent events.
Sign up free to mark lessons complete, bookmark topics and track your exam readiness.