Production stage
FROM node:20-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules EXPOSE 3000 USER node CMD ["node", "dist/server.js"]
### Python multi-stage
```dockerfile
FROM python:3.12-slim AS builder
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install uv && uv sync --frozen --no-dev
COPY . .
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app /app
USER nobody
CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0"]
db: image: postgres:16-alpine environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD", "pg_isready"] interval: 5s timeout: 3s
redis: image: redis:7-alpine healthcheck: test: ["CMD", "redis-cli", "ping"]
volumes: pgdata:
</compose_dev>
<concurrent_runs>
Compose derives its **project name from the working directory**. Two concurrent runs that resolve to the *same* project name (parallel CI jobs, sibling git worktrees, the same repo checked out twice) share one namespace and clobber each other's containers, networks, and volumes.
- Pass a unique `-p <name>` (or `COMPOSE_PROJECT_NAME=<name>`) per invocation, or serialize the runs.
- The `--exit-code-from`/`--abort-on-container-exit` integration pattern is especially exposed: the second run tears down the first's `test` container mid-flight, so its result is bogus (SIGKILL, not a real pass/fail).
</concurrent_runs>
<security>
Universal Docker security guardrails (pin base, non-root, no secrets in image, .dockerignore, minimal base, drop capabilities) live in `~/.claude/rules/infrastructure/RULE.md`. Multi-stage build examples and Compose-specific operational guidance are in `<compose_dev>` / `<volume_strategies>` below.
</security>
<volume_strategies>
| Type | Use For |
|------|---------|
| Named volume | Persistent data (databases) |
| Bind mount | Source code hot reload (dev only) |
| Anonymous volume | Preserve container-managed dirs (node_modules) |
</volume_strategies>
<anti_patterns>
Core Docker guardrails live in `~/.claude/rules/infrastructure/RULE.md`; the Compose/dev anti-patterns specific to this skill are covered in the sections above.
</anti_patterns>
<success_criteria>
- [ ] Multi-stage build (separate build/production stages)
- [ ] Non-root user in production
- [ ] Health checks defined
- [ ] `.dockerignore` excludes sensitive files
- [ ] Base images pinned to specific versions
</success_criteria>