docker
Skill2 starsChanged 4 months agoMITView on GitHub
Use when writing Dockerfiles, Docker Compose files, building or debugging container images, choosing base images, pushing to registries, or running containers locally. Also trigger when asked about multi-stage builds, .dockerignore, container networking, volumes, or self-hosting an application with Docker. NOT for Kubernetes workloads (see k8s-workloads), Helm charts (see helm), Docker in CI pipelines (see github-actions), or GPU operator configuration (see gpu-operator).
- Reads credentials
- Installs packages
55 other projects use a version of this.
Adopted by
Most recently taken up by
- codewithmukesh/dotnet-claude-kittheir own version, first seen Nov 8, 2026
- fmind/dottheir own version, first seen Nov 8, 2026
- fmind/dotfilestheir own version, first seen Nov 8, 2026
- ericwood8/skillstheir own version, first seen Nov 1, 2026
- turkeryildirim/ai-skillstheir own version, first seen Nov 1, 2026
- jars-demo/jars-skillstheir own version, first seen Oct 25, 2026
Used with
Projects with it also use ml-training-recipe, replication and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
getcompanion-aiSkillml-training-recipe
Find implementable ML training recipes from papers, datasets, docs, and code. Use when the user wants to fine-tune, train, reproduce, or choose a practical ML method, dataset, hyperparameter setup, or benchmark recipe.
Also in 3 projects that use this
getcompanion-aiSkillreplication
Plan a replication of a paper, claim, or benchmark, and execute only after an explicit environment choice. Use when the user asks to replicate results, reproduce an experiment, verify a claim empirically, or build a replication package.
Also in 3 projects that use this
Sorcha-PlatformSkillscalar
Generates and configures Scalar OpenAPI UI for API documentation. Use when: Adding API documentation to services, configuring OpenAPI endpoints, customizing documentation themes
Also in 3 projects that use this
brainbytes-devSkillalpha-research
Also in 3 projects that use this
JaimeParkerSkillpaper-code-audit
Perform three-way cross-validation of a research paper by comparing the original paper text (via Zotero), official code implementation (via Git), and personal Obsidian notes. Use this skill whenever the user wants to "audit a paper", "verify paper claims against code", "cross-check notes with implementation", "triangulate paper + code + notes", "find discrepancies between paper and code", or mentions wanting a deep, structured comparison of a paper's claims against its implementation and their own notes. Also trigger when the user asks to "analyze this paper thoroughly" with code available, or when they want to systematically reconcile what the paper says, what the code does, and what their notes claim.
Also in 3 projects that use this
Sorcha-PlatformSkillredis
Implements Redis caching, session management, and distributed coordination for the Sorcha platform. Use when: Adding caching layers, token revocation, rate limiting, SignalR backplane, or distributed state.
Also in 5 projects that use this
- +1 more from getcompanion-ai
Other versions55 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 55
- advaitpaliwal/feynman★ 10ksame name
- companion-inc/feynman★ 10ksame name
- getcompanion-ai/feynman★ 10ksame name
- codewithmukesh/dotnet-claude-kit★ 808same name
- TheDecipherist/claude-code-mastery-project-starter-kit★ 337same name
- Mindrally/skills★ 275same name
- Resgrid/Core★ 238same name
- kid-sid/claude-spellbook★ 190same name
- OpenHands/extensions★ 167same name
- avibebuilder/claude-prime★ 119same name
45 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository67 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agent-architectureSkill
- agent-evaluationSkill
- agent-memorySkill
- agent-post-trainingSkill
- agent-self-evolutionSkill
- agent-tool-designSkill
- api-designSkill
- application-architectureSkill
- brainstormSkill
- code-reviewerSkill
- coding-agent-designSkill
- concurrency-designSkill
- context-engineeringSkill
- game-audioSkill
- game-designSkill
- game-narrativeSkill
- game-patternsSkill
- game-performanceSkill
- game-renderingSkill
- game-visualsSkill
- git-commitSkill
- git-prSkill
- godot-shaderSkill
- godotSkill
- gpu-rendering-architectureSkill
- grafanaSkill
- helmSkill
- homelab-monitoringSkill
- k3sSkill
- k8s-networkingSkill
- k8s-operationsSkill
- k8s-storageSkill
- k8s-workloadsSkill
- knowledge-baseSkill
- level-designSkill
- llm-inference-servingSkill
- loggingSkill
- logqlSkill
- love2d-fennelSkill
- love2dSkill
- ml-platform-architectureSkill
- ml-post-trainingSkill
- multi-agent-collaborationSkill
- nix-dendriticSkill
- nix-packagingSkill
- nixSkill
- odin-designSkill
- odin-gamedevSkill
- orchestratorSkill
- physical-ai-systemsSkill
- plannerSkill
- prd-to-storiesSkill
- prd-writingSkill
- promqlSkill
- pr-reviewerSkill
- python-designSkill
- rag-designSkill
- ray-data-pipelinesSkill
- ray-kubernetes-infrastructureSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
9 rules. 0 are common, 2 are distinctive, and 7 are very specific to this project.
0
Common
Most of the 47 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 19
Use single-stage: only for interpreted languages where you don't need a separate build step (e.g., Python running directly, simple shell …
- Very specific: line 123
Limitation: No package manager means you can't install missing shared libraries at runtime.
- Very specific: line 178
Always create .dockerignore at the build context root.
- Very specific: line 243
Place USER as the last directive before ENTRYPOINT/CMD.
- Distinctive: line 275
Use Compose for local development and simple self-hosted deployments.
- Very specific: line 327
Use depends_on with condition: service_healthy (not just service_started) to avoid race conditions
- Very specific: line 328
Never hardcode secrets in compose.yaml — use ${VAR} with .env file or env_file
- Very specific: line 329
Use named volumes (not bind mounts) for database data — named volumes survive compose down
- Very specific: line 439
Prefer named volumes over bind mounts.
“Common” is measured: kept by at least 6 in 10 of the 47 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Docker
Patterns and decisions for containerizing applications and managing containers locally or in self-hosted environments.
Dockerfile: Single-Stage vs Multi-Stage
Use single-stage only for interpreted languages where you don't need a separate build step (e.g., Python running directly, simple shell scripts).
Use multi-stage for everything else. The size difference is dramatic: a single-stage Node.js image is ~1.9 GB uncompressed; the equivalent multi-stage image is ~607 MB (75% smaller after compression). Multi-stage also prevents source code, dev dependencies, and build secrets from leaking into the final image.
Single-stage (basic — has known problems)
# syntax=docker/dockerfile:1
FROM node:24.7-trixie
WORKDIR /usr/src/app
COPY . .
RUN npm ci
RUN npm run build
ENV NODE_ENV=production
CMD npm run start # ← shell form: doesn't forward OS signals (use exec form)
EXPOSE 3000Problems with this: (1) source code and dev deps remain in the image, (2) no cache optimization — deps reinstall on every code change, (3) shell form CMD doesn't forward SIGTERM to the process.
Multi-stage (production-ready)
# syntax=docker/dockerfile:1
# stage 1: build
FROM node:24-bookworm-slim AS builder
WORKDIR /usr/src/app
COPY package*.json ./ # copy lockfile first — maximizes cache hits
RUN npm ci
COPY . .
RUN npm run build
RUN npm prune --omit=dev --omit=optional # removes dev + optional deps
# stage 2: runtime
FROM node:24-alpine AS runner
WORKDIR /usr/src/app
COPY --chown=65534:65534 --from=builder /usr/src/app/node_modules ./node_modules
COPY --chown=65534:65534 --from=builder /usr/src/app/package.json ./package.json
COPY --chown=65534:65534 --from=builder /usr/src/app/.next ./.next
COPY --chown=65534:65534 --from=builder /usr/src/app/public ./public
EXPOSE 3000
ENV NODE_ENV=production
USER 65534:65534
CMD ["npm", "run", "start"] # exec form: forwards signals correctlyWhy this ordering matters for cache: Copy package*.json and install deps before copying application code. Deps change rarely; code changes constantly. Docker invalidates cache at the first changed layer — if you copy everything first, deps reinstall on every code change.
Base Image Selection
| Situation | Reach for | Why |
| Build stage (needs compilers, tools) | <lang>:<version>-slim or <lang>:<version>-bookworm | Full toolchain, Debian base |
| Runtime stage (just needs to run) | <lang>:<lts-version>-alpine | Minimal attack surface, smallest size |
| System-level tools needed at runtime | <lang>:<version>-bookworm-slim | Debian without extras |
| Scratch binary (Go, Rust static builds) | scratch or gcr.io/distroless/static | Zero OS overhead |
Never use latest in production. Pin to at least a major version tag (node:24-alpine, not node:alpine). For maximum reproducibility, pin to a patch version (node:24.7-alpine). latest is a moving target that breaks reproducibility.
Alpine trade-off: Alpine uses musl libc instead of glibc. Most apps work fine, but some native extensions (certain Python packages, some Node.js addons) require glibc. If you hit mysterious runtime errors with Alpine, switch to -slim (Debian-based).
Distroless and Minimal Runtime Images
Distroless images strip out the shell, package manager, and OS utilities entirely. Less software means fewer CVEs and a smaller attack surface — an attacker who gains code execution can't use curl, wget, or bash if they don't exist in the image.
| Image | Use case |
gcr.io/distroless/static | Go, Rust, any static binary (includes CA certs, tzdata, /etc/passwd) |
gcr.io/distroless/base | C/C++ needing glibc (adds glibc and OpenSSL runtime libraries (libssl, libcrypto)) |
gcr.io/distroless/nodejs22-debian12 | Node.js apps |
gcr.io/distroless/python3-debian12 | Python apps |
Unversioned tags (/nodejs, /python3) exist but are not pinned to a runtime version.
Go example — static binary into distroless:
# syntax=docker/dockerfile:1
FROM golang:1.23-bookworm AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux go build -o /app/server ./cmd/server
FROM gcr.io/distroless/static AS runner
COPY --from=builder /app/server /server
USER nonroot # distroless provides this user (UID 65532)
EXPOSE 8080
ENTRYPOINT ["/server"]Limitation: No package manager means you can't install missing shared libraries at runtime. Native extensions requiring uncommon .so files may not work — use gcr.io/distroless/base (glibc) or fall back to Alpine if you need more.
FROM scratch is the extreme version: zero OS layer, static binary only. Works for Go (CGO_ENABLED=0) and Rust when targeting musl (cargo build --target x86_64-unknown-linux-musl). On glibc hosts, -C target-feature=+crt-static alone does not produce a fully static binary. Not practical for interpreted languages.
Debugging without a shell (Linux hosts only): nsenter runs host binaries inside a container's namespace. This does not work on macOS or Windows — Docker Desktop runs containers in a VM whose PIDs aren't accessible from the host.
# Requires root on the host; -n enters the network namespace only
PID=$(docker inspect -f '{{.State.Pid}}' container_name)
[ "$PID" -gt 0 ] && sudo nsenter -t "$PID" -n ss -tulpn || echo "container not running"The -n flag is the least-privileged option — it only enters the network namespace. Avoid -a or -m in production; they give full filesystem and process access, equivalent to docker exec as root.
Build Cache Optimization
Order Dockerfile instructions from least-changing to most-changing:
- Base image (
FROM) - System packages (
RUN apt-get install) - Dependency manifests (
COPY package*.json ./) - Dependency install (
RUN npm ci) - Application code (
COPY . .) - Build step (
RUN npm run build)
BuildKit cache mounts (avoid reinstalling packages on every build):
# npm — cache must be explicitly pointed to the mount target with npm ci
RUN --mount=type=cache,target=/root/.npm \
npm ci --cache /root/.npm
# pip
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
# Go
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -o /app/serverBind mounts for build-only files (don't copy into the layer):
RUN --mount=type=bind,source=requirements.txt,target=/tmp/requirements.txt \
pip install --requirement /tmp/requirements.txt.dockerignore
Always create .dockerignore at the build context root. Unlike .gitignore, Docker only reads one .dockerignore at the context root — subdirectory ignore files are not respected.
.git
.gitignore
node_modules
.env
.env.*
*.log
dist
.next/cache
__pycache__
*.pyc
.pytest_cacheOmitting .dockerignore means COPY . . sends your entire git history, local node_modules, and .env files into the build context — slowing builds and risking secret leakage.
CMD vs ENTRYPOINT
Use exec form (JSON array) for both. Shell form (CMD npm start) wraps the command in /bin/sh -c, making the shell the PID 1 process. The shell doesn't forward SIGTERM to child processes, so docker stop kills the container forcefully instead of gracefully.
# Shell form — PID 1 is /bin/sh, signals not forwarded
CMD npm run start
# Exec form — PID 1 is npm, SIGTERM forwarded correctly
CMD ["npm", "run", "start"]ENTRYPOINT vs CMD:
ENTRYPOINT— fixed executable, not easily overridden at runtimeCMD— default arguments, easily overridden withdocker run <image> <args>- Combined:
ENTRYPOINTsets the executable,CMDprovides default args that can be overridden
# Image acts as a CLI tool
ENTRYPOINT ["s3cmd"]
CMD ["--help"] # default: show help; override: docker run myimage ls s3://bucketRunning as Non-Root
Always include a USER directive in production Dockerfiles. Docker defaults to root (UID 0), which carries capabilities like cap_chown and cap_net_raw that can be exploited if a process is compromised. Combine USER with no-new-privileges=true and cap_drop: [ALL] in Compose to fully eliminate capability escalation paths — a non-root process's effective capabilities are empty, but the permitted set is still inherited from the container's bounding set without these.
Create a dedicated user and switch to it:
# Alpine / BusyBox
RUN addgroup -g 65534 appgroup && \
adduser -u 65534 -G appgroup -D -H appuser
# Debian / Ubuntu
RUN groupadd --gid 65534 appgroup && \
useradd --uid 65534 --gid appgroup --no-create-home --shell /sbin/nologin appuser
USER 65534:65534Or skip user creation entirely and use USER 65534:65534 with a numeric UID — the user doesn't need to exist in /etc/passwd for most applications.
Place USER as the last directive before ENTRYPOINT/CMD. Using numeric UID:GID (not name) works in distroless images that lack /etc/passwd entries.
Volume permissions: Files written by the container will be owned by UID 65534 on the host. Two options:
chown 65534:65534 /host/pathbefore mounting- Override in Compose with
user: "1000:1000"to match your host UID
Compose hardening:
services:
app:
image: myapp:1.0.0
user: "65534:65534"
security_opt:
- no-new-privileges=true # prevents setuid/setgid escalation
cap_drop:
- ALL # drop all capabilities; add back specific ones if needed
read_only: true # optional: make root filesystem read-only
tmpfs:
- /tmp # writable scratch space if neededno-new-privileges=true prevents the process from gaining additional privileges via setuid binaries or file capabilities — a defense-in-depth measure even when already running as non-root.
PUID/PGID images: Images using PUID/PGID environment variables (common in LinuxServer.io images) still start the entrypoint as root before dropping privileges. Prefer images that set USER to never run as root at all.
Kubernetes: Clusters can enforce non-root at the pod level with securityContext.runAsNonRoot: true — containers that would run as UID 0 will fail to start with a RunAsNonRoot violation error.
Docker Compose
Use Compose for local development and simple self-hosted deployments. It is not a substitute for Kubernetes: no self-healing, no rolling updates, no secret management, single-machine only.
Canonical file name: compose.yaml (preferred) or docker-compose.yaml. Docker Compose looks for these automatically in the current directory.
Minimal production-ready Compose file
name: my_app
services:
db:
image: postgres:17-bookworm
container_name: postgres_db
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} # read from .env file
# Alternative: env_file loads all vars from file; if both are set, 'environment' takes precedence
# env_file: .env
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
retries: 5
start_period: 30s
timeout: 5s
networks:
- internal # no ports published — DB is only reachable from web via internal network
web:
build: .
depends_on:
db:
condition: service_healthy # wait for DB to be ready, not just started
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/app
networks:
- internal # can reach db
- default # can reach internet (for external API calls, etc.)
volumes:
postgres_data:
networks:
internal:
driver: bridge
internal: true # no internet — db is only reachable from web, not from outside
default: {} # standard bridge with internet access for webKey patterns:
- Use
depends_onwithcondition: service_healthy(not justservice_started) to avoid race conditions - Never hardcode secrets in
compose.yaml— use${VAR}with.envfile orenv_file - Use named volumes (not bind mounts) for database data — named volumes survive
compose down compose downremoves containers and networks but not volumes; add--volumesto also remove data
Compose commands
docker compose up --detach # start all services in background
docker compose up --detach --build # rebuild images before starting
docker compose down # stop and remove containers + networks
docker compose down --volumes # also remove named volumes (⚠ DESTROYS all volume data — irreversible)
docker compose logs -f web # stream logs for a service
docker compose ps # list running services
docker compose exec db psql -U postgres # shell into a running service
docker compose watch # rebuild/sync on file changes (dev mode)
docker compose -f custom.yaml up # use a non-default compose file
docker compose -p myproject ps # target a project by nameFor Docker daemon hardening (log rotation, storage, network subnets), see references/daemon-config.md.
Container Lifecycle (CLI Essentials)
# Run a stateful service (database) — no --rm, container survives stops
docker container run \
--detach \
--name postgres_db \
--env POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ # use env var — never hardcode; visible in docker inspect
--volume postgres_data:/var/lib/postgresql/data \
--publish 127.0.0.1:5432:5432 \ # bind to localhost only — 0.0.0.0 exposes to all interfaces
postgres:17-bookworm
# Run an ephemeral one-off task — --rm auto-removes when done
docker container run --rm -it ubuntu:24.04 bash
# Inspect and debug
docker container logs -f <name> # stream logs
docker container exec -it <name> /bin/bash # interactive shell
docker container inspect <name> # full JSON metadata
docker container stats <name> # live CPU/memory/network metrics
# Lifecycle
docker container stop <name> # SIGTERM → SIGKILL after timeout
docker container start <name>
docker container restart <name>
docker container rm <name> # remove stopped container
docker container prune # remove all stopped containersExpose vs publish: EXPOSE in a Dockerfile is documentation only — it doesn't make the port accessible. --publish (or -p) at runtime maps a container port to the host. A service can be accessible without EXPOSE if you publish the port.
Volumes and Networks
# Volumes
docker volume create postgres_data
docker volume inspect postgres_data
docker volume rm postgres_data
docker volume prune --all # ⚠ removes ALL unused volumes on this host, across all projects
# Networks
docker network create --driver bridge --internal no_internet
docker network connect no_internet my_container
docker network disconnect no_internet my_container
docker network inspect no_internetUser-defined bridge networks (not the default bridge) enable DNS resolution by container name. Containers on the same user-defined network can reach each other at http://container-name:port. The default bridge network does not support this.
Named Volumes with Remote Backends
Named volumes aren't limited to local disk. The local driver accepts driver_opts to mount NFS shares, CIFS/SMB shares, or tmpfs:
Host prerequisites: NFS requires
nfs-common(Debian/Ubuntu) ornfs-utils(RHEL/Alpine). CIFS requirescifs-utils. Without these,docker compose upfails with a cryptic mount error.
volumes:
# NFS share
nfs_data:
driver: local
driver_opts:
type: nfs
o: "addr=192.168.1.30,nolock,hard,timeo=600,retrans=3,nfsvers=4"
device: ":/volume1/appdata"
# CIFS/SMB share
smb_data:
driver: local
driver_opts:
type: cifs
o: "username=svc_user,password=${SMB_PASSWORD},uid=65534,gid=65534,vers=3.0"
device: "//192.168.1.40/appdata"
# tmpfs (in-memory, cleared on restart — good for scratch/cache)
tmp_cache:
driver: local
driver_opts:
type: tmpfs
device: tmpfs
o: "size=256m,uid=65534,gid=65534"NFS mount modes: Use
hard(shown above) for stateful workloads — databases, write-ahead logs, anything usingfsync. Ahardmount retries indefinitely rather than returning errors on transient network blips. Usesoftonly for read-heavy or cache workloads where data loss is tolerable — a timed-outsoftwrite may be partially committed, corrupting data.
CIFS credentials: Credentials passed via
driver_optsare stored in plaintext in Docker's volume metadata (visible viadocker volume inspect). For production, use a credentials file with restricted permissions (chmod 600) mounted separately, rather than embedding the password in volume options.
Prefer named volumes over bind mounts. Docker manages creation, permissions, and quotas. Use bind mounts only when you need a specific host path (e.g., /etc/localtime, a hardware device, or a path managed by another tool).
Building and Tagging Images
# Build
docker buildx build \
--platform linux/amd64 \ # target platform (default: host arch)
--tag registry.example.com/myapp:1.2.3 \
--file path/to/Dockerfile \
./build-context/
# Tag format: <registry-host>/<namespace>/<repository>:<version>
# Avoid 'latest' — use semantic versions or git SHAs
# Inspect
docker image inspect myapp:1.2.3
docker image history myapp:1.2.3 # show layers and sizes
# Use 'dive' for interactive layer exploration
# Cleanup
docker image prune --all # ⚠ removes ALL unused images — next start requires re-pulling from registryContainer Registries
See references/registries.md for registry-specific setup (AWS ECR, Scaleway, Docker Hub).
Login pattern:
# Generic (POSIX-portable)
echo "$TOKEN" | docker login --username <user> --password-stdin <registry-host>
# AWS ECR (token expires after 12 hours)
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin \
<account-id>.dkr.ecr.us-east-1.amazonaws.com
# Push workflow
docker tag myapp:1.2.3 registry.example.com/ns/myapp:1.2.3
docker push registry.example.com/ns/myapp:1.2.3Tag immutability: Enable it on private registries (AWS ECR supports this). Mutable tags mean two different images can share the same tag — a silent source of "works on my machine" bugs.
Credentials are stored in ~/.docker/config.json (pointing to the OS keychain). View registered registries: cat ~/.docker/config.json. Log out: docker logout <registry-host>.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

