home / skills / yldgio / codereview-skills / docker
This skill guides Dockerfile best practices, security hardening, and multi-stage builds to optimize images and reduce risk.
npx playbooks add skill yldgio/codereview-skills --skill dockerReview the files below or copy the command above to add this skill to your agents.
---
name: docker
description: Dockerfile best practices, security hardening, multi-stage builds, and image optimization
---
## Docker Code Review Rules
### Security (Critical)
- Run as non-root user (`USER` directive)
- Don't store secrets in image (use runtime injection)
- Don't use `--privileged` without justification
- Scan images for vulnerabilities
- Set `readonly` root filesystem where possible
- Review any use of build-time variables (e.g., `ARG`, `ENV`, `LABEL` values) that can be influenced by external inputs (such as `--build-arg` values or CI/CD environment variables sourced from untrusted users) to ensure they are not used in a way that enables build-time injection
- Never use HTML comments (`<!-- -->`) in Dockerfiles
### Base Images
- Pin base image to specific version (not `latest`)
- Use official images from trusted sources
- Prefer minimal images (`alpine`, `slim`, `distroless`)
- Regularly update base images for security patches
### Build Optimization
- Use multi-stage builds to reduce final image size
- Order instructions by change frequency (cache optimization)
- Combine `RUN` commands to reduce layers
- Use `.dockerignore` to exclude unnecessary files, sensitive data, and build artifacts like `node_modules`
### Instructions (Essential)
- Use `COPY` instead of `ADD` (unless extracting archives)
- Set `WORKDIR` before `COPY`/`RUN`
- Use explicit `EXPOSE` for documentation
- Set meaningful `LABEL` metadata
### Additional Instructions
- Explicitly set `SHELL` if bash/sh features are needed
- Set environment variables with `ENV` for configuration (not secrets)
- Clean up package manager caches after install (e.g., `apt-get clean`)
- Understand `ENTRYPOINT` vs `CMD`: use `ENTRYPOINT` for main command, `CMD` for default args
- Document container usage with OCI labels (`org.opencontainers.image.*`)
### Health Checks
- Include `HEALTHCHECK` instruction
- Health check should verify app is actually working
- Set appropriate interval and timeout
### Example Good Dockerfile Pattern
```dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Runtime stage
FROM node:20-alpine
# Add OCI labels for documentation
LABEL org.opencontainers.image.title="My App"
LABEL org.opencontainers.image.description="Production web application"
LABEL org.opencontainers.image.version="1.0.0"
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# Copy dependencies and app files
COPY --from=builder /app/node_modules ./node_modules
COPY . .
# Set environment variables (not secrets)
ENV NODE_ENV=production
USER appuser
EXPOSE 3000
HEALTHCHECK CMD wget -q --spider http://localhost:3000/health || exit 1
# Use ENTRYPOINT for main command, CMD for default args
ENTRYPOINT ["node"]
CMD ["server.js"]
```
This skill provides actionable Dockerfile best practices focused on security hardening, multi-stage builds, and image optimization. It guides reviewers and authors to produce smaller, safer, and more maintainable container images. The guidance balances security controls, build performance, and runtime reliability.
The skill inspects Dockerfile patterns and recommends concrete changes: pinning base images, enforcing non-root execution, minimizing layers with multi-stage builds, and removing secrets from images. It highlights risky constructs (privileged mode, build-time injection vectors, ADD misuse) and suggests fixes like .dockerignore, cache-friendly instruction ordering, and health checks. Output is practical advice you can apply directly to CI/CD pipelines or code reviews.
Should I ever use ADD?
Only when you need its archive extraction or remote URL fetch behavior; prefer COPY for predictable file copying.
How do I manage secrets if not in the image?
Inject secrets at runtime via environment variables managed by your orchestrator, secret mounts, or a secrets manager; never bake them into ENV or source files.