Kubernetes Pod Debug Cheat Sheet
When a pod won’t come up in production, every second counts. This cheat sheet turns pod autopsies into a repeatable system: 3 starting commands, 6 failure modes with their exact fixes, and a 6-step debug order that cuts incident time in half.
kubectl get pod <pod> -n <ns> kubectl describe pod <pod> -n <ns> kubectl logs <pod> -n <ns> -c <container> --previous
- 1Status
- 2Events
- 3Last State
- 4Exit Code
- 5Restarts
- 6Logs
-c <container> for multi-container pods — otherwise you may be reading the wrong container's logs.kubectl describe pod <pod> -n <ns>kubectl get nodeskubectl get pvc -n <ns>
- FailedScheduling
- Insufficient cpu / memory
- taints / tolerations mismatch
- nodeSelector / affinity mismatch
- quota exceeded
- PVC Pending or not bound
- storage class mismatch
- Lower requests
- Add capacity
- Fix taints / tolerations
- Update quota
- Bind storage
kubectl logs <pod> -n <ns> -c <container> --previouskubectl describe pod <pod> -n <ns>
- Exit Code 1 → app / config failure
- Exit Code 137 → OOMKilled
- Exit Code 126 → not executable
- Exit Code 127 → command not found
- missing env var
- bad startup command
- failed dependency
- Read previous logs
- Confirm Last State / Reason
- Map the exit code
- Fix app, config, command, or dependency
kubectl describe pod <pod> -n <ns>kubectl top pod <pod> -n <ns>kubectl get pod <pod> -n <ns> -o jsonpath='{.spec.containers[*].resources}'
- Reason: OOMKilled
- Exit Code 137
- memory limit too low
- sudden memory spike
- restarts after traffic bursts
- Increase limits
- Set realistic requests
- Profile memory usage
- Fix the memory leak
kubectl top requires Metrics Server to be installed.kubectl get pod <pod> -n <ns> -o jsonpath='{.status.initContainerStatuses}'kubectl logs <pod> -n <ns> -c <init-container>
- DB migration failure
- dependency unavailable
- missing secret
- permission issue
- DNS failure
- bad wait logic
- Fix dependency
- Verify secret and DB connectivity
- Fix migration script
- Fix DNS or wait condition
kubectl describe pod <pod> -n <ns>kubectl describe serviceaccount <sa> -n <ns>
- manifest unknown
- repository does not exist
- pull access denied
- authentication required
- wrong image tag
- wrong registry URL
- missing imagePullSecret
- Fix image name and tag
- Verify registry auth
- Add imagePullSecret
- Fix registry permissions
- Verify serviceAccount reference
kubectl describe pod <pod> -n <ns>kubectl get cm -n <ns>kubectl get secret -n <ns>kubectl get pvc -n <ns>
- missing ConfigMap
- missing Secret
- invalid env reference
- invalid volume mount
- permission denied
- PVC Pending or unbound
- read-only filesystem
- mount path conflict
- Fix config references
- Verify secrets and PVCs
- Fix mounts and permissions
- Investigate container runtime error
# Attach debug container to existing pod kubectl debug -it <pod> -n <ns> \ --image=nicolaka/netshoot --target=<container> # Spin up a one-shot network debug pod kubectl run netshoot -it --rm \ --image=nicolaka/netshoot \ --restart=Never -- sh
Common Mistakes
Misreading exit codes: Exit Code 137 is not always OOMKilled — it can also mean SIGKILL (signal 9). Always check the Reason field in kubectl describe for the authoritative answer.
Skipping --previous on logs: After a pod restarts, the current log is empty. For crash-time logs you must always add --previous.
Fixating on one container: When an init container fails, the main container never starts. Check initContainerStatuses in kubectl get pod -o yaml before assuming the main container is at fault.
Confusing requests and limits: The scheduler uses requests to place pods; the OOM killer uses limits. They are independent — inspect both separately when debugging resource-related failures.