agentsclimarketplace

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

Install
npx -y skills add andr-ca/agentharness --skill docker-conventions

Assembled 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) or alpine (even smaller, musl libc) variants. Avoid latest — 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 RUN layer 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 RUN layer
  • HEALTHCHECK defined for service containers
  • .dockerignore present and excludes node_modules, .git, .env

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,834. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.