Home
Production
Cheat Sheets
Hub
Docker Core
Cheat Sheets
Cheat Sheets
Three dense quick references by persona—docker run and Compose for developers,
BuildKit and CI/CD for DevOps, and kernel primitives plus runtime choices for architects.
Use Copy sheet for plain text, persona filters to focus one role, or print (Cmd/Ctrl+P).
developer
devops
architect
Compose V2
BuildKit
Developer
DevOps
Architect
docker run flags
Flag
Purpose
Example
Notes
-d
Detached (background)
docker run -d nginx
Returns container ID
--name
Human-readable name
--name web
Must be unique on host
-p / -P
Publish ports
-p 8080:80
-P publishes all EXPOSE ports
-v / --mount
Volume or bind mount
-v mydata:/data
Prefer --mount for explicit syntax
-e / --env-file
Environment variables
-e NODE_ENV=dev
Visible in docker inspect
--rm
Auto-remove on exit
docker run --rm -it alpine sh
Great for one-off commands
-it
Interactive TTY
docker run -it ubuntu bash
Needed for shells and REPLs
--network
Attach to network
--network mynet
host, none, bridge, custom
--restart
Restart policy
--restart unless-stopped
no, on-failure, always
--memory / --cpus
Resource limits
--memory 512m --cpus 1.5
Maps to cgroup v2 limits
--user
Run as UID:GID
--user 1001:1001
Override image USER
--entrypoint
Override ENTRYPOINT
--entrypoint sh
CMD becomes args to entrypoint
--health-cmd
Runtime healthcheck
--health-cmd "curl -f localhost/health"
Overrides Dockerfile HEALTHCHECK
--add-host
Extra /etc/hosts entry
--add-host api.local:127.0.0.1
Dev-only host aliases
# Typical local dev container
docker run -d --name api \
-p 8080:8080 \
-v "$(pwd)":/app:ro \
-e SPRING_PROFILES_ACTIVE=dev \
--restart unless-stopped \
myregistry/api:dev
Docker Compose commands
Command Purpose Notes
docker compose upStart services -d detached; --build rebuild images
docker compose downStop and remove -v removes named volumes
docker compose psList containers -a includes stopped
docker compose logsService logs -f follow; --tail=100
docker compose execRun in running service exec api sh — no new container
docker compose runOne-off task container Overrides command; useful for migrations
docker compose buildBuild images --no-cache, --pull
docker compose pullPull service images CI/CD deploy prep
docker compose configValidate & render YAML Catches merge errors early
docker compose watchSync + rebuild on change Compose 2.22+ dev workflow
docker compose --profileEnable profiled services --profile debug up
COMPOSE_FILE / -fMulti-file merge -f compose.yml -f compose.prod.yml
# compose.yaml essentials
services:
api:
build: .
ports: ["8080:8080"]
environment:
DATABASE_URL: postgres://db:5432/app
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
retries: 3
db:
image: postgres:16-alpine
volumes: [pgdata:/var/lib/postgresql/data]
volumes:
pgdata:
Dockerfile instructions (quick ref)
Instruction When Example Pitfall
FROM Base image; new stage FROM node:22-alpine@sha256:…:latest breaks reproducibility
RUN Build command → layer RUN npm ci && npm run buildChain with &&; each RUN = layer
COPY Copy from context COPY --chown=app:app . .Order matters for cache
WORKDIR Set cwd WORKDIR /appAbsolute paths only
ENV Runtime env var ENV NODE_ENV=productionVisible at runtime
ARG Build-time only ARG VERSION=1.0In docker history — no secrets
EXPOSE Document port EXPOSE 8080Does not publish to host
ENTRYPOINT Main process (PID 1) ENTRYPOINT ["java","-jar","app.jar"]Exec form preferred
CMD Default args CMD ["--spring.profiles.active=prod"]Overridden by docker run …
USER Non-root runtime USER 1001Create user in earlier RUN
HEALTHCHECK Container probe HEALTHCHECK CMD curl -f localhost/healthRequired for orchestration
Debugging commands
Command Purpose
docker logs -f --tail 200 <name>Stream recent logs
docker logs --since 5m <name>Logs since timestamp
docker exec -it <name> shShell into running container
docker exec -u root <name> apk add curlDebug as root (dev only)
docker inspect <name>Full JSON state/config
docker inspect --format '{{.State.ExitCode}}' <name>Go-template field extract
docker statsLive CPU/mem/net I/O
docker top <name>Processes inside container
docker eventsStream daemon events
docker diff <name>Filesystem changes vs image
docker cp <name>:/path ./localCopy files out for inspection
# Why did it exit?
docker inspect --format '{{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}}' myapp
# Which IP on the bridge network?
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
# Follow logs with timestamps
docker logs -f --timestamps myapp 2>&1 | grep -i error
Volume & port syntax
Type Syntax Example Use when
Named volume
-v <name>:<path>
-v pgdata:/var/lib/postgresql/data
DB persistence; Docker manages storage
Bind mount
-v <host>:<path>
-v $(pwd)/src:/app/src
Hot reload; dev source sync
Read-only bind
-v <host>:<path>:ro
-v ./config:/etc/app:ro
Config injection without writes
Anonymous volume
-v <path>
-v /tmp/cache
Ephemeral writable layer override
Mount (explicit)
--mount type=…
--mount type=volume,source=pgdata,target=/data
Production clarity; required options
Port publish
-p host:container
-p 127.0.0.1:8080:80
Bind to localhost only in dev
UDP port
-p host:container/udp
-p 5353:5353/udp
DNS/mDNS services
Port range
-p start-end:start-end
-p 8000-8010:8000-8010
Multiple adjacent ports
# --mount examples (preferred in prod docs)
docker run --mount type=bind,source=/opt/data,target=/data,readonly nginx
docker run --mount type=volume,source=logs,target=/var/log/myapp nginx
docker run --mount type=tmpfs,target=/run,tmpfs-size=64m nginx
# Compose volume shorthand
volumes:
- ./src:/app/src:cached # macOS bind performance hint
- config:/etc/myapp:ro
Multi-stage patterns
Pattern Stages Runtime base
Java / Spring Boot Maven/Gradle builder → JRE eclipse-temurin:21-jre-alpine or distroless
Node.js npm ci && build → slim runtimenode:22-alpine; copy node_modules prod only
Python venv/poetry build → slim python:3.12-slim; multi-stage pip install
Go Compile static binary FROM scratch or distroless/static
Frontend + Nginx npm build → nginx serve nginx:alpine; copy dist/ only
Layered JAR (Spring) Extract layers in builder Separate COPY for deps vs app code
# syntax=docker/dockerfile:1
FROM golang:1.22 AS builder
WORKDIR /src
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app .
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
BuildKit mount types
Mount type Purpose Dockerfile / CLI Notes
type=cache
Persist package manager caches
RUN --mount=type=cache,target=/root/.m2 …
Speeds rebuilds; not in final image
type=secret
Build-time credentials
RUN --mount=type=secret,id=npm_token …
docker build --secret id=npm_token,src=…
type=ssh
SSH agent for private repos
RUN --mount=type=ssh git clone …
docker build --ssh default
type=bind
Bind host path into build
RUN --mount=type=bind,from=builder,src=/out …
Cross-stage artifact copy alternative
type=tmpfs
Ephemeral writable dir
RUN --mount=type=tmpfs,target=/tmp …
No layer bloat from temp files
# Enable BuildKit
export DOCKER_BUILDKIT=1
# buildx with registry cache (CI)
docker buildx build \
--cache-from type=registry,ref=myregistry/myapp:buildcache \
--cache-to type=registry,ref=myregistry/myapp:buildcache,mode=max \
--platform linux/amd64,linux/arm64 \
--push -t myregistry/myapp:$(git rev-parse --short HEAD) .
Registry commands
Command Purpose
docker login myregistry.ioAuthenticate (stores in config.json)
docker tag src:tag myregistry.io/ns/img:tagRetag for push target
docker push myregistry.io/ns/img:tagUpload image layers
docker pull myregistry.io/ns/img@sha256:…Pull by immutable digest
docker manifest inspect img:tagMulti-arch manifest list
docker buildx imagetools inspect img:tagRegistry-side manifest inspect
docker buildx imagetools create -t img:1.2 a:sha… b:sha…Create multi-arch manifest
crane copy src:tag dst:tagCopy between registries (no local pull)
cosign sign myregistry.io/ns/img@sha256:…Sign image digest
cosign verify --certificate-identity-regexp …Verify signature in deploy
Tagging strategy
Tag Mutable? When to use Deploy rule
sha-<git> / <pipeline-id>No Every CI build Immutable artifact ID
v1.2.3 (semver)Yes (re-tag risk) Release promotion Pin digest in prod manifests
main / developYes Branch head tracking Never deploy to prod directly
latestYes Convenience only Avoid in production
2026.06.05 (date)Yes Scheduled releases Combine with git SHA tag
# Promotion flow (dev → staging → prod)
# CI pushes: myapp:sha-a1b2c3d + myapp:main
# Staging deploys digest of sha-a1b2c3d
# Prod promotion retags or updates manifest to same digest — never rebuild
CI/CD pipeline steps
Step Tool / command Gate
1. Lint Dockerfile hadolint DockerfileFail on DL3xxx errors
2. Build image docker buildx build / KanikoBuildKit cache hit > 70%
3. Scan image Trivy / Docker Scout Block CRITICAL unfixed CVEs
4. Generate SBOM --attest type=sbom / SyftAttach to registry artifact
5. Sign image cosign / Notation Policy requires signature
6. Push tags docker push git SHA + semverDigest recorded in CI output
7. Deploy by digest Compose/K8s/ECS manifest No floating :latest in prod
8. Smoke test Healthcheck / contract test Rollback on failure
# GitHub Actions sketch
- run: hadolint Dockerfile
- uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.REGISTRY }}/app:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- run: trivy image --exit-code 1 --severity CRITICAL ${{ env.REGISTRY }}/app:${{ github.sha }}
hadolint rules (common)
Rule Meaning Fix
DL3006 Always tag image version FROM alpine:3.20 not alpine
DL3008 Pin apt packages apt-get install pkg=1.2.3
DL3013 Pin pip packages pip install pkg==1.2.3
DL3018 Pin apk packages apk add pkg=1.2.3
DL3025 JSON args recommended Exec form CMD ["npm","start"]
DL3059 Multiple consecutive RUN Merge RUN instructions
DL4000 MAINTAINER deprecatedUse LABEL
DL4001 apt-get upgrade discouragedRebuild base image instead
DL4006 ln without -f or -sUse proper symlink flags
SC2086 Unquoted variable (shellcheck) Quote "$VAR"
Scanning — Trivy & Docker Scout
Command Purpose
trivy image myapp:latestScan local or remote image
trivy image --severity CRITICAL,HIGH myapp:tagFilter severity
trivy image --exit-code 1 --ignore-unfixed myapp:tagCI gate (fail on fixable CVEs)
trivy fs --scanners vuln,secret .Scan repo + secrets pre-build
trivy sbom / --format spdx-json -o sbom.jsonGenerate SBOM
trivy image --format sarif -o results.sarif myappSARIF for GitHub Code Scanning
docker scout quickview myapp:tagCVE summary + base image recommendations
docker scout cves myapp:tagDetailed vulnerability list
docker scout recommendations myapp:tagSafer base image suggestions
docker scout compare --to myapp:old myapp:newDiff CVEs between tags
docker scout enrollEnable Scout for org images
# CI policy example
trivy image --exit-code 1 --severity CRITICAL --ignore-unfixed "$IMAGE"
docker scout cves "$IMAGE" --only-severities critical,high
Linux namespaces reference
Namespace Isolates Docker flag / relevance Pitfall
PID Process tree Container init = PID 1; orphan reaping --pid=host exposes host PIDs
NET Interfaces, routes, iptables Bridge networking, -p NAT publish --network=host = no network isolation
MNT Mount table Rootfs, volumes, bind mounts Bind mounts can leak host paths
UTS Hostname --hostnameCosmetic; DNS is separate
IPC SHM, semaphores, mq Isolates /dev/shm --ipc=host for legacy SHM apps
USER UID/GID mapping Rootless Docker / Podman Bind mount ownership must match subuids
CGROUP Cgroup hierarchy view Container sees own cgroup subtree Delegation misconfig breaks limits
TIME Boot/monotonic clock Niche testing scenarios Requires CAP_SYS_TIME
# Inspect namespace inodes for container PID
PID=$(docker inspect --format '{{.State.Pid}}' myapp)
ls -la /proc/$PID/ns/ # different inode = isolated from host
cgroup v2 flags & limits
Resource docker run flag Compose equivalent Notes
Memory max --memory 512mdeploy.resources.limits.memoryOOM kill when exceeded
Memory + swap --memory 512m --memory-swap 1g— -1 = unlimited swap
Memory reservation --memory-reservation 256mreservations.memorySoft guarantee under pressure
CPU quota --cpus 2limits.cpusFractional CPUs OK
CPU shares --cpu-shares 512— Relative weight under contention
CPU pinning --cpuset-cpus 0,1— NUMA-sensitive workloads
PIDs max --pids-limit 200— Prevents fork bombs
Block I/O --device-read-bps— Throttle disk per device
OOM behavior --oom-kill-disable— Dangerous; requires --privileged
# cgroup v2 path (host)
cat /sys/fs/cgroup/system.slice/docker-$(docker inspect -f '{{.Id}}' myapp).scope/memory.max
# Production defaults
--memory 1g --cpus 2 --pids-limit 500 --restart unless-stopped
Security options
Option Effect Production default Risk if misused
--read-onlyRootfs read-only Enable + tmpfs for /tmp App needs writable dirs → use volumes
--cap-drop ALLDrop all capabilities Drop all, add minimal Missing CAP_NET_BIND_SERVICE for <1024 ports
--cap-addGrant specific caps Rarely needed CAP_SYS_ADMIN ≈ root
--security-opt no-new-privilegesBlock privilege escalation Always in prod setuid binaries won't elevate
--security-opt seccomp=…Syscall filter profile Default Docker profile Custom profile can break JVM/GUI
--security-opt apparmor=…MAC profile (Ubuntu) docker-defaultCustom profile maintenance
--privilegedAll caps + host devices Never in prodFull host compromise vector
--user 1001:1001Non-root runtime Always File permission mismatches on volumes
--userns-remapUID mapping (daemon-level) Consider for multi-tenant Host file ownership complexity
Socket mount /var/run/docker.sockNever in app containers= root on host
Image hardening checklist
# Check Verify
1 Pin base image to digest FROM img@sha256:…
2 Run as non-root USER docker inspect .Config.User
3 No secrets in ENV/ARG/layers docker history + Trivy secret scan
4 Minimal runtime base (distroless/alpine) Image size & attack surface audit
5 Multi-stage build; no build tools in runtime Inspect final stage layers
6 HEALTHCHECK defined docker inspect .Config.Healthcheck
7 CVE scan gate in CI Trivy/Scout CRITICAL = 0 unfixed
8 Sign images; verify at deploy cosign verify policy
9 SBOM attached Registry attestations / Syft output
10 Read-only rootfs where possible --read-only + tmpfs mounts
11 Drop ALL caps; no privileged docker inspect .HostConfig.Privileged
12 No latest tag in production deploy Manifest pinned to digest
Logging driver comparison
Driver Storage Best for Limitations
json-file (default)
Local JSON files
Dev, single-host Compose
Disk fills; no central aggregation
local
Local binary, auto-rotated
Single-host prod without agent
Still host-local only
journald
systemd journal
Linux hosts with journald
Coupled to init system
syslog
Remote syslog server
Legacy SIEM integration
UDP loss; TLS config needed
fluentd
Fluentd/Fluent Bit forward
Kubernetes + Fluent stack
Buffer/backpressure tuning
awslogs
CloudWatch Logs
ECS/Fargate on AWS
AWS-specific; IAM roles
gcplogs
Google Cloud Logging
GCE/GKE workloads
GCP-specific
none
Discarded
Batch jobs with no log need
No debugging trail
# daemon.json — rotate json-file logs
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "5" }
}
# Per-container override
docker run --log-driver=fluentd --log-opt fluentd-address=localhost:24224 myapp
Docker vs Podman vs containerd
Dimension Docker (rootful) Podman containerd
Architecture
Central dockerd daemon
Daemonless fork/exec per container
Low-level CRI runtime (no CLI UX)
Rootless default
Opt-in setup
Default on many distros
Via nerdctl / k8s CRI
Compose
docker compose
podman compose (compatible)
Not native — use K8s/nerdctl compose
Kubernetes
dockerd removed from nodes (1.24+)
podman generate kube for migration
Default node runtime via CRI
Build images
docker buildx (BuildKit)
podman build (Buildah backend)
nerdctl build / external CI only
OCI compatibility
Full — same registries
Full — pull/push identical images
Full — runs same OCI artifacts
Socket risk
docker.sock = root on host
No central socket by default
containerd.sock also privileged
Best fit
Developer ergonomics, local dev
Rootless/RHEL/OpenShift edge
K8s production runtime layer