| name | k8s-debug |
| description | Debug Kubernetes issues: CrashLoopBackOff, OOMKilled, ImagePullBackOff, pending pods, networking, and resource limits using kubectl. Trigger: when debugging Kubernetes pods, troubleshooting CrashLoopBackOff, OOMKilled pods, ImagePullBackOff errors, pending Kubernetes pods, K8s networking issues |
| version | 1 |
| argument-hint | [pod-name or issue: crashloop|oom|imagepull|pending|networking] |
| allowed-tools | ["bash","read","grep"] |
Kubernetes Debugging
You are now operating in Kubernetes debugging mode.
Standard Debug Workflow
When a pod is not working, follow these steps in order:
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
kubectl exec -it <pod-name> -n <namespace> -- sh
kubectl top pod <pod-name> -n <namespace>
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
CrashLoopBackOff
The container starts, crashes, and Kubernetes keeps restarting it.
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
kubectl describe pod <pod-name> -n <namespace> | grep -A5 "Last State:"
kubectl get pod <pod-name> -n <namespace> -o json | \
jq '.status.containerStatuses[0] | {restartCount, lastState}'
Common Causes:
- Application crashes on startup (missing env var, bad config, connection failure)
- Missing required secrets or ConfigMaps
- Database connection failures
- Incorrect entrypoint command in Dockerfile or pod spec
Resolution Steps:
- Read the
--previous logs first — they show why the container crashed
- Check environment variables are present:
kubectl exec ... -- env | grep MY_VAR
- Verify secrets/configmaps exist:
kubectl get secret my-secret -n <namespace>
- Test the database connection separately using port-forward
OOMKilled (Out of Memory)
The Linux OOM killer terminated the container because it exceeded its memory limit.
kubectl describe pod <pod-name> -n <namespace> | grep -A3 "Last State:"
kubectl describe pod <pod-name> -n <namespace> | grep -A6 "Limits:"
kubectl top pod <pod-name> -n <namespace>
kubectl get pods -n <namespace> -o json | \
jq '.items[] | select(.status.containerStatuses[0].lastState.terminated.reason == "OOMKilled") | .metadata.name'
kubectl top pods -n <namespace> --sort-by=memory
Resolution:
resources:
requests:
memory: 256Mi
limits:
memory: 512Mi
kubectl apply -f deployment.yaml
kubectl rollout status deployment/my-app -n <namespace>
If memory is legitimately high:
- Profile the application for memory leaks
- Check for unbounded caches or connection pools
- Consider using a larger node or VM class
ImagePullBackOff / ErrImagePull
Kubernetes cannot pull the container image.
kubectl describe pod <pod-name> -n <namespace> | grep -A10 "Events:"
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[0].image}'
docker manifest inspect myregistry/my-app:v2.0.0 2>&1
Resolution — Wrong Image Name/Tag:
kubectl set image deployment/my-app \
my-container=myregistry/my-app:v1.0.0 \
-n <namespace>
Resolution — Missing Registry Credentials:
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypass \
-n <namespace>
kubectl apply -f deployment.yaml
Resolution — Private Registry (ECR, GCR, ACR):
aws ecr get-login-password --region us-east-1 | \
kubectl create secret docker-registry ecr-cred \
--docker-server=<account>.dkr.ecr.us-east-1.amazonaws.com \
--docker-username=AWS \
--docker-password-stdin \
-n <namespace>
Pending Pods
Pods remain in Pending state, meaning Kubernetes cannot schedule them.
kubectl describe pod <pod-name> -n <namespace> | grep -A20 "Events:"
kubectl describe nodes | grep -A5 "Allocatable:"
kubectl describe nodes | grep -A8 "Allocated resources:"
kubectl get pvc -n <namespace>
kubectl describe pvc <pvc-name> -n <namespace>
Resolution — Insufficient Resources:
resources:
requests:
cpu: 50m
memory: 64Mi
Resolution — Node Affinity Mismatch:
kubectl get nodes --show-labels
Resolution — PVC Not Bound:
kubectl get pv
kubectl get storageclass
kubectl describe pvc <pvc-name> -n <namespace>
Networking Issues
kubectl exec <pod-name> -n <namespace> -- nslookup other-service
kubectl exec <pod-name> -n <namespace> -- nslookup other-service.other-namespace.svc.cluster.local
kubectl exec <pod-name> -n <namespace> -- curl -s http://my-service/health
SVC_IP=$(kubectl get svc my-service -n <namespace> -o jsonpath='{.spec.clusterIP}')
kubectl exec <pod-name> -n <namespace> -- curl -s http://$SVC_IP/health
kubectl get endpoints my-service -n <namespace>
kubectl describe svc my-service -n <namespace> | grep Selector:
kubectl get pods -n <namespace> --show-labels
kubectl get networkpolicies -n <namespace>
kubectl describe networkpolicy <policy-name> -n <namespace>
kubectl run debug-pod --image=nicolaka/netshoot --rm -it --restart=Never -n <namespace> -- sh
Config and Environment Issues
kubectl exec <pod-name> -n <namespace> -- env | sort
kubectl exec <pod-name> -n <namespace> -- printenv MY_VAR
kubectl describe secret my-secret -n <namespace>
kubectl get configmap my-config -n <namespace> -o yaml
kubectl describe pod <pod-name> -n <namespace> | grep -A10 "Mounts:"
kubectl describe pod <pod-name> -n <namespace> | grep -A10 "Volumes:"
Ephemeral Debug Containers
For pods without a shell or debugging tools:
kubectl debug -it <pod-name> -n <namespace> \
--image=busybox \
--target=my-container
kubectl debug -it <pod-name> -n <namespace> \
--image=nicolaka/netshoot \
--target=my-container
kubectl debug <pod-name> -n <namespace> \
--copy-to=debug-pod \
--container=my-container \
--image=busybox \
-it -- sh
Cluster-Level Diagnostics
kubectl get events -A --sort-by='.lastTimestamp' | tail -30
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
kubectl get events -n <namespace> --field-selector reason=OOMKilling
kubectl get events -n <namespace> --field-selector reason=BackOff
kubectl get nodes
kubectl describe node <node-name>
kubectl get pdb -n <namespace>
Quick Diagnostic Summary
kubectl get pods -A | grep -v Running | grep -v Completed | grep -v Terminating
kubectl get pods -n <namespace> -o json | \
jq '.items[] | {name: .metadata.name, restarts: .status.containerStatuses[0].restartCount}' | \
jq -s 'sort_by(.restarts) | reverse[]'
kubectl get events -n <namespace> \
--field-selector type=Warning \
--sort-by='.lastTimestamp' | tail -20
Safety Rules
- Never expose secret values in logs or
kubectl exec output. Use kubectl describe secret to check key names only.
- Use
kubectl exec with caution in production — commands run directly on live containers.
- Avoid
kubectl delete pod in production unless you intend to force a restart (the deployment will recreate it).
kubectl debug --copy-to creates a new pod; clean it up with kubectl delete pod debug-pod when done.
- Resource limit changes require a rolling restart — use
kubectl rollout status to verify the restart completes.
kubectl delete namespace is irreversible and removes all resources — confirm the namespace name before running.