DS DevShelfHub Projects · AI tools
Cheatsheets / Docker
Cheatsheet · Dev tooling

Docker: Images, Containers, Volumes and Compose Reference Guide

By DevShelfHub

Images, containers, volumes, networks, Compose, multi-stage builds, and BuildKit — the day-to-day Docker commands and Compose snippets for Docker Engine 25+ and Compose v2. Covers the full workflow from Dockerfile authoring through registry push and production cleanup.

97 items 6 min Build Run Compose

Start hereQuick start · 6 you’ll reach for daily

Builddocker build -t app .
Rundocker run -p 8000:8000 app
Shell indocker exec -it CID sh
Tail logsdocker logs -f CID
Compose updocker compose up -d --build
Clean diskdocker system prune -af

Target versions · paceVersions

Targets: Docker Engine ≥ 25 BuildKit (default) Compose v2

This sheet assumes docker compose (Go plugin) — not the deprecated docker-compose Python tool. BuildKit is the default builder; the --mount=type=cache and --platform flags assume it’s on.

smoke test · daily-loop commandsSetup

bash
# Sanity check
docker version                     # client + daemon versions
docker info                        # storage driver, registry mirrors

# Daily quick-loop
docker run --rm -it alpine sh                              # throwaway shell
docker run --rm -p 8080:80 nginx:alpine                    # publish a port
docker run --rm -e ENV=prod -v $(pwd):/app -w /app node:22 # env + bind mount

# Auth to a registry
docker login ghcr.io                # GitHub container registry
docker logout ghcr.io

# Clean up reclaimable disk
docker system df                   # show usage
docker system prune -af --volumes  # everything not in use

build artefactsImages

docker imagesList local images.
docker pull alpine:3.20Fetch an image. Pin the tag.
docker build -t app:dev .Build from the Dockerfile in ..
docker build -f infra/Dockerfile -t app:dev .Custom Dockerfile path.
docker build --target build -t app:build .Stop at a named multi-stage target.
docker build --build-arg VER=1.2 .Pass an ARG.
docker tag app:dev ghcr.io/me/app:0.4.1Add a registry-qualified tag.
docker push ghcr.io/me/app:0.4.1Push to a registry.
docker rmi IMAGERemove an image.
docker image prune -aRemove dangling + unused images.
docker history IMAGELayer-by-layer breakdown.
docker image inspect IMAGEFull metadata as JSON.

running instancesContainers

docker run IMAGECreate + start. Foreground.
docker run --rm IMAGEAuto-remove on exit. Default for one-shots.
docker run -d IMAGEDetached / background.
docker run -it IMAGE shInteractive shell.
docker run -p 8000:8000 IMAGEPublish container:host port.
docker run -e KEY=val IMAGESingle env var. Repeat the flag.
docker run --env-file .env IMAGELoad env vars from a file.
docker run --name api IMAGEPin a friendly name.
docker run --restart unless-stopped IMAGERestart policy for prod.
docker run -v $(pwd):/app -w /app IMAGEBind mount cwd. Common dev pattern.
docker psRunning containers.
docker ps -aInclude stopped.
docker logs -f --tail 100 NAMEFollow logs.
docker exec -it NAME shShell inside a running container.
docker stop NAME · docker rm NAMEStop, then remove.
docker cp NAME:/path ./outCopy files in or out.
docker statsLive CPU / mem per container.
docker inspect NAMEFull container metadata.

instructions referenceDockerfile

FROM python:3.13-slim AS buildBase image. AS names a stage.
ARG VER=1.2.3Build-time variable. Available only during build.
ENV PYTHONUNBUFFERED=1Runtime env var. Persists in the image.
WORKDIR /appSets cwd for subsequent steps; creates it.
COPY src/ /app/src/Copy from build context. Respects .dockerignore.
ADD url|tar destCOPY + auto-extract tars + URL support. Prefer COPY.
RUN apt-get update && apt-get install -y …Shell exec at build time. Chain to keep layers small.
RUN --mount=type=cache,target=/root/.cache/pip …BuildKit cache mount. Survives across builds.
USER appDrop root. Pair with RUN useradd -m.
EXPOSE 8000Documentation only — doesn’t publish.
VOLUME ["/data"]Mark a path as an anonymous volume.
ENTRYPOINT ["python", "-m"]The thing always run.
CMD ["myapp"]Default args. Override at docker run time.
HEALTHCHECK --interval=30s CMD curl -f … || exit 1Container-level liveness probe.
bash
# syntax=docker/dockerfile:1.7
# --- build stage ---
FROM python:3.13-slim AS build
WORKDIR /app

# Use BuildKit cache for pip — survives across builds
RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=bind,source=requirements.txt,target=requirements.txt \
    pip install --prefix=/install -r requirements.txt

COPY . .

# --- runtime stage ---
FROM python:3.13-slim AS runtime
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
RUN useradd -m -u 10001 app
WORKDIR /app
COPY --from=build /install /usr/local
COPY --from=build /app /app
USER app
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s CMD curl -fsS localhost:8000/health || exit 1
CMD ["python", "-m", "myapp"]

smaller images, faster buildsBuildKit & multi-stage builds

# syntax=docker/dockerfile:1.7Pin the frontend. Unlocks newer features.
FROM … AS build / FROM … AS runtimeTwo stages: build artefacts, ship only what runs.
COPY --from=build /app /appPull artefacts from the build stage. Skips build tools.
RUN --mount=type=cache,target=…Persistent package-manager cache.
RUN --mount=type=secret,id=npm,target=…Inject secrets at build time without baking them in.
RUN --mount=type=bind,source=requirements.txt,target=…Read context files without COPY.
docker buildx build --platform linux/amd64,linux/arm64Cross-arch image. Push to registry as manifest list.
--cache-from / --cache-to type=registry,ref=…Share cache across CI runners.
.dockerignoreExcludes from build context. Add .git, .venv, node_modules.
Order layers by change frequency. Put COPY requirements.txt + pip install before COPY .. Source edits shouldn’t bust the dependency layer.

persistenceVolumes

docker volume create dataNamed volume managed by Docker.
docker run -v data:/var/lib/data IMAGEMount named volume.
docker run -v $(pwd):/app IMAGEBind mount host path. Dev-only.
--mount type=bind,source=…,target=…,readonlyModern syntax. Explicit type.
--tmpfs /scratchRAM-backed scratch dir. Disappears with the container.
docker volume ls / inspect / rmManage volumes.
docker volume pruneRemove unused volumes. Read this before running.
Bind mounts shadow the in-image contents at the same path. If /app in the image has files and you bind-mount over it, those files vanish for the container.

container connectivityNetworks

docker network lsDefault networks: bridge, host, none.
docker network create appUser-defined bridge. Containers can DNS each other by name.
docker run --network app --name db postgresAttach a container to a network.
docker network connect app apiAttach a running container.
--network hostShare host network. Linux only; bypasses port publishing.
--add-host host.docker.internal:host-gatewayReach the host machine from inside a container.
-p 127.0.0.1:8000:8000Publish only to localhost. Important for dev daemons.

multi-service workflowsCompose

docker compose up -dBring services up, detached.
docker compose up --buildForce rebuild before up.
docker compose up --watchFile-sync dev loop using develop.watch.
docker compose down -vStop + remove, including volumes. Destructive.
docker compose psStatus across services.
docker compose logs -f apiFollow one service.
docker compose exec api shShell into a service container.
docker compose run --rm api pytestOne-off command in a fresh container.
docker compose configResolve + print the merged config.
--profile devActivate optional services tagged with a profile.
yaml
# compose.yaml — modern format (no `version:` key needed)
services:
  api:
    build: .
    image: myorg/api:dev
    ports: ["8000:8000"]
    environment:
      DATABASE_URL: postgres://app:app@db:5432/app
    depends_on:
      db: { condition: service_healthy }
    develop:
      watch:
        - { action: sync,    path: ./src,        target: /app/src }
        - { action: rebuild, path: requirements.txt }
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
      POSTGRES_DB: app
    volumes: ["pgdata:/var/lib/postgresql/data"]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      retries: 5

volumes:
  pgdata:

distributionRegistries

docker login ghcr.ioAuth. Token in ~/.docker/config.json.
docker tag local:dev ghcr.io/me/app:0.4.1Always tag before push.
docker push ghcr.io/me/app:0.4.1Push the named tag.
docker pull ghcr.io/me/app@sha256:…Pull by digest. Most reproducible.
docker buildx imagetools inspect IMAGEMulti-arch manifest details.
docker scout cves IMAGECVE scan (Docker Desktop’s built-in).

when it’s on fireDebugging

docker logs --tail 200 --since 10m NAMEBound log volume; --timestamps for clock.
docker exec -it NAME shShell in. Use bash only if present.
docker run --rm -it --network container:NAME nicolaka/netshootNetwork diag in target container’s namespace.
docker run --rm -it --pid container:NAME alpine shShare PID namespace. Inspect target’s processes.
docker inspect --format '{{json .State}}' NAMEExit codes, OOM, restart counts.
docker top NAMEProcesses inside the container.
docker events --filter container=NAMELive event stream.
docker system df -vFind which image / volume is hogging disk.

build → push → runEnd-to-end · Build, push, run

Multi-arch BuildKit build, push to GHCR, run locally with env + restart policy, tail logs, tear down.

bash
# Build, tag, run, ship — the full local-to-registry loop.

# 1 · Build for multiple platforms with BuildKit
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag ghcr.io/me/api:0.4.1 \
  --tag ghcr.io/me/api:latest \
  --push .

# 2 · Inspect the result
docker image inspect ghcr.io/me/api:0.4.1 --format '{{.Size}}'
docker history ghcr.io/me/api:0.4.1

# 3 · Run locally
docker run -d --name api \
  -p 8000:8000 \
  -e DATABASE_URL=postgres://app:app@db:5432/app \
  --restart unless-stopped \
  ghcr.io/me/api:0.4.1

# 4 · Tail logs and exec into the running container
docker logs -f --tail 100 api
docker exec -it api sh

# 5 · Tear down
docker stop api && docker rm api

Best practiceGood to know

Pin tags. python:3.13-slim beats python:latest. For reproducibility, pin by digest: python:3.13-slim@sha256:….
One process per container. No supervisord. If you need two, run two containers and let Compose / Kubernetes wire them. Signals + logs only work cleanly with one.
Multi-stage by default. Final image gets the artefact, not the toolchain. Cuts size 5–10× on most stacks and shrinks the attack surface.

Common trapsWatch out for

Never put secrets in ENV or ARG. They show up in docker history and image inspect. Use --mount=type=secret at build time or runtime secrets (Compose / k8s).
latest isn’t magic. It’s just a tag. If you don’t push it, it’s whatever someone last pushed manually. Pin to a version or digest in production.
Bind mounts hide image files. -v $(pwd):/app over an /app that already has a node_modules in the image will erase it for the container. Mount sub-paths or use named volumes for vendored deps.

Go deeperSee also

Docker FAQ

What is the difference between a Docker image and a container?

An image is a read-only blueprint built from a Dockerfile — it contains the filesystem layers and metadata. A container is a running instance of an image with its own writable layer, network, and process space. One image can spawn many containers.

How do I run a Docker container in the background?

Use docker run -d to detach. Add -p 8080:8000 to publish ports and --name app to give it a stable name. Check it with docker ps and follow its logs with docker logs -f app.

What is Docker Compose used for?

Docker Compose defines and runs multi-container applications with a single docker-compose.yml file. It manages service dependencies, shared networks, and named volumes. Use docker compose up -d --build to start everything, and docker compose down -v to tear it down.

How do I reduce Docker image size?

Use multi-stage builds to discard build tooling from the final image, choose a minimal base image (alpine or distroless), combine RUN commands to squash layers, and add a .dockerignore file to exclude node_modules and .git from the build context.

How do I persist data in Docker?

Use named volumes (docker volume create my-vol) for managed persistence, or bind mounts (-v $(pwd)/data:/app/data) to map a host directory into the container. Named volumes are preferred for databases; bind mounts are convenient for development hot-reload.

How do I access a running container shell?

Run docker exec -it CONTAINER_ID sh (or bash if available). Use docker exec -it $(docker ps -qf name=app) sh to resolve the container by name. For a stopped container, start it with docker start -ai CONTAINER_ID to attach to its original command.