Docker Debug Cheat Sheet
When the container won't start, won't stop, or won't behave, these commands tell you why. Skip the docs; type these.
List and filter
Start by knowing what's running, what crashed, and what's about to.
docker ps, running containersdocker ps -a, including stopped and exiteddocker ps -a --filter status=exited, only exited containersdocker ps --filter health=unhealthy, failing healthchecksdocker ps --filter "label=app=api", by labeldocker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}", clean table for your eyesdocker ps -q, IDs only; pipe into other commandsdocker ps --latest, last container created
Logs
The first stop. --since is the flag that turns 10,000-line logs into the 200 lines you actually need.
docker logs <container>, full logsdocker logs -f <container>, followdocker logs --tail 200 <container>, last 200 linesdocker logs --since 10m <container>, last 10 minutesdocker logs --until 2026-04-16T14:00:00 <container>, up to a timestampdocker logs --timestamps <container>, prepend wallclock to each linedocker logs <container> 2>&1 | grep -i error, both streams together (logs writes to stderr by default)
Exec into a container
Get a shell inside. Try bash first, fall back to sh, fall back further to nsenter.
docker exec -it <container> bash, interactive shelldocker exec -it <container> sh, for slim/alpine imagesdocker exec <container> env, environment without interactive shelldocker exec <container> cat /etc/hosts, quick file peekdocker exec --user root -it <container> sh, root shell when the default user is locked downdocker cp <container>:/app/file.log ./file.log, copy file outdocker cp ./script.sh <container>:/tmp/, copy file in
Inspect
Everything Docker knows about a container or image, in one JSON blob. Pair with jq.
docker inspect <container>, full JSONdocker inspect --format '{{.State.Status}}' <container>, running, exited, restartingdocker inspect --format '{{.State.ExitCode}}' <container>, exit code (137 = OOMKilled, 143 = SIGTERM)docker inspect --format '{{.State.OOMKilled}}' <container>, boolean for OOMKilldocker inspect --format '{{.NetworkSettings.IPAddress}}' <container>, internal IPdocker inspect --format '{{json .Mounts}}' <container> | jq, volumes and bind mountsdocker inspect <image>, works on images too; check.Config.Cmdand.Config.Entrypoint
Resource pressure
Live CPU, memory, network IO, block IO per container. Use it to confirm a container is hot before you start blaming it.
docker stats, live for all running containersdocker stats --no-stream, single snapshot, scriptabledocker stats <container>, single containerdocker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}", clean outputdocker top <container>, processes inside the container, host PIDs visibledocker events --since 1h, container lifecycle events (start, die, OOMKill)docker events --filter event=oom, OOMKills only
Disk and prune
Docker fills disks. Reclaim space carefully.
docker system df, total disk used by images, containers, volumes, build cachedocker system df -v, per-image, per-volume breakdowndocker image prune, remove dangling images (no tag)docker image prune -a, remove all unused images (aggressive)docker container prune, remove all stopped containersdocker volume prune, remove unused volumes (careful, data loss possible)docker builder prune, clear build cachedocker system prune -a --volumes, nuke everything unused; only on dev boxes
Networking
"My container can't reach the database." Half the time it's networks, half the time it's DNS, occasionally it's actually the database.
docker network ls, list networksdocker network inspect bridge, what's connected, gateway, subnetdocker port <container>, published port mappingsdocker exec <container> cat /etc/resolv.conf, DNS the container seesdocker exec <container> getent hosts db, name resolution testdocker run --rm --network=<net> nicolaka/netshoot, temporary debug container with curl, dig, nslookup, tcpdump, mtr