Docker

Cheat-sheet for day-to-day and incident work — images, containers, volumes, networks, compose, and cleanup.

Images

Build, tag, transfer, and remove images.

Build

Build from Dockerfile in current dir

docker build -t myapp:1.0 .

Custom Dockerfile path

docker build -f docker/Dockerfile -t myapp:1.0 .

Skip layer cache

docker build --no-cache -t myapp:1.0 .

Stop at an intermediate stage

docker build --target builder -t myapp:builder .

Pass build args

docker build --build-arg VERSION=1.0.3 -t myapp .

Multi-platform build + push (buildx)

docker buildx build --platform linux/amd64,linux/arm64 --push -t registry.example.com/myapp:1.0 .

Registry

Login

docker login registry.example.com

Pull

docker pull nginx:1.25-alpine

Re-tag for a registry

docker tag myapp:1.0 registry.example.com/myapp:1.0

Push

docker push registry.example.com/myapp:1.0

Save / Load

Transfer full images (layers, history, ENV, CMD, ENTRYPOINT) — ideal for air-gapped environments.

Save image to tar

docker save -o myapp.tar myapp:1.0

Save + compress

docker save myapp:1.0 | gzip > myapp.tar.gz

Load from tar

docker load -i myapp.tar

Load from compressed tar

gunzip -c myapp.tar.gz | docker load

Export / Import

Flattens a container's filesystem into a single-layer image — loses history and metadata (ENV, CMD, ENTRYPOINT). Use save/load instead when you need a faithful copy.

Export container filesystem

docker export <container> -o fs.tar

Import as image

docker import fs.tar myapp:flat

Inspect & Remove

List images

docker image ls

Build history / layer sizes

docker history myapp:1.0

Full metadata

docker image inspect myapp:1.0

Remove image

docker rmi myapp:1.0

Prune dangling images

docker image prune

Prune ALL unused images

docker image prune -a

Containers

Run, inspect, and manage container lifecycles.

Run

Detached, named, port-mapped

docker run -d --name web -p 8080:80 nginx

Interactive shell, auto-remove on exit

docker run -it --rm ubuntu bash

Bind-mount current dir as workdir

docker run -v "$(pwd):/app" -w /app node:20 npm test

Load env from file

docker run --env-file .env -d myapp

Auto-restart unless manually stopped

docker run --restart unless-stopped -d myapp

Resource limits

docker run --memory 512m --cpus 1.5 myapp

Attach to a specific network

docker run --network my-net --name api myapp

Run as non-root user

docker run --user 1000:1000 myapp

Lifecycle

Start / stop / restart

docker start|stop|restart <id>

Force-kill (SIGKILL)

docker kill <id>

Pause / unpause (freeze processes)

docker pause <id> # docker unpause <id>

Rename

docker rename old-name new-name

Snapshot container to image

docker commit <id> myapp:snapshot

Remove stopped container

docker rm <id>

Force-remove running container

docker rm -f <id>

Prune stopped containers

docker container prune

Inspect & Observe

Running containers

docker ps

All (including stopped)

docker ps -a

Filter by status + name

docker ps -a --filter "status=exited" --filter "name=web"

Follow logs, last 100 lines

docker logs -f --tail 100 <id>

Full inspect (JSON)

docker inspect <id>

Single field via Go template

docker inspect --format '{{.State.Status}}' <id>

Live resource usage

docker stats

Processes inside container

docker top <id>

Daemon event stream

docker events --since 10m

Exec & Copy

Shell into a running container

docker exec -it <id> sh

Shell as root

docker exec -u 0 -it <id> sh

Run one-off command

docker exec <id> printenv

Copy file INTO container

docker cp ./file.conf <id>:/etc/app/file.conf

Copy file OUT of container

docker cp <id>:/var/log/app.log ./app.log

Volumes & Mounts

Persistent storage for containers.

Named volumes

Create

docker volume create mydata

List

docker volume ls

Inspect (see mountpoint on host)

docker volume inspect mydata

Remove

docker volume rm mydata

Prune unused

docker volume prune

Mount syntax

In -v, a leading "/" means bind-mount (host path); no leading "/" means named volume.

Named volume

docker run -v mydata:/data myapp

Bind mount (absolute path required)

docker run -v "$(pwd):/app" myapp

Read-only bind mount

docker run -v "$(pwd):/app:ro" myapp

In-memory tmpfs

docker run --tmpfs /tmp:size=64m myapp

Verbose --mount form

docker run --mount type=bind,source="$(pwd)",target=/app,readonly myapp

Networks

Isolate and connect containers.

CRUD

List

docker network ls

Create bridge network

docker network create --driver bridge my-net

Custom subnet

docker network create --subnet 172.20.0.0/16 my-net

Inspect (shows attached containers)

docker network inspect my-net

Remove

docker network rm my-net

Prune unused

docker network prune

Attach / Detach

Connect a running container

docker network connect my-net web

Disconnect

docker network disconnect my-net web

Drivers

bridge (default, isolated virtual L2), host (share host stack, no port mapping), none (no networking), overlay (multi-host, requires swarm). Containers on the same user-defined bridge can resolve each other by name via embedded DNS.

Compose

Multi-container stacks via docker-compose.yml (Compose V2 syntax).

Lifecycle

Start in background

docker compose up -d

Rebuild images first

docker compose up -d --build

Stop + remove containers & networks

docker compose down

Also remove named volumes

docker compose down -v

Stop without removing

docker compose stop

Restart a single service

docker compose restart web

Scale & Profiles

Scale a service

docker compose up -d --scale worker=3

Gate services behind a profile

docker compose --profile dev up -d

Observe & Exec

Status

docker compose ps

Follow logs for one service

docker compose logs -f web

Shell into running service

docker compose exec web sh

One-off disposable container

docker compose run --rm web npm test

Build & Config

Build all services

docker compose build

Build without cache

docker compose build --no-cache

Pull latest images

docker compose pull

Validate + print merged config

docker compose config

Layer compose files (override base)

docker compose -f compose.yml -f compose.prod.yml up -d

Custom env file

docker compose --env-file .env.prod up -d

System & Cleanup

Inspect the daemon and reclaim disk.

Info

Daemon info

docker info

Disk usage breakdown

docker system df

Verbose disk usage (per-image)

docker system df -v

Live daemon events

docker system events

Safe prune

Removes stopped containers, unused networks, and dangling images. Does NOT remove volumes.

Default prune

docker system prune

Include volumes

docker system prune --volumes

Aggressive prune

Full reset of unused Docker resources — verify first.

All unused images + stopped containers + networks + volumes

docker system prune -a --volumes

Targeted prune

Stopped containers

docker container prune

Dangling images

docker image prune

All unused images

docker image prune -a

Unused volumes

docker volume prune

Unused networks

docker network prune

Inspect before deleting

docker ps -a
docker volume ls
docker image ls
docker system df -v

Tips & Pitfalls

Hard-won defaults and things that bite in production.

Volumes hold persistent data

Databases, uploads, and caches live in volumes. docker system prune --volumes is destructive — verify with docker volume ls first.

Can't delete? It's attached

If a volume, network, or image refuses to remove, something still references it. Trace with docker ps -a --filter volume= or docker inspect.

Layer cache order matters

Copy lockfiles before source: COPY package*.json ./RUN npm ciCOPY . .. Source edits then reuse the cached deps layer.

Multi-stage builds shrink images

FROM node:20 AS build → compile → FROM nginx:alpineCOPY --from=build /app/dist /usr/share/nginx/html. Toolchain stays out of the runtime image.

Use a .dockerignore

Keeps .git, node_modules, .env, and tests out of the build context — faster builds and no accidental secrets in images.

Non-root + pinned tags

USER app in the Dockerfile and pin tags (node:20.11.1-alpine, not :latest) for reproducibility and defense in depth.

ARG vs ENV

ARG is build-time only and does not persist. ENV persists in the final image — never put secrets there. Use BuildKit --secret or runtime --env-file.

HEALTHCHECK for orchestrators

HEALTHCHECK CMD curl -fsS http://localhost:8080/health || exit 1 lets Swarm/Kubernetes/Compose detect unhealthy containers.

Bound log driver

Default json-file driver grows unbounded. Cap per-container: --log-opt max-size=10m --log-opt max-file=3, or set defaults in /etc/docker/daemon.json.

save/load ≠ export/import

save/load transfer full images (layers + history + metadata). export/import flatten the filesystem into one layer and drop ENV/CMD/ENTRYPOINT — not a faithful copy.