This cheatsheet lists the Docker CLI commands and flags for running, inspecting, building and cleaning up containers, plus the Compose equivalents. It is for developers who know the idea of a container and want the exact command. The Docker glossary page explains what Docker is. The common confusion here is an image (a template) versus a container (a running or stopped instance of it). Every command below was run against Docker 29.6.2.
| Flag | Meaning | Example |
|---|---|---|
| `-d` | Run in the background (detached) | `docker run -d nginx:alpine` |
| `--name` | Give the container a fixed name | `--name web1` |
| `-p HOST:CONTAINER` | Publish a container port on the host | `-p 8080:80` |
| `-p 127.0.0.1:HOST:CONTAINER` | Publish on the host loopback only | `-p 127.0.0.1:8080:80` |
| `-e KEY=value` | Set an environment variable | `-e GREETING=hi` |
| `--env-file` | Read variables from a file | `--env-file .env` |
| `-v SRC:DEST[:ro]` | Bind mount a path or named volume | `-v $PWD:/data:ro` |
| `--rm` | Delete the container when it exits | `docker run --rm alpine:3.20 date` |
| `-it` | Keep stdin open and allocate a terminal | `docker run -it alpine:3.20 sh` |
| `--network` | Attach to a named network | `--network net1` |
| `-w` / `-u` | Working directory / user inside the container | `-w /app -u 1000` |
| `-m` / `--cpus` | Memory and CPU limits | `-m 512m --cpus 1.5` |
| `--entrypoint` | Replace the image entrypoint | `--entrypoint sh` |
| `--read-only` | Mount the root filesystem read only | `--read-only` |
| Policy | Behavior |
|---|---|
| `no` | Never restart. This is the default |
| `on-failure[:max-retries]` | Restart only on a non-zero exit code, optionally up to a limit |
| `always` | Restart whenever it stops. A manually stopped container comes back when the daemon restarts |
| `unless-stopped` | Like `always`, but a manually stopped container stays stopped after a daemon restart |
| Command | What it does |
|---|---|
| `docker ps` | List running containers. Add `-a` for stopped ones |
| `docker logs -f --tail 100 NAME` | Follow the last 100 log lines (`-t` adds timestamps) |
| `docker exec -it NAME sh` | Open a shell in a running container |
| `docker inspect -f '{{.State.Status}}' NAME` | Read one field from the JSON detail |
| `docker port NAME` | Show published port mappings |
| `docker cp NAME:/path ./path` | Copy a file out of (or into) a container |
| `docker stats --no-stream` | One snapshot of CPU and memory use |
| `docker stop` / `kill` / `restart` | Stop gracefully, kill, or restart |
| `docker rm -f NAME` | Remove a container, even a running one |
| Command | What it does |
|---|---|
| `docker build -t name:tag .` | Build an image from the Dockerfile in the current directory |
| `docker images` | List local images |
| `docker pull` / `push` | Download or upload an image |
| `docker tag SRC NEW` | Add another name to an image |
| `docker rmi name:tag` | Remove an image tag |
| `docker volume create` / `ls` / `rm` | Manage named volumes |
| `docker network create` / `ls` / `rm` | Manage networks |
| Command | What it does |
|---|---|
| `docker compose up -d` | Create and start every service in `compose.yaml` |
| `docker compose ps` | List the project's containers |
| `docker compose logs --tail 50 web` | Show logs for one service |
| `docker compose config` | Print the merged, validated configuration |
| `docker compose down` | Stop and remove containers and the default network |
| `docker container prune -f` | Remove all stopped containers |
| `docker image prune -a` | Remove all images not used by a container |
| `docker system prune` | Remove stopped containers, unused networks, dangling images and unused build cache |
docker run --rm alpine:3.20 echo hello
docker run --rm alpine:3.20 sh -c 'exit 3'; echo "exit=$?"
hello
exit=3
--rm keeps stopped containers from piling up. The shell sees the exit code of the command inside the container, which makes docker run usable in scripts and CI steps. Without --rm, a finished container stays in docker ps -a until you remove it.
docker run -d --name web1 -e GREETING=hi -v /tmp/dc:/data:ro --restart unless-stopped alpine:3.20 sh -c 'echo $GREETING; ls /data; sleep 300'
docker logs web1
docker inspect -f '{{.HostConfig.RestartPolicy.Name}} {{.State.Status}}' web1
hi
compose.yaml
unless-stopped running
Logs show what the main process wrote to stdout and stderr, so log to the console rather than to files inside the container. The inspect template pulls just the two fields you care about.
docker run -d --name n1 -p 127.0.0.1:8081:80 nginx:alpine
curl -s -o /dev/null -w "%{http_code}\n" localhost:8081/
docker port n1
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
200
80/tcp -> 127.0.0.1:8081
NAMES IMAGE STATUS
n1 nginx:alpine Up 1 second
Binding to 127.0.0.1 keeps the port off the network. Without that prefix, the port is reachable from other machines. The --format 'table ...' template lets you choose the columns docker ps prints.
printf 'FROM alpine:3.20\nRUN echo built > /msg\nCMD ["cat","/msg"]\n' > Dockerfile
docker build -q -t demo:1 .
docker run --rm demo:1
sha256:cf9d34fbd893f3e3be9e6fb0831ccf72b11a9a7c81cf22084bdfa578a2c0372b
built
-q prints only the image ID. The ID will differ on your machine.
docker network create net1
docker run -d --name n2 --network net1 nginx:alpine
docker run --rm --network net1 alpine:3.20 wget -qO- -T 3 http://n2 | head -3
<!DOCTYPE html>
<html>
<head>
On a user-defined network, containers resolve each other by container name. On the default bridge network the same lookup failed in this run with wget: bad address 'n4', so create a network when services must find each other. Compose does this for you by creating a project network.
docker compose config
docker compose up -d
docker compose ps --format '{{.Service}} {{.State}} {{.Ports}}'
docker compose down
web running 127.0.0.1:8082->80/tcp
Run docker compose config before up. It prints the resolved file, expands defaults such as the dc_default network, and fails on YAML or schema mistakes. The project name comes from the directory name, so web in a directory called dc becomes the container dc-web-1. down removes the containers and that network but keeps named volumes unless you add -v.
Bind for 127.0.0.1:8082 failed: port is already allocated. Stop the first container or pick another host port.-it in a script or CI job: docker exec -it prints cannot attach stdin to a TTY-enabled container because stdin is not a terminal. Drop -t when there is no terminal.127.0.0.1 or put a reverse proxy in front.docker run --rm alpine:3.20 nosuchcmd ends with exec: "nosuchcmd": executable file not found in $PATH and exit 127. The binary is not in the image, so check the image contents or the command spelling.docker stop: Status Exited (137) means the process was killed with SIGKILL, either because it ignored SIGTERM past the timeout or because of an out-of-memory kill. Handle SIGTERM in PID 1.docker system prune surprises: It removes stopped containers and unused networks, but volumes are only pruned with --volumes, and then only anonymous ones. Build cache is always eligible. Use -f only when you have read what it lists.-d and losing the terminal: Without -d, docker run stays attached and Ctrl+C stops the container. Add -d, then read output with docker logs.:latest is just a tag: It does not mean newest. Pin a version such as nginx:1.27 so a rebuild gives the same image.-u to the owner or fix the host mode, as described in the chmod Permissions Cheatsheet.docker-compose.yml into Kubernetes Deployments and Services-p