Sooner or later every Kubernetes user stares at a pod stuck in CrashLoopBackOff, ImagePullBackOff, or Pending and wonders where to even begin. The good news: these three states cover a large share of everyday failures, and each has a short, repeatable diagnostic path.
The trick is to stop guessing and let Kubernetes tell you what's wrong. It almost always will — if you ask the right command.
The two commands you'll use constantly
kubectl get pods
kubectl describe pod <pod-name>describe is the underrated one. Scroll to the Events section at the bottom — scheduler decisions, image pulls, probe failures, and restarts are all recorded there in plain language.
Pending: the pod hasn't been placed anywhere
Pending means the pod was accepted but isn't running yet. Most often the scheduler can't find a node that fits.
kubectl describe pod <pod-name>
# Look for events like:
# 0/3 nodes are available: 3 Insufficient cpu.Common causes and what to check:
- Insufficient CPU or memory. The pod's resource
requestsexceed what any node has free. Lower the requests, add capacity, or fix an accidentally huge value (memory: 16Giinstead of16Miis a classic). - Node selectors, affinity, or taints. The pod demands a node label that doesn't exist, or nodes carry a taint the pod doesn't tolerate. Compare the pod spec against
kubectl get nodes --show-labelsandkubectl describe node. - Unbound PersistentVolumeClaim. The pod is waiting for storage. Run
kubectl get pvcand check whether a matching volume or StorageClass exists. Our storage post covers this in depth.
ImagePullBackOff and ErrImagePull: the image can't be fetched
The node tried to pull the container image and failed, then backs off and retries with increasing delays.
kubectl describe pod <pod-name>
# Events often show: Failed to pull image "myapp:1.2" ... not found
# or: pull access denied / unauthorizedCheck, in this order:
- Typos. Wrong image name, wrong tag, wrong registry host. It's embarrassingly often this.
- The tag really exists. Confirm in the registry. A tag that was never pushed — or a CI job that failed before pushing — looks identical to a typo.
- Authentication. Private registries need an image pull secret referenced by the pod or its service account.
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=<user> \
--docker-password=<token>spec:
imagePullSecrets:
- name: regcred- Network access. Can the node actually reach the registry? Firewalls, proxies, and missing NAT routes show up here.
CrashLoopBackOff: the container starts, then dies, repeatedly
This one means Kubernetes keeps restarting a container that keeps exiting. The pod is scheduled and the image pulled, so the problem is inside the container — or in how it's being checked.
kubectl logs <pod-name>
kubectl logs <pod-name> --previous # logs from the last crashed instance
kubectl describe pod <pod-name> # look at Last State and Exit CodeThe --previous flag is the one people forget. The current container may have just restarted and have no logs yet, while the instance that crashed has the answer.
Read the exit code in describe:
| Exit code | Usual meaning |
|---|---|
| 1 | Application error — check the logs |
| 137 | Killed, commonly out-of-memory (OOMKilled) or forcibly terminated |
| 139 | Segmentation fault |
| 143 | Terminated by SIGTERM |
Frequent root causes:
- The app crashes on startup — missing configuration, a bad environment variable, an unreachable dependency. See our post on ConfigMaps, Secrets, and environment configuration.
- OOMKilled. The container exceeded its memory limit. Raise the limit or fix the leak.
- A failing liveness probe that kills a perfectly healthy but slow-starting app. If the app needs time to boot, use a startup probe or a longer initial delay.
- The wrong command or entrypoint, so the process exits immediately with success. A container whose main process finishes is, to Kubernetes, a container that stopped.
A debugging toolkit worth knowing
# Run a throwaway pod to test connectivity from inside the cluster
kubectl run tmp --rm -it --image=busybox -- sh
# Open a shell in a running container
kubectl exec -it <pod-name> -- sh
# Recent cluster events, newest last
kubectl get events --sort-by=.lastTimestamp
# Attach an ephemeral debug container to a running pod
kubectl debug -it <pod-name> --image=busybox --target=<container-name>The habit that saves the most time
Change one thing at a time and re-check. The fastest way to turn a ten-minute problem into a two-hour one is to alter the image, the config, and the resource limits all at once and then wonder which one mattered.
Practice beats reading
Troubleshooting is a skill built by breaking things on purpose and fixing them under mild pressure — which is exactly how the practical Certified Kubernetes Administrator exam tests it. If you're getting started, begin with Kubernetes 101: Pods, Deployments, and Services, and for a guided, hands-on path see our Kubernetes and DevOps in Practice course.
