When a pod won’t start, or keeps restarting, Kubernetes usually tells you why, if you know where to look. The status column (CrashLoopBackOff, Pending, ImagePullBackOff, OOMKilled) points to the category of problem, and kubectl describe plus logs usually give the exact cause.
The three commands to start with
kubectl get pods -o wide # status, restarts, node
kubectl describe pod <pod> # events at the bottom: the most useful part
kubectl logs <pod> [-c <container>] --previous # logs of the last crashed instance
Cluster-wide recent events:
kubectl get events -A --sort-by=.lastTimestamp | tail -30
Common statuses and fixes
Pending
The pod can’t be scheduled. describe shows why:
| Event message | Fix |
|---|---|
Insufficient cpu / Insufficient memory |
Lower requests, or add node capacity |
didn't match node selector/affinity |
Fix nodeSelector/affinity, or label nodes |
had untolerated taint |
Add a toleration, or remove the taint |
pod has unbound PersistentVolumeClaims |
StorageClass/provisioner missing. See persistent volumes |
ImagePullBackOff / ErrImagePull
- Typo in the image name or tag, or the tag doesn’t exist.
- Private registry without an
imagePullSecret. - Registry rate limits. See Docker Hub rate limits.
- Wrong architecture (
exec format errorhappens later, at runtime). See multi-arch images.
kubectl create secret docker-registry regcred --docker-server=registry.example.com --docker-username=u --docker-password=token
CrashLoopBackOff
The container starts and exits repeatedly. Kubernetes waits longer between restarts (backoff).
kubectl logs <pod> --previous: the app’s own error (missing config, bad credentials, can’t reach the database).kubectl describe pod: Exit Code in “Last State”:
| Exit code | Meaning |
|---|---|
| 1 / other | Application error. Read the logs |
| 137 | Killed (SIGKILL), often OOMKilled (check “Reason”) |
| 139 | Segmentation fault |
| 143 | Terminated (SIGTERM), e.g. a failed liveness probe |
- Missing ConfigMap or Secret keys show as
CreateContainerConfigError. See ConfigMaps and Secrets.
OOMKilled
The container exceeded its memory limit. Raise the limit (and request), or fix the leak. For JVM, Node and similar runtimes, set heap sizes below the container limit. See Linux cgroups.
Running but not receiving traffic
- Readiness probe failing:
describeshows “Readiness probe failed”. The pod is excluded from the Service. - Service selector doesn’t match pod labels:
kubectl get endpoints web # empty = no ready pods match the selector
kubectl get pods --show-labels
See Kubernetes deployments and services and Kubernetes ingress.
Get inside
kubectl exec -it <pod> -- sh
kubectl port-forward pod/<pod> 8080:8080
For minimal images without a shell (distroless), attach an ephemeral debug container:
kubectl debug -it <pod> --image=busybox:1.36 --target=<container>
kubectl debug node/<node> -it --image=ubuntu # debug a node
Make a copy of a crashing pod with a different command, so you can inspect it:
kubectl debug <pod> -it --copy-to=debug-pod --container=app -- sh
Node-level problems
kubectl get nodes
kubectl describe node <node> # pressure conditions: MemoryPressure, DiskPressure
DiskPressure (a full disk, often from images or logs) causes evictions. Clean up on the node (crictl rmi --prune), and check log rotation. See disk full troubleshooting.
Tools that help
- k9s: a terminal UI to browse pods, logs and events quickly. See k9s.
- stern: tail logs from many pods at once (
stern web).
Quick reference
| Status | First check |
|---|---|
| Pending | describe → scheduling events |
| ImagePullBackOff | Image name, tag, pull secret |
| CrashLoopBackOff | logs --previous, exit code |
| OOMKilled | Memory limit vs usage |
| Running, no traffic | Readiness probe, get endpoints |
| No shell in image | kubectl debug --target |
Related: kubectl cheat sheet and Linux troubleshooting methodology.