Docker from Basics to Production · Operate Containers
Debugging Containers
A repeatable checklist for containers that won't start, crash, or misbehave: state, exit code, logs, inspect and a shell.
What you'll build
Three broken containers (a crash on startup, a wrong command and an out-of-memory kill) diagnosed with the same five commands.
The idea
Work through the same questions every time:
- What state is it in?
docker ps -a(exited? restarting?). - How did it end?
docker inspect --format '{{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}'. - What did it say?
docker logs --tail 50(stdout and stderr). - How is it configured?
docker inspectfor command, environment, mounts, network and user. - What does it see?
docker exec -it NAME sh, or for an image without a shell,docker run --rm -it --entrypoint shon a debug-friendly variant ordocker cpfiles out.
| Exit code | Usual meaning |
|---|---|
| 1 | Application error (read the logs) |
| 126 | Command found but not executable |
| 127 | Command not found (typo, missing binary in a slim image) |
| 137 | SIGKILL: out of memory or killed after a stop timeout |
| 143 | SIGTERM: stopped normally |
The code
trap 'docker rm -f rc-crash rc-typo rc-oom > /dev/null 2>&1' EXIT
docker run --name rc-crash alpine:3.24 sh -c 'echo "reading config"; echo "fatal: DATABASE_URL not set" >&2; exit 1' > /dev/null 2>&1 || true
docker run --name rc-typo alpine:3.24 pythn app.py > /dev/null 2>&1 || true
docker run --name rc-oom --memory 48m --memory-swap 48m alpine:3.24 sh -c 'tail /dev/zero' > /dev/null 2>&1 || true
for c in rc-crash rc-typo rc-oom; do
echo "== $c: $(docker inspect $c --format 'status={{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}}')"
docker logs --tail 2 $c 2>&1 | sed 's/^/ log: /'
err=$(docker inspect $c --format '{{.State.Error}}' | grep -oE 'exec: "[^"]+": executable file not found[^:]*' || true)
if [ -n "$err" ]; then echo " error: $err"; fi
done
Output
== rc-crash: status=exited exit=1 oom=false log: fatal: DATABASE_URL not set log: reading config == rc-typo: status=created exit=127 oom=false error: exec: "pythn": executable file not found in $PATH == rc-oom: status=exited exit=137 oom=true
Run this on your computer — see “Get Started” for setup.
Common mistakes
- Restarting a broken container in a loop instead of reading its logs and exit code.
- "Fixing" things with
docker execin a running container; the next deploy loses the fix. - Forgetting that slim images lack tools (no
curl,ps,bash): use a debug container ordocker cp. - Ignoring
OOMKilled=trueand blaming the application code.
Key points
- State, exit code, logs, configuration, then look inside.
- Exit codes 127, 137 and 143 point straight at the cause.
- Fix the image or configuration, not the running container.
Further reading: docker inspect · docker logs
Practice questions
A container exits immediately with code 127. What do you check?
Answer
That the command exists in the image: 127 means command not found, often a typo or a tool missing from a slim base image.
How do you debug a distroless container that has no shell?
Answer
Read logs and inspect output, copy files out with docker cp, run a debug variant of the image (for example a :debug tag) or attach a separate debug container sharing its namespaces.
Why shouldn't you fix production problems with docker exec?
Answer
Changes made inside a running container are lost when it is replaced and aren't reproducible; the fix belongs in the image or configuration.
Open in the app to mark lessons complete, take notes and track your progress.