Docker conventions
Skill andr-ca/agentharness/.claude/skills/docker-conventions
Use when writing a Dockerfile, docker-compose file, or CI containerization config — multi-stage builds, layer caching, security (non-root user, minimal base images, no secrets in layers), and health checks.From its SKILL.md
npx -y skills add andr-ca/agentharness --skill docker-conventionsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.8 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it
Docker Conventions
Best practices for Dockerfiles and container configurations. Focus areas: image size, build cache efficiency, security, and production readiness.
Base images
- Use official images with a pinned version tag:
python:3.12-slim,node:22-alpine,golang:1.24-alpine. - Prefer
slim(Debian-based, small) oralpine(even smaller, musl libc) variants. Avoidlatest— it changes without notice. - For production, prefer distroless or scratch (Go static binaries) to minimise the attack surface.
# Good: specific version, minimal base
FROM python:3.12-slim
# Bad: unpinned, full Debian base
FROM python:latest
Multi-stage builds
Use multi-stage builds to keep the production image small — the build tools (compilers, test runners, dev dependencies) stay in the build stage and never reach the final image.
# Stage 1: build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: production
FROM node:22-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]
Layer caching
Docker caches layers until a layer (or one of its inputs) changes. Copy dependency files before source code so the dependency install step is cached across code-only changes.
# Good: dependency install cached when only code changes
COPY package*.json ./
RUN npm ci
COPY . . # ← only invalidates layers from here down
# Bad: copies all source first — dependency install re-runs on every code change
COPY . .
RUN npm install
Security
Never embed secrets in a Dockerfile or in a layer. Secrets baked into a layer remain accessible in the image history even if deleted in a later layer.
# WRONG: secret in a layer (visible via `docker history`)
RUN echo "API_KEY=abc123" > /app/.env
# RIGHT: pass secrets at runtime via environment variable or a secret mount
# docker run -e API_KEY=$API_KEY ...
# or use BuildKit secrets for build-time:
RUN --mount=type=secret,id=api_key cat /run/secrets/api_key > /tmp/key
Run as a non-root user. Containers running as root have unnecessary privileges; if the process is compromised, the attacker has root inside the container.
# Create a non-root user and switch to it
RUN addgroup --system app && adduser --system --ingroup app app
USER app
Minimal attack surface:
- Remove package manager caches in the same
RUNlayer that installs packages:apt-get install -y ... && rm -rf /var/lib/apt/lists/* - Don't install
curl,wget, or debugging tools in production images.
Health checks
Add a HEALTHCHECK so the orchestrator (Docker Compose, Kubernetes) can
detect when the container is running but unhealthy.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:3000/health || exit 1
.dockerignore
Always provide a .dockerignore. Without it, COPY . . sends your
entire working directory (including node_modules, .git, and build
artifacts) to the Docker daemon.
.git
.env
*.env
node_modules
__pycache__
.venv
dist
build
*.log
docker-compose for local development
services:
app:
build:
context: .
target: development # use the dev stage of a multi-stage build
ports:
- "3000:3000"
volumes:
- .:/app # mount source for hot-reload
- /app/node_modules # anonymous volume prevents host override
environment:
- NODE_ENV=development
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
retries: 5
volumes:
postgres_data:
Review checklist
- Base image pinned to a specific version tag (not
latest) - Multi-stage build separates build tools from the final image
- Dependency files copied before source code for cache efficiency
- No secrets in Dockerfile or image layers; use runtime env vars
- Container runs as a non-root user
- Package manager cache cleaned in the same
RUNlayer -
HEALTHCHECKdefined for service containers -
.dockerignorepresent and excludesnode_modules,.git,.env
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.