Claude-skill-registry dockerfile-best-practices
Create and optimize Dockerfiles with BuildKit, multi-stage builds, advanced caching, and security. Use when: (1) Creating new Dockerfile, (2) Optimizing existing Dockerfile, (3) Reducing image size, (4) Improving security, (5) Using Python with uv, (6) Resolving cache or slow build issues, (7) Setting up CI/CD builds
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dockerfile-best-practices" ~/.claude/skills/majiayu000-claude-skill-registry-dockerfile-best-practices && rm -rf "$T"
skills/data/dockerfile-best-practices/SKILL.mdDockerfile Best Practices
Comprehensive guide for creating optimized, secure, and fast Docker images using modern BuildKit features.
Quick Start Workflow
When working with Dockerfiles, follow this decision tree:
- Choose your language/framework → Use appropriate template below
- Apply security hardening → Non-root user, pin versions, secrets management
- Optimize for cache → Separate deps from code, use cache mounts
- Multi-stage if needed → Separate build from runtime for compiled languages
- Review with analyzer → Run
scripts/analyze_dockerfile.py
Essential Rules (Always Apply)
-
Start with BuildKit syntax:
# syntax=docker/dockerfile:1 -
Pin runtime versions, not OS versions:
# ✅ GOOD - Pin runtime, let OS update FROM python:3.12-slim # ❌ BAD - Pins OS version (bookworm), prevents security updates FROM python:3.12-slim-bookwormWhy? OS versions update with security patches. Pin runtime (python:3.12) for reproducible behavior.
-
Create
: Use template from.dockerignoreassets/dockerignore-template -
Use cache mounts for package managers:
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt -
APT cache setup (before any apt operations):
RUN rm -f /etc/apt/apt.conf.d/docker-clean; \ echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache -
Never use ARG/ENV for secrets:
RUN --mount=type=secret,id=api_key curl -H "Authorization: $(cat /run/secrets/api_key)" https://api.example.com -
Use non-root user with safe UID/GID:
# Let system auto-assign (simple) RUN groupadd -r app && useradd -r -g app app # Or use UID/GID >10000 for consistency across environments RUN groupadd -r -g 10001 app && useradd -r -u 10001 -g app app
Language-Specific Templates
Python (with uv - Recommended)
For detailed Python/uv integration, see
references/uv_integration.md.
# syntax=docker/dockerfile:1 FROM python:3.12-slim COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ WORKDIR /app # Install dependencies (separate layer for caching) RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --locked --no-install-project # Copy and install project COPY . . RUN --mount=type=cache,target=/root/.cache/uv \ uv sync --locked # Security: non-root user with UID/GID >10000 RUN groupadd -r -g 10001 app && \ useradd -r -u 10001 -g app app && \ chown -R app:app /app USER app ENV PATH="/app/.venv/bin:$PATH" CMD ["python", "-m", "myapp"]
Node.js
# syntax=docker/dockerfile:1 FROM node:20-alpine WORKDIR /app # Install dependencies COPY package.json yarn.lock ./ RUN --mount=type=cache,target=/root/.yarn \ yarn install --frozen-lockfile --production # Copy source COPY . . # Security: non-root user with UID/GID >10000 RUN addgroup -g 10001 app && \ adduser -u 10001 -G app -S app && \ chown -R app:app /app USER app EXPOSE 3000 CMD ["node", "index.js"]
Go (Multi-stage)
# syntax=docker/dockerfile:1 # Build stage FROM golang:1-alpine 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 -ldflags="-w -s" -o main # Runtime stage FROM alpine:3 RUN addgroup -g 10001 app && adduser -u 10001 -G app -S app USER app COPY --from=builder /app/main /main ENTRYPOINT ["/main"]
Debian-based (with APT cache)
# syntax=docker/dockerfile:1 FROM debian:stable-slim # Configure APT for cache reuse RUN rm -f /etc/apt/apt.conf.d/docker-clean; \ echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache WORKDIR /app # Install dependencies with cache mount RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt-get update && \ apt-get install -y --no-install-recommends curl ca-certificates # Copy application COPY . . # Security: non-root user with UID/GID >10000 RUN groupadd -r -g 10001 app && \ useradd -r -u 10001 -g app app && \ chown -R app:app /app USER app CMD ["./app"]
PHP (with Composer)
# syntax=docker/dockerfile:1 FROM php:8-fpm-alpine WORKDIR /app # Install Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Install dependencies COPY composer.json composer.lock ./ RUN --mount=type=cache,target=/tmp/cache \ composer install --no-dev --optimize-autoloader --no-scripts # Copy source COPY . . RUN composer dump-autoload --optimize # Security: non-root user with UID/GID >10000 RUN addgroup -g 10001 app && \ adduser -u 10001 -G app -S app && \ chown -R app:app /app USER app EXPOSE 9000 CMD ["php-fpm"]
Security Checklist
- Use specific version tags for base images
- Use minimal base image (alpine, slim, distroless)
- Create and use non-root user
- Never expose secrets via ARG/ENV
- Use
for sensitive dataRUN --mount=type=secret - Add HEALTHCHECK instruction
- Scan image for vulnerabilities (
)docker scan
Performance Checklist
- Add BuildKit syntax directive
- Create comprehensive
.dockerignore - Order instructions: manifests → deps → code
- Use
for all package managers--mount=type=cache - Implement multi-stage builds for compiled languages
- Chain RUN commands with
&& - Clean up in same RUN instruction
Size Optimization
Quick wins:
- Use alpine or slim variants
- Multi-stage builds
- Remove unnecessary files in same layer
- Use
with apt--no-install-recommends - Consider distroless for runtime
Common Patterns
Intermediate Layers (Faster Rebuilds)
Separate dependency installation from code copy:
# Install deps first (rarely changes) COPY package.json package-lock.json ./ RUN npm ci --production # Copy code (changes frequently) COPY . .
Remote Cache (CI/CD)
docker buildx build \ --cache-from=type=registry,ref=myregistry.com/app:cache \ --cache-to=type=registry,ref=myregistry.com/app:cache,mode=max \ --push \ -t myregistry.com/app:latest .
Secret Management
# Build with secret docker buildx build --secret id=api_key,src=./key.txt . # Or from environment docker buildx build --secret id=api_key,env=API_KEY .
Tools and Scripts
Analyze Dockerfile
python scripts/analyze_dockerfile.py ./Dockerfile
Detects common anti-patterns:
- Missing BuildKit syntax
- Using :latest tags
- ADD instead of COPY
- Missing cache mounts
- Secrets in ARG/ENV
- Missing non-root USER
- apt-get without cleanup
Generate .dockerignore
cp assets/dockerignore-template .dockerignore
Docker Compose Best Practices
For multi-container applications, follow modern Compose practices:
Key Rules
-
Don't use
field - Deprecated since Compose V2version:# ✅ GOOD - No version field services: app: image: myapp:1.0.0 -
Never use
- Prevents scaling and parallel environmentscontainer_name:# ✅ GOOD - Let Compose generate names services: app: image: myapp:1.0.0 # No container_name - allows scaling with --scale # Use project names for environment isolation: # docker compose -p myapp-dev up # docker compose -p myapp-test up -
Use specific image tags - Not
:latest -
Define health checks - For service dependencies
-
Set resource limits - Prevent resource exhaustion
For complete Compose guide, see
references/compose_best_practices.md.
Reference Documentation
For detailed information, consult these references:
- Complete optimization guide with BuildKit, caching, multi-stage buildsreferences/optimization_guide.md
- Checklist of all best practices with impact levelsreferences/best_practices.md
- Real-world before/after optimization examplesreferences/examples.md
- Python with uv package manager (recommended for Python)references/uv_integration.md
- Docker Compose modern practices (no version:, no container_name:)references/compose_best_practices.md
Common Issues and Solutions
Slow builds
- Add cache mounts:
RUN --mount=type=cache,target=... - Optimize layer ordering: deps before code
- Use remote cache in CI/CD
Large images
- Use multi-stage builds
- Switch to alpine/slim base images
- Clean up in same RUN instruction
- Remove dev dependencies
Security concerns
- Pin versions with SHA256
- Use non-root USER
- Never use ARG/ENV for secrets
- Use BuildKit secret mounts
- Scan with
docker scan
Cache invalidation
- Separate dependency installation from code
- Use
for manifests--mount=type=bind - Order instructions correctly
Examples by Use Case
CLI Tool
# syntax=docker/dockerfile:1 FROM python:3.12-alpine COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/ WORKDIR /app RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --locked --no-install-project COPY . . RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked ENV PATH="/app/.venv/bin:$PATH" ENTRYPOINT ["mytool"]
Web API
# syntax=docker/dockerfile:1 FROM node:20-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN --mount=type=cache,target=/root/.yarn yarn install --frozen-lockfile --production COPY . . RUN addgroup -g 10001 app && \ adduser -u 10001 -G app -S app && \ chown -R app:app /app USER app EXPOSE 3000 HEALTHCHECK --interval=30s CMD wget -qO- http://localhost:3000/health || exit 1 CMD ["node", "server.js"]
Static Site
# syntax=docker/dockerfile:1 FROM node:20-alpine AS builder WORKDIR /app COPY package.json yarn.lock ./ RUN --mount=type=cache,target=/root/.yarn yarn install --frozen-lockfile COPY . . RUN yarn build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 80
Build Commands Reference
# Basic build docker buildx build -t myapp:latest . # With cache from registry docker buildx build \ --cache-from=type=registry,ref=registry.com/myapp:cache \ --cache-to=type=registry,ref=registry.com/myapp:cache,mode=max \ -t myapp:latest . # With secrets docker buildx build \ --secret id=api_key,src=./key.txt \ -t myapp:latest . # Multi-platform docker buildx build \ --platform linux/amd64,linux/arm64 \ -t myapp:latest --push . # Target specific stage docker buildx build --target builder -t myapp:builder .
Next Steps
After creating your Dockerfile:
- Run analyzer:
python scripts/analyze_dockerfile.py Dockerfile - Test locally:
docker buildx build -t test . - Check size:
docker images test - Scan for vulnerabilities:
docker scout cves test - Profile build:
docker buildx build --progress=plain . 2>&1 | less