The docker command talks to a Docker daemon to run containers from images. This sheet covers running and stopping containers, reading their logs and getting a shell inside, building and cleaning up images, and keeping data in volumes. Every flag below is from the Docker CLI reference on docs.docker.com. The examples were run with Docker 29.9.2. We attempt to test on all versions. Docker Compose is a separate plugin and isn’t covered here.
what it is and when to use it
- Image: a read-only template, such as
alpine:3ornginx:alpine. It’s built from a Dockerfile or pulled from a registry. - Container: a running (or stopped) instance of an image, with its own filesystem, processes and network.
- Volume: storage managed by Docker that outlives any container.
- Network: lets containers reach each other. User-defined networks also let them find each other by name.
Reach for it when you want a service or tool running without installing it on the host, when a build has to be the same on every machine, or when you need a clean environment to try something and throw away.
install and check the version
Installation depends on your OS. The Docker docs have a page per Linux distribution, plus Docker Desktop for macOS and Windows. Use the instructions at docs.docker.com/engine/install/ rather than a copied one-liner.
| Command | What it does |
|---|---|
docker version output Client: Version: 29.9.2 API version: 1.56 Server: Docker Engine - Community Engine: Version: 29.9.2 | Client and daemon versions |
That output is trimmed. The full output also lists containerd, runc and the Go versions.
run containers
| Command | What it does |
|---|---|
docker run --rm alpine:3 echo hello | Run a command in a new container, then delete it |
docker run -it --rm alpine:3 sh | Interactive shell, deleted when you exit |
docker run -d --name web -p 8080:80 nginx:alpine | Run in the background with a name, publishing host port 8080 to container port 80 |
docker run -d --name web -p 127.0.0.1:8080:80 nginx:alpine | Publish on localhost only, not on every interface |
docker run --rm -e GREETING=hi -w /tmp alpine:3 sh -c 'pwd; echo $GREETING' | Set an environment variable and the working directory |
docker run --rm --user 1000:1000 alpine:3 id output uid=1000 gid=1000 groups=1000 | Run as a given user and group ID |
docker run --rm -m 64m --cpus 0.5 alpine:3 true | Cap memory and CPU |
docker run --rm --entrypoint sh alpine:3 -c 'echo entry' | Replace the image’s entrypoint |
docker run -d --restart unless-stopped --name web nginx:alpine | Restart automatically unless you stop it yourself |
Inside docker run -it, Ctrl-p Ctrl-q detaches and leaves the container running. exit ends the shell, and the container stops with it.
list, stop, start, remove
| Command | What it does |
|---|---|
docker ps | Running containers |
docker ps -a | All containers, including stopped ones |
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"output NAMES IMAGE STATUS web nginx:alpine Up 3 seconds | Pick the columns (output trimmed to the first three) |
docker stop web | Stop a container |
docker start web | Start a stopped container |
docker restart web | Restart a container |
docker rm web | Remove a stopped container |
docker rm -f web | Force-remove a running container. No undo. |
docker container prune | Remove every stopped container. No undo. |
logs, shells, and files
| Command | What it does |
|---|---|
docker logs --tail 50 -f web | Last 50 lines, then keep following |
docker logs --since 10m web | Only logs from the last 10 minutes |
docker exec web nginx -v | Run a command inside a running container |
docker exec -it web sh | Open a shell inside a running container |
docker cp web:/etc/nginx/nginx.conf ./nginx.conf | Copy a file out of a container |
docker cp ./hi.txt web:/tmp/hi.txt | Copy a file into a container |
docker top web | Processes in a container |
docker stats --no-stream | Resource use, printed once with --no-stream |
docker port web output 80/tcp -> 127.0.0.1:8080 | Port mappings |
inspect
| Command | What it does |
|---|---|
docker inspect -f '{{.State.Status}}' web | One field from a container’s details |
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' weboutput 172.17.0.2 | The container’s IP address on each network it’s attached to |
docker inspect -f '{{json .Config.Env}}' web | Environment variables as JSON |
images
| Command | What it does |
|---|---|
docker pull alpine:3 | Download an image without running it |
docker images | List images |
docker build -t myapp:1 . | Build from the Dockerfile in this directory and tag it |
docker tag myapp:1 myapp:latest | Add another tag to an image |
docker image history myapp:1 | Show the layers and the command that made each one |
docker rmi myapp:latest | Remove a tag or an image |
docker image rm myapp:1 | The same, as docker image rm |
docker image prune | Remove dangling images |
docker image prune -a | Remove every image no container uses, including ones you pulled on purpose |
docker build uses BuildKit through the buildx plugin, which normal Docker installs include. Without the plugin, Docker falls back to the old builder and prints a deprecation warning.
volumes and bind mounts
| Command | What it does |
|---|---|
docker volume create appdata docker run --rm -v appdata:/data alpine:3 sh -c 'echo saved > /data/f' | Create a named volume and use it |
docker run --rm -v appdata:/data:ro alpine:3 cat /data/f | Mount it read-only in another container |
docker run --rm --mount type=bind,src="$PWD",dst=/app,readonly alpine:3 ls /app | Bind-mount a host directory, read-only, with the long --mount form |
docker volume ls | List volumes |
docker volume inspect appdata | Inspect a volume |
docker volume rm appdata | Remove a volume and its data. No undo. |
networks
| Command | What it does |
|---|---|
docker network create appnet docker run -d --name db --network appnet alpine:3 sleep 600 | Create a network and start a container on it |
docker network ls | List networks |
docker network rm appnet | Remove a network |
On a user-defined network like appnet, containers reach each other by container name. On the default bridge network they can only use IP addresses.
disk space and cleanup
| Command | What it does |
|---|---|
docker system df output TYPE TOTAL ACTIVE SIZE Images 3 0 94.63MB Containers 0 0 0B Local Volumes 1 0 6B Build Cache 0 0 0B | What Docker is using (RECLAIMABLE column trimmed) |
docker system prune | Remove stopped containers, unused networks, dangling images, and build cache |
docker system prune -a --volumes | Also remove every unused image and anonymous volumes |
--volumes removes anonymous volumes only. Named volumes stay until you docker volume rm them.
gotchas
-p 8080:80publishes on every interface of the host, not just localhost. The Docker docs call publishing ports "insecure by default". Use-p 127.0.0.1:8080:80for something only you should reach.- Adding your user to the
dockergroup saves typingsudo, but the docs warn it "grants root-level privileges to the user". docker exec -itanddocker run -itfail in scripts and CI with "cannot attach stdin to a TTY-enabled container because stdin is not a terminal". Drop-twhen there’s no terminal.- Older guides use
{{.NetworkSettings.IPAddress}}. Docker deprecated that top-level field long ago, and on Docker 29.9.2 it failed withmap has no entry for key "IPAddress". Read the address from.NetworkSettings.Networksas shown above. docker rm -fstops and removes in one go. There’s no undo.docker image prune -aanddocker system prune -aalso delete images you pulled on purpose but aren’t running right now.DOCKER_HOSToverrides the activedocker context. Docker prints a warning when both are set.
related on terminal-life
sources
Checked against the Docker CLI reference and Engine docs on docs.docker.com, with Docker Engine 29 release notes up to 29.9.2.
Tested with the Docker 29.9.2 static binaries on Linux, using a separate daemon socket and data directory that were deleted afterwards. Buildx was v0.38.1.
What ran:
runwith--rm,-it(under a terminal multiplexer),-d,-p,-e,-w,--user,-m,--cpus,--entrypointand the detach keys.ps,stop,start,restart,rm,container prune.logs,exec,cp,top,stats,port,inspect.pull,images,build(with and without buildx),tag,image history,rmi,image prune.volume,--mount,network create,lsandrm.system df,system prune.
Docs only:
docker logs --since.--restart unless-stopped.- Name resolution on a user-defined network. The test daemon ran without firewall rules, so containers couldn’t resolve each other’s names.
Sources:
- docker container run: https://docs.docker.com/reference/cli/docker/container/run/
- docker container ls: https://docs.docker.com/reference/cli/docker/container/ls/
- docker container logs: https://docs.docker.com/reference/cli/docker/container/logs/
- docker container exec: https://docs.docker.com/reference/cli/docker/container/exec/
- docker container attach (detach keys): https://docs.docker.com/reference/cli/docker/container/attach/
- docker inspect: https://docs.docker.com/reference/cli/docker/inspect/
- docker buildx build: https://docs.docker.com/reference/cli/docker/buildx/build/
- docker image prune: https://docs.docker.com/reference/cli/docker/image/prune/
- docker system prune: https://docs.docker.com/reference/cli/docker/system/prune/
- Port publishing: https://docs.docker.com/engine/network/port-publishing/
- Bridge networks: https://docs.docker.com/engine/network/drivers/bridge/
- Volumes: https://docs.docker.com/engine/storage/volumes/
- Linux post-install (docker group): https://docs.docker.com/engine/install/linux-postinstall/
- Engine 29 release notes: https://docs.docker.com/engine/release-notes/29/
terminal-life.com/cheatsheets/docker/ · checked against the Docker Engine 29 CLI reference