kubectl Debug
Troubleshoot running and crashed pods without modifying deployments.
Time: ~10 minutes Difficulty: Intermediate
What You Will Learn
Section titled “What You Will Learn”kubectl debug: attach a debug container to a running or crashed pod- Ephemeral containers: debug without rebuilding images
- Debugging CrashLoopBackOff pods
- Debugging distroless/minimal images that have no shell
- Node-level debugging
- Common troubleshooting workflows
Deploy
Section titled “Deploy”Navigate to the demo directory:
cd demos/kubectl-debugkubectl apply -f manifests/namespace.yamlkubectl apply -f manifests/crashing-pod.yamlkubectl apply -f manifests/distroless-app.yamlkubectl apply -f manifests/running-app.yamlScenario 1: Debug a CrashLoopBackOff Pod
Section titled “Scenario 1: Debug a CrashLoopBackOff Pod”kubectl get pods -n debug-demo# crash-loop is in CrashLoopBackOffCheck logs first:
kubectl logs crash-loop -n debug-demo# ERROR: Config file not found!You cannot exec into a crashed container. Use kubectl debug to create a copy with a different command:
kubectl debug crash-loop -n debug-demo -it \ --copy-to=crash-debug \ --container=app \ -- /bin/shInside the debug copy, investigate:
# Check what files existls /config/# Directory doesn't exist - that's the problem
# Check env vars, mounts, etc.envmountexitClean up the debug pod:
kubectl delete pod crash-debug -n debug-demoScenario 2: Debug a Distroless Container
Section titled “Scenario 2: Debug a Distroless Container”The distroless-app uses the pause image, which has no shell and no tools:
# This fails - no shell availablekubectl exec -it deploy/distroless-app -n debug-demo -- /bin/shAdd an ephemeral debug container that shares the process namespace:
kubectl debug -it deploy/distroless-app -n debug-demo \ --image=busybox:1.36 \ --target=appInside the debug container, you can see the target container’s processes:
ps aux# You can see the pause process from the app container
# Check the networkwget -qO- http://localhost:80 2>&1 || echo "No web server (expected for pause)"
# Check filesystemls /proc/1/root/exitScenario 3: Debug a Running Pod
Section titled “Scenario 3: Debug a Running Pod”Add a debug container to a running nginx pod:
POD=$(kubectl get pod -l app=web-app -n debug-demo -o jsonpath='{.items[0].metadata.name}')
kubectl debug -it "$POD" -n debug-demo \ --image=curlimages/curl \ --target=nginx \ -- /bin/shInside the debug container:
# Test the app from inside the podcurl localhost:80
# Check DNS resolutionnslookup web-app.debug-demo.svc.cluster.local
# Check network connectivitycurl -s http://web-app.debug-demo.svc/
exitScenario 4: Debug at the Node Level
Section titled “Scenario 4: Debug at the Node Level”kubectl debug node/minikube -it --image=busybox:1.36Inside the node debug pod, the host filesystem is at /host:
# Check host processeschroot /host ps aux | head -20
# Check host disk usagechroot /host df -h
# Check kubelet logschroot /host journalctl -u kubelet --no-pager | tail -20
exitCommon Troubleshooting Checklist
Section titled “Common Troubleshooting Checklist”# 1. Check pod statuskubectl get pods -n debug-demo
# 2. Check eventskubectl describe pod <pod-name> -n debug-demo
# 3. Check logs (current and previous)kubectl logs <pod-name> -n debug-demokubectl logs <pod-name> -n debug-demo --previous
# 4. Check resource usagekubectl top pods -n debug-demo
# 5. Check endpoints (is the Service routing correctly?)kubectl get endpoints web-app -n debug-demo
# 6. Test DNS from inside the clusterkubectl run dns-test --rm -it --image=busybox:1.36 -n debug-demo -- nslookup web-appWhat is Happening
Section titled “What is Happening”manifests/ namespace.yaml # debug-demo namespace crashing-pod.yaml # Pod that crashes (missing config file) distroless-app.yaml # Minimal image with no shell running-app.yaml # Normal nginx app for testingkubectl debug modes:
| Mode | Flag | Use Case |
|---|---|---|
| Copy pod | --copy-to=name | Debug crashed containers by creating a copy |
| Ephemeral container | (default) | Add a debug container to a running pod |
| Node debug | node/<name> | Debug at the node level with host access |
Cleanup
Section titled “Cleanup”kubectl delete namespace debug-demo
# If you ran the node debug scenario, clean up the debug pod in default namespacekubectl get pods --field-selector=status.phase=Running -o name | grep node-debugger | xargs -r kubectl deleteFurther Reading
Section titled “Further Reading”See docs/deep-dive.md for a detailed explanation of ephemeral containers, process namespace sharing, debug profiles, and advanced troubleshooting patterns.
Next Step
Section titled “Next Step”Move on to Multi-Container to learn sidecar, adapter, and ambassador patterns.