Container lifecycle commands and debugging a container that will not stay up
Build, run, inspect, enter and clean up containers, and read exit codes and logs to explain why a container stopped.
Knowing what goes in a Dockerfile is half of Docker. The other half is running the result and finding out why it is not behaving. In a screening you may be shown a container that exits straight away and asked what you would check. Here are the commands, in the order you would use them.
Build, run, inspect
docker build -t shop-api:1.2 .
docker run -d --name api -p 8080:8000 --env-file .env shop-api:1.2
docker ps
docker ps -a
docker logs -f --tail 100 api
docker exec -it api sh
docker inspect api --format '{{.State.ExitCode}} {{.NetworkSettings.IPAddress}}'
-d runs in the background, --name names the container, and -p host:container publishes the port. docker ps shows only running containers; add -a to see the ones that exited, which is where a crashed container hides. logs -f follows output, and exec -it opens a shell inside to check files and environment variables.
Reading exit codes
When a container stops, docker ps -a shows a code. Exit 0 means the main process finished normally, which for a web server means the command returned instead of staying in the foreground. Exit 1 is usually an application error; read the logs. Exit 137 means the process received SIGKILL, most often because it exceeded a memory limit. Exit 139 is a segmentation fault. A container that restarts in a loop with --restart always can hide all of this, so stop it and run once in the foreground: docker run --rm -it shop-api:1.2.
Worked example: a colleague says "the container starts and dies". docker ps -a shows exit code 1 two seconds after start, and docker logs api ends with "connection refused: db:5432". The app came up before the database and did not retry. The fix is a retry in the app or a depends_on health condition in Compose, not a longer sleep. Second example: exit 0 immediately. The Dockerfile ends with CMD ["npm", "run", "build"], a one-time task, instead of CMD ["node", "server.js"].
Clean up
docker stop api && docker rm api
docker image ls
docker image rm shop-api:1.1
docker system prune
docker system df
Stopped containers, dangling images and build cache fill disks quickly. system prune removes what is not in use; add --volumes only when no data you need lives in an unnamed volume.
Common mistakes and a practice habit
- Rebuilding the image but running the old container. Stop, remove, run again.
- Publishing
-p 8000:8000when the app listens on 127.0.0.1 inside the container. It must bind to 0.0.0.0. - Deleting a container that held data with no volume attached.
- Expecting
docker logsto show an app that writes to a file; log to stdout instead.
Practice habit. Containerise any small web app, then break it four ways: wrong CMD, wrong port binding, a missing environment variable, and a memory limit of 20 MB. Diagnose each using only ps, logs, exec and inspect.
More in Cloud and DevOps