Containers & orchestration 24 entries 13 run in the sandbox

Docker cheat sheet

Build, run, inspect and debug containers and images. Each entry has a worked example and the flags worth knowing, and where one is easy to get wrong, the gotcha.

Run containers

docker run -d --name <name> -p <host>:<ctr> <image>

Start a container in the background with a name and a published port.

docker run -d --name web -p 8080:80 --restart unless-stopped nginx:1.27
-d
Detached: run in the background.
-p HOST:CTR
Publish container port CTR on host port HOST.
-e KEY=VAL / --env-file
Environment variables.
--restart unless-stopped
Restart after crashes and reboots unless you stopped it.
-v SRC:DST
Mount a volume or host path.

Gotcha -p 8080:80 means host 8080 to container 80. The app inside must listen on 0.0.0.0, not 127.0.0.1, or the published port gets nothing.

docker run --rm -it <image> sh

Throwaway interactive container for trying things out; it is deleted when you exit.

docker run --rm -it alpine:3.20 sh
--rm
Remove the container when it exits.
-i -t
Keep stdin open and allocate a terminal.
--entrypoint sh
Override the image's entrypoint to get a shell.

docker ps

List running containers with image, status, ports and names.

docker ps -a
CONTAINER ID   IMAGE        COMMAND                  STATUS                       PORTS                  NAMES
3f9a1c2b7d10   nginx:1.27   "/docker-entrypoint.…"   Up 2 hours                   0.0.0.0:8080->80/tcp   web
8b21e0f4c3aa   api:1.4.2    "node server.js"         Exited (137) 3 minutes ago                          api
-a
Include stopped containers; crashed ones hide here.
--format '{{.Names}} {{.Status}}'
Go template output.
-f status=exited
Filter by state.

docker stop <name>

Stop a container gracefully: SIGTERM, then SIGKILL after the timeout.

docker stop -t 30 api
-t SEC
Seconds to wait before SIGKILL (default 10).
start / restart
Start again or restart.
kill -s SIGNAL
Send a specific signal, such as HUP to reload.

Gotcha If shutdown always takes exactly 10 seconds, the process ignores SIGTERM, often because a shell wrapper is PID 1. Use exec in entrypoint scripts.

docker rm <name>

Delete stopped containers. Their writable layer, and any data not in a volume, is gone.

docker rm api
-f
Force-remove a running container.
-v
Also remove anonymous volumes attached to it.

Inspect & debug

docker logs <name>

Read what the container wrote to stdout and stderr.

docker logs --tail 100 -f api
-f
Follow new output.
--tail N
Start from the last N lines.
--since 10m
Only recent output.
-t
Prefix timestamps.

Gotcha Logs survive a crash but not docker rm. Read them before removing a failed container.

docker exec -it <name> sh

Open a shell or run a command inside a running container.

docker exec -it api sh
-it
Interactive terminal.
-u USER
Run as a specific user, for example -u 0 for root.
-e KEY=VAL
Extra environment for this command.

Gotcha Distroless and scratch images have no shell. Attach a debug container to its namespaces instead: docker run --rm -it --network container:api --pid container:api nicolaka/netshoot.

docker inspect -f '<template>' <name>

Read one field from a container's full JSON configuration and state.

docker inspect -f '{{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}}' api
exited exit=137 oom=true
.State
Status, ExitCode, OOMKilled, StartedAt, Health.
.NetworkSettings.Networks
IP address per network.
.Mounts
Volumes and bind mounts.
.Config.Env
Environment variables baked in at create time.

Container exit codes

What the number in 'Exited (N)' usually means.

docker ps -a shows Exited (N). Codes above 128 mean the process died from signal N - 128.

0
Clean exit. For a server, check why the main process finished.
1
Application error; read docker logs.
125
docker run itself failed (bad flag, name conflict).
126 / 127
Command not executable / not found in the image.
137
SIGKILL: the OOM killer or docker kill / stop timeout.
139
SIGSEGV: segmentation fault.
143
SIGTERM: a normal docker stop that the app honoured.

docker stats --no-stream

CPU, memory, network and block I/O per container, compared with the memory limit.

CONTAINER ID   NAME   CPU %   MEM USAGE / LIMIT     MEM %   NET I/O          BLOCK I/O
3f9a1c2b7d10   web    0.04%   9.2MiB / 7.7GiB       0.12%   1.2MB / 3.4MB    0B / 4.1kB
8b21e0f4c3aa   api    97.8%   498MiB / 512MiB       97.3%   22MB / 18MB      12MB / 0B
--no-stream
One snapshot instead of a live view.
--format
Custom columns.

docker port <name>

Show which host ports map to which container ports.

docker port web
80/tcp -> 0.0.0.0:8080
docker top NAME
Processes running inside the container.

docker events --since <time>

Stream daemon events: container starts, dies, OOMs and health status changes.

docker events --since 30m --filter event=die
--filter event=die
Only container exits.
--filter container=NAME
One container.

Build & ship images

docker build -t <name>:<tag> .

Build an image from the Dockerfile in the current directory (the build context).

docker build -t api:1.4.2 --target runtime .
-t NAME:TAG
Name and tag the result.
-f FILE
Use another Dockerfile.
--target STAGE
Stop at a named multi-stage stage.
--build-arg K=V
Build-time variable (not for secrets).
--no-cache
Rebuild every layer.

Gotcha Everything in the context is sent to the builder. Without a .dockerignore you ship .git, node_modules and maybe .env into the image.

docker images

List local images with tags, IDs and sizes.

-a
Include intermediate layers.
--digests
Show content digests.
-f dangling=true
Untagged images left by rebuilds.

docker pull <image>@<digest>

Download an image. Pinning a digest guarantees the same bytes every time, unlike a mutable tag.

docker pull nginx:1.27
:TAG
Mutable name; latest is only a convention.
@sha256:...
Immutable content address.
--platform linux/amd64
Choose an architecture explicitly.

Gotcha Built on an ARM Mac, deployed on x86? 'exec format error' means an architecture mismatch. Use buildx with --platform.

docker tag <src> <registry>/<repo>:<tag>

Name an image for a registry and push it.

docker tag api:1.4.2 ghcr.io/acme/api:1.4.2 && docker push ghcr.io/acme/api:1.4.2
tag
Adds a name; does not copy data.
push
Upload missing layers to the registry.
login REGISTRY
Authenticate first.

docker history <image>

Show each layer, its size and the instruction that created it, to find what makes an image big.

docker history --no-trunc api:1.4.2
--no-trunc
Full instructions.
--format '{{.Size}} {{.CreatedBy}}'
Compact size breakdown.

Gotcha A file deleted in a later RUN still takes space in the earlier layer. Delete it in the same RUN that created it.

docker buildx build --platform <list> --push

Build multi-architecture images and push them as a single manifest list.

docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/acme/api:1.4.2 --push .
--platform
Target architectures.
--push
Push directly; multi-platform results cannot load into the local image store.
--cache-from / --cache-to
Registry or CI cache for layers.

Multi-stage Dockerfile

Build with the full toolchain, ship a small runtime image that runs as a non-root user.

FROM node:20-bookworm AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:20-bookworm-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/dist ./dist
USER node
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s CMD node dist/healthcheck.js
CMD ["node", "dist/server.js"]
COPY package*.json first
Dependency layers stay cached until the lockfile changes.
AS build / --from=build
Only artifacts reach the final image, not compilers.
USER node
Do not run as root inside the container.
CMD ["..."] exec form
The app is PID 1 and receives SIGTERM directly.

.dockerignore

Keep secrets, VCS data and local build output out of the build context.

.git
node_modules
dist
*.log
.env
.env.*
coverage
Dockerfile*
.env
Never let local secrets reach an image layer.
node_modules
Install inside the image for the right platform.

Networks & volumes

docker network create <name>

Create a user-defined bridge network. Containers on it resolve each other by name.

docker network create app-net && docker run -d --network app-net --name db postgres:16
ls / inspect NAME
List networks or show connected containers.
--network NAME
Attach a container at run time.
connect NET CTR
Attach a running container.

Gotcha The default bridge network has no name-based DNS. Containers there can only reach each other by IP.

docker volume create <name>

Create a named volume managed by Docker, the right home for database data.

docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16
-v NAME:/path
Named volume; survives container removal.
-v /host/path:/path
Bind mount a host directory.
:ro
Mount read-only.
volume ls / inspect
List volumes or find their mount point.

Gotcha No -v for a database means its data lives in the container layer and disappears with docker rm.

Disk cleanup

docker system df

How much disk images, containers, volumes and build cache use, and how much is reclaimable.

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          41        6         18.2GB    15.9GB (87%)
Containers      9         3         1.1GB     804MB (73%)
Local Volumes   12        4         6.4GB     2.2GB (34%)
Build Cache     210       0         9.8GB     9.8GB
-v
Per-object breakdown.

docker system prune

Remove stopped containers, unused networks, dangling images and build cache.

docker image prune -a --filter "until=168h"
-a
Also remove every image not used by a container.
--volumes
Also remove unused volumes. This deletes data.
--filter until=168h
Only objects older than a week.
builder prune
Build cache only.

Gotcha prune --volumes on a host where a database container is stopped deletes the database. Read the list before typing y.

Your pager is ready.

Free, instant, and it works on your phone. No signup: start as a guest and save your progress later.