Docker containerization guide covering Dockerfile authoring, multi-stage builds, image optimization, security hardening, Docker Compose for local development, and .dockerignore best practices. Use PROACTIVELY when creating or editing Dockerfiles, docker-compose.yml files, containerizing an application, or troubleshooting Docker build and runtime issues. **PROACTIVE ACTIVATION**: Invoke on Dockerfile, docker-compose, 'containerize', 'docker build', 'container won't start', or any task involving images, volumes, or container networking. **USE CASES**: New Dockerfile, optimizing image size, adding health checks, setting up multi-service local dev environment, fixing build failures, securing containers.
Before writing anything, understand the environment:
docker --version
find . -name "Dockerfile*" -type f
find . -name "*compose*.yml" -o -name "*compose*.yaml" | head -5
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | head -10
Separate the build environment from the runtime environment to keep production images small:
# Stage 1: install dependencies
FROM node:22-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# Stage 2: build
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 3: production runtime (minimal)
FROM node:22-alpine AS runtime
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
WORKDIR /app
COPY --from=deps --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=build --chown=appuser:appgroup /app/dist ./dist
COPY --from=build --chown=appuser:appgroup /app/package*.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "dist/index.js"]
Copy dependency manifests before source code so Docker reuses cached layers on every code change:
# Good — dependencies cached separately from source
COPY package*.json ./
RUN npm ci
COPY . .
# Bad — cache busted on every source change
COPY . . # ❌
RUN npm ci
Always run as a non-root user:
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
# ... copy files with --chown=appuser:appgroup
USER appuser
Never put secrets in ENV or ARG — they appear in docker history:
# Bad
ENV API_KEY=secret123 # ❌ visible in image layers
# Good — use BuildKit mount secrets
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) && do-something-with-key
RUN --mount=type=cache,target=/root/.npm \
npm ci --only=production
Always create .dockerignore to keep build context small and avoid leaking secrets:
.git
.env*
node_modules
dist
*.log
.DS_Store
README.md
coverage/
.github/