Docker Expert
Create containers that are small, secure, and predictable across local and CI environments.
When to Use
- You are creating or hardening a
Dockerfile.
- Builds are slow, non-reproducible, or failing in CI.
- Runtime behavior differs between local machine and container.
Workflow
Base image selection: Prefer alpine for minimal size when musl compatibility is acceptable; use distroless for maximum security (no shell, minimal attack surface); use debian-slim when glibc or common tools are required. Pin major.minor version (e.g. node:20-alpine3.19) and avoid latest.
Multi-stage builds: Use a builder stage for compilation and a minimal runtime stage. Copy only artifacts with COPY --from=builder:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
FROM node:20-alpine
RUN addgroup -g 1000 app && adduser -u 1000 -G app -D app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER app
CMD ["node", "dist/index.js"]
Layer ordering: Copy dependency manifests (package.json, requirements.txt, go.mod) before source code. Install dependencies in a separate RUN. This maximizes cache reuse when only source changes.
BuildKit cache mounts: For package managers, use cache mounts to speed repeated builds:
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=dev
Configure .dockerignore: Exclude node_modules, .git, .env*, *.log, and build artifacts. Missing entries bloat context and can leak secrets.
Non-root execution: Create a dedicated user, set USER, and use explicit WORKDIR. Prefer CMD with exec form ["executable", "arg1"] over shell form for proper signal handling.
Compose: Define depends_on with condition: service_healthy where applicable. Use env files for overrides, not hardcoded values.
Common Pitfalls
- apt-get without cleanup: Always combine
apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/* in one RUN to avoid bloating layers.
- COPY . before dependency install: Copying source before
npm install or pip install invalidates cache on every code change. Copy manifests first, install, then copy source.
- Missing
.dockerignore: Without it, node_modules, .git, and local .env can be sent as build context, causing slow builds and potential secret leakage.
- ENTRYPOINT without signal handling: Use exec form so PID 1 receives SIGTERM. Wrap scripts with
exec or use tini/dumb-init if a shell script is required.
- ADD vs COPY: Prefer
COPY; ADD has URL and archive-extraction behavior that can surprise. Use COPY for deterministic, explicit behavior.
Security Hardening
- Scan images: Run
trivy image <image> or grype <image> in CI. Fix critical/high CVEs before release.
- Read-only root filesystem: Add
securityContext: { readOnlyRootFilesystem: true } in Kubernetes; ensure writable paths use tmpfs or volumes.
- Drop capabilities: Run with
--cap-drop=ALL and add back only what is needed. Avoid --privileged.
- Minimal base: Prefer distroless or alpine. Fewer packages mean fewer vulnerabilities.
Quality Checklist
Output Format
Return:
- Recommended
Dockerfile/Compose changes with inline examples where helpful
- Build commands:
docker build -t <tag> . and verification: docker run --rm <tag>
- Security scan commands:
trivy image <tag> or equivalent
- Performance and security risks identified
- Follow-up hardening tasks (scan results, capability drops, read-only FS)
Constraints
- Avoid
latest tags in production workflows.
- Prefer deterministic lockfile-based installs (
npm ci, pip install -r requirements.txt with pinned versions).
- Do not rely on host-specific paths or tooling assumptions.
- Do not use
ADD when COPY suffices.
- Ensure entrypoint/CMD use exec form for proper signal propagation.
1---2name: docker-expert3description: Use this skill when containerizing services or debugging Docker workflows, including production Dockerfiles, Compose setups, reproducible builds, secure defaults, image size, caching, and runtime behavior.4---56# Docker Expert78Create containers that are small, secure, and predictable across local and CI environments.910## When to Use1112- You are creating or hardening a `Dockerfile`.13- Builds are slow, non-reproducible, or failing in CI.14- Runtime behavior differs between local machine and container.1516## Workflow17181. **Base image selection**: Prefer `alpine` for minimal size when musl compatibility is acceptable; use `distroless` for maximum security (no shell, minimal attack surface); use `debian-slim` when glibc or common tools are required. Pin major.minor version (e.g. `node:20-alpine3.19`) and avoid `latest`.19202. **Multi-stage builds**: Use a builder stage for compilation and a minimal runtime stage. Copy only artifacts with `COPY --from=builder`:2122```dockerfile23FROM node:20-alpine AS builder24WORKDIR /app25COPY package*.json ./26RUN npm ci --omit=dev27COPY . .28RUN npm run build2930FROM node:20-alpine31RUN addgroup -g 1000 app && adduser -u 1000 -G app -D app32COPY --from=builder /app/dist ./dist33COPY --from=builder /app/node_modules ./node_modules34USER app35CMD ["node", "dist/index.js"]36```37383. **Layer ordering**: Copy dependency manifests (`package.json`, `requirements.txt`, `go.mod`) before source code. Install dependencies in a separate RUN. This maximizes cache reuse when only source changes.39404. **BuildKit cache mounts**: For package managers, use cache mounts to speed repeated builds:4142```dockerfile43RUN --mount=type=cache,target=/root/.npm \44 npm ci --omit=dev45```46475. **Configure `.dockerignore`**: Exclude `node_modules`, `.git`, `.env*`, `*.log`, and build artifacts. Missing entries bloat context and can leak secrets.48496. **Non-root execution**: Create a dedicated user, set `USER`, and use explicit `WORKDIR`. Prefer `CMD` with exec form `["executable", "arg1"]` over shell form for proper signal handling.50517. **Compose**: Define `depends_on` with `condition: service_healthy` where applicable. Use env files for overrides, not hardcoded values.5253## Common Pitfalls5455- **apt-get without cleanup**: Always combine `apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/*` in one RUN to avoid bloating layers.56- **COPY . before dependency install**: Copying source before `npm install` or `pip install` invalidates cache on every code change. Copy manifests first, install, then copy source.57- **Missing `.dockerignore`**: Without it, `node_modules`, `.git`, and local `.env` can be sent as build context, causing slow builds and potential secret leakage.58- **ENTRYPOINT without signal handling**: Use exec form so PID 1 receives SIGTERM. Wrap scripts with `exec` or use `tini`/`dumb-init` if a shell script is required.59- **ADD vs COPY**: Prefer `COPY`; `ADD` has URL and archive-extraction behavior that can surprise. Use `COPY` for deterministic, explicit behavior.6061## Security Hardening6263- **Scan images**: Run `trivy image <image>` or `grype <image>` in CI. Fix critical/high CVEs before release.64- **Read-only root filesystem**: Add `securityContext: { readOnlyRootFilesystem: true }` in Kubernetes; ensure writable paths use tmpfs or volumes.65- **Drop capabilities**: Run with `--cap-drop=ALL` and add back only what is needed. Avoid `--privileged`.66- **Minimal base**: Prefer distroless or alpine. Fewer packages mean fewer vulnerabilities.6768## Quality Checklist6970- [ ] Final image excludes build tools and caches.71- [ ] Secrets are not baked into image layers.72- [ ] Ports, volumes, and env vars are explicitly documented.73- [ ] Image runs with least privilege.7475## Output Format7677Return:7879- Recommended `Dockerfile`/Compose changes with inline examples where helpful80- Build commands: `docker build -t <tag> .` and verification: `docker run --rm <tag>`81- Security scan commands: `trivy image <tag>` or equivalent82- Performance and security risks identified83- Follow-up hardening tasks (scan results, capability drops, read-only FS)8485## Constraints8687- Avoid `latest` tags in production workflows.88- Prefer deterministic lockfile-based installs (`npm ci`, `pip install -r requirements.txt` with pinned versions).89- Do not rely on host-specific paths or tooling assumptions.90- Do not use `ADD` when `COPY` suffices.91- Ensure entrypoint/CMD use exec form for proper signal propagation.