Docker cheat sheet
A scannable Docker reference: 23 short snippets across 12 topics, each linking back to the lesson it came from.
At a glance
| Topic | What it covers | |
|---|---|---|
| Images and containers | An image is an ordered set of read-only layers plus a small config that says which command to run. docker pull | lesson |
| Writing a Dockerfile | Every instruction creates a layer. Docker reuses a cached layer while the instruction and its inputs are unchanged, but | lesson |
| Compose, volumes and networking | Compose takes one YAML file and creates the whole set of containers, networks and volumes with a single command. It is | lesson |
| Installing Docker and the core CLI workflow | Docker is three things wearing one name: a client (docker), a long-running daemon (dockerd) that does the work, and a | lesson |
| Container lifecycle, logs and debugging | States and restart policies, where stdout goes, exec versus attach, inspect and exit codes, and the reflex that finds | lesson |
| Registries, tags and image distribution | How an image name is assembled, why digests are the only immutable reference, and pushing to Docker Hub, GHCR or a | lesson |
| BuildKit, cache and multi-platform images | BuildKit is the build engine behind modern Docker. The docker driver builds inside the daemon and cannot export cache | lesson |
| Container security: users, capabilities and secrets | A container runs as root unless you say otherwise, and root inside a container is root on the host kernel — namespaces | lesson |
| Data persistence and backup patterns | Volume drivers and where data really lives, permission mismatches, database containers, and a backup you have restored | lesson |
| Docker in CI and publishing images | Building in a pipeline, caching layers across runs, tagging with the commit, scanning for vulnerabilities and signing | lesson |
| Production concerns: resources, health and logging | CPU and memory limits, healthchecks that mean something, log rotation, and shutting down without dropping requests | lesson |
| Podman, containerd and the OCI ecosystem | Docker popularised containers but does not define them. Three Open Container Initiative specifications do: the image | lesson |
Quick snippets
Images and containers
Images are stacked layers
docker pull nginx:1.27-alpine # a tag points at a specific digest
docker images # what is on disk
docker history nginx:1.27-alpine # layer by layer
docker rmi nginx:1.27-alpine # remove (fails if a container still uses it)
Lifecycle and cleanup
docker stop web # SIGTERM, then SIGKILL after 10 seconds
docker kill web # SIGKILL immediately
docker restart web
docker rm web # only when stopped; -f forces it
docker system df # where the disk went
docker system prune -a # reclaim space: unused images, networks, build cacheFull lesson: Images and containers →
Writing a Dockerfile
A first Dockerfile
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
Layers and the build cache
# slow: any source change reinstalls every dependency
COPY . .
RUN npm ci
# fast: dependencies stay cached until the manifest changes
COPY package*.json ./
RUN npm ci
COPY . .
Layers and the build cache
docker build -t myapp:1.0 .
docker build --no-cache -t myapp:1.0 . # verify without stale layers
docker build --target build -t myapp:debug . # stop at a named stage
cat > .dockerignore <<'EOF'
node_modules
.git
dist
*.log
EOFFull lesson: Writing a Dockerfile →
Compose, volumes and networking
Describing a stack with Compose
docker compose up -d # build if needed, then start everything
docker compose ps
docker compose logs -f api
docker compose exec api sh
docker compose down # stop and remove containers (volumes survive)
Volumes and bind mounts
docker run -d --name db \
-v pgdata:/var/lib/postgresql/data \
postgres:16-alpine
docker run --rm -it -v "$PWD:/work" -w /work node:20-alpine npm test
docker volume ls
docker volume inspect pgdata
Networking
docker network ls
docker network inspect myapp_default
docker run --rm -it --network myapp_default nicolaka/netshoot nslookup dbFull lesson: Compose, volumes and networking →
Installing Docker and the core CLI workflow
What you are actually installing
docker version # client AND server - an error here means the daemon is down
docker info # storage driver, cgroup version, runtimes, root dir
docker context ls # which endpoint the CLI talks to
docker context use default
# talk to a remote or rootless daemon without touching the default
DOCKER_HOST=ssh://deploy@web docker psFull lesson: Installing Docker and the core CLI workflow →
Container lifecycle, logs and debugging
States and restart policies
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'
docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}}' app
docker inspect app --format '{{json .HostConfig.RestartPolicy}}'
docker stop app # SIGTERM, then SIGKILL after the grace period
docker stop -t 30 app # give it 30 seconds to flush
docker start app # same configuration as the original run
Logs: where they come from
docker logs app # everything PID 1 ever wrote
docker logs -f --tail 100 app # follow the last 100 lines
docker logs -t --since 30m app # timestamps, last 30 minutes
docker logs --until 2026-09-18T09:00:00 app
docker inspect -f '{{.HostConfig.LogConfig.Type}}' app
ls -lh $(docker inspect -f '{{.LogPath}}' app) # the file on the host
# rotate it - json-file grows without limit by default
docker run -d --log-opt max-size=10m --log-opt max-file=3 --name web nginx
# or globally, in /etc/docker/daemon.json
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }Full lesson: Container lifecycle, logs and debugging →
Registries, tags and image distribution
Anatomy of an image name
registry.example.com/team/api:1.4.2-alpine
└────────┬──────────┘ └─┬─┘ └┬┘ └────┬─────┘
registry host namespace repo tag
nginx -> docker.io/library/nginx:latest
ghcr.io/acme/api:sha-9f3c1 -> tag carries the commit
app@sha256:8f1c... -> digest: immutable, exact bytes
Anatomy of an image name
docker tag app:local registry.example.com/team/app:1.4.2
docker tag app:local registry.example.com/team/app:1
docker push registry.example.com/team/app:1.4.2
docker push registry.example.com/team/app:1
# pin the exact bytes you tested
docker inspect --format='{{index .RepoDigests 0}}' registry.example.com/team/app:1.4.2
docker pull registry.example.com/team/app@sha256:8f1c9a4e...
Manifests, digests and multi-architecture tags
docker buildx imagetools inspect registry.example.com/team/app:1.4.2
docker manifest inspect alpine:3.20 | head -40
# what the tag actually points at, per platform
docker buildx imagetools inspect --raw nginx:1.27-alpine | jq '.["mediaType"]'
# force the platform you want instead of the emulated default
docker pull --platform linux/arm64 alpine:3.20
docker run --rm --platform linux/amd64 alpine:3.20 uname -mFull lesson: Registries, tags and image distribution →
BuildKit, cache and multi-platform images
Cache mounts and cache backends
# python
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
# apt: the lists directory is reused between builds
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends curl
# go modules
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=bind,source=go.sum,target=go.sum \
go mod download
Cache mounts and cache backends
# reuse layers across machines and CI runs
docker buildx build \
--cache-from type=registry,ref=registry.example.com/team/app:buildcache \
--cache-to type=registry,ref=registry.example.com/team/app:buildcache,mode=max \
--tag registry.example.com/team/app:1.4.2 --push .
# GitHub Actions cache, no registry needed
docker buildx build --cache-from type=gha --cache-to type=gha,mode=max --load .
# local directories, useful on one machine
docker buildx build --cache-from type=local,src=/tmp/cache --cache-to type=local,dest=/tmp/cache .Full lesson: BuildKit, cache and multi-platform images →
Container security: users, capabilities and secrets
Never run as root by default
FROM node:20-alpine
WORKDIR /app
COPY --chown=10001:10001 package*.json ./
RUN npm ci --omit=dev
COPY --chown=10001:10001 . .
USER 10001:10001
CMD ["node", "server.js"]
Secrets that never become layers
# syntax=docker/dockerfile:1
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
# the token exists only for this RUN and leaves nothing behind
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci --omit=dev
COPY . .
USER 10001:10001
Secrets that never become layers
docker buildx build --secret id=npmrc,src=$HOME/.npmrc -t app:1.4.2 .
# proof that nothing leaked into a layer
docker history --no-trunc app:1.4.2 | grep -i -E 'token|secret|password' || echo "no secret in layers"
# at runtime, give the process a file or an env var instead of the image
docker run --rm --env-file ./secrets.env app:1.4.2
docker run --rm -v "$PWD/secrets:/run/secrets:ro" app:1.4.2Full lesson: Container security: users, capabilities and secrets →
Data persistence and backup patterns
Where the bytes live
docker volume create --driver local \
--opt type=nfs --opt o=addr=10.0.0.5,rw --opt device=:/export/data shared
docker volume ls
docker volume inspect pgdata --format '{{.Mountpoint}} {{.Driver}}'
sudo ls -la /var/lib/docker/volumes/pgdata/_data # the real path on the host
docker run --rm -v pgdata:/data alpine ls -la /data
docker volume rm pgdata # fails while a container uses it
docker volume prune # deletes every unused volume - read twiceFull lesson: Data persistence and backup patterns →
Docker in CI and publishing images
Tag strategy
docker buildx build --push \
--tag ghcr.io/acme/api:sha-$GIT_SHA \
--tag ghcr.io/acme/api:1.4.2 \
--tag ghcr.io/acme/api:1.4 \
--cache-from type=registry,ref=ghcr.io/acme/api:buildcache \
--cache-to type=registry,ref=ghcr.io/acme/api:buildcache,mode=max .
# record what you shipped
docker buildx imagetools inspect ghcr.io/acme/api:1.4.2 --format '{{json .Manifest.Digest}}'Full lesson: Docker in CI and publishing images →
Production concerns: resources, health and logging
Healthchecks
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
CMD node -e "require('http').get('http://127.0.0.1:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"Full lesson: Production concerns: resources, health and logging →
Podman, containerd and the OCI ecosystem
How Kubernetes consumes the same images
# on a node, the runtime is containerd and the CLI you may have is nerdctl
nerdctl --namespace k8s.io ps
nerdctl -n k8s.io images | grep api
crictl ps # the CRI view of the same containers
crictl pull registry.example.com/team/app:1.4.2Full lesson: Podman, containerd and the OCI ecosystem →
FAQ
Is this Docker cheat sheet free to use?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
Git Linux Kubernetes Nginx CI / CD Bash Scripting
Last refreshed 2026-09-27.