| name | docker |
| description | Containerization principles — multi-stage builds, base image selection, layer caching, security. Use when containerizing a service, shrinking a bloated image, chasing CVEs in a base image, adding non-root + distroless to an existing Dockerfile, or reviewing any `Dockerfile` / `.dockerignore` changes. Trigger on any task mentioning "docker", "container", "image", "base image", or "deploy to kubernetes" — even when the user does not explicitly say "use the docker skill". Pair with language-specific docker skill for build patterns.
|
Docker
Build small, secure, production-ready containers.
When to Use
- Containerizing an application for production
- Optimizing Docker image size or build time
- Reviewing Dockerfiles for security and best practices
- Setting up CI/CD container pipelines
When NOT to Use
- Local development without containers
- Writing language-specific build stages (use
<lang>/docker skill)
Core Process
- Choose base image — smallest image that meets runtime needs
- Multi-stage build — build in SDK image, run in minimal image
- Optimize layers — dependency manifests first, source code last
- Secure the image — non-root user, no secrets in layers, pinned versions
- Add health checks — container orchestrators need them
- Configure .dockerignore — reduce build context
- Verify — build, check size, run as non-root, test health check
Base Image Selection
| Image Type | Size | Use Case |
|---|
| scratch | ~0MB | Static binaries only |
| distroless/static | ~2MB | Static binaries, better debugging |
| distroless/base | ~20MB | Binaries needing libc |
| alpine | ~5MB | Need shell/debugging tools |
| debian:slim | ~70MB | Complex dependencies |
Default: distroless/static for production. Alpine for development/debugging.
Multi-Stage Builds
- Build stage: full SDK/toolchain, compile application
- Runtime stage: minimal image, copy only binary/artifacts
Size reduction: 90-95% vs single-stage builds.
Layer Caching
Order for maximum cache reuse:
- Copy dependency manifests (changes infrequently)
- Install dependencies
- Copy source code (changes frequently)
- Build
Code-only changes reuse cached dependency layers.
Security Checklist
- Non-root user: always run as non-root (UID 65532 standard)
- Pin versions: never
:latest — pin base image versions + digests
- No secrets in layers: use
--mount=type=secret, not ARG/ENV
- Minimal runtime: no shells, package managers, or unnecessary tools
- Scan for vulnerabilities: run image scanning in CI
.dockerignore
Exclude: .git, docs, tests, IDE files, .env, build artifacts, node_modules/vendor, Dockerfile itself.
Health Checks
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD ["/app", "healthcheck"]
Build Metadata
Use OCI labels and build args for version, commit, build date. Enables traceability from running container back to source.
Image Size Targets
| Application Type | Target Size |
|---|
| Static binary (Go, Rust) | <20MB |
| Node.js | <150MB |
| Python | <200MB |
| Java | <250MB |
If significantly over target, investigate unnecessary dependencies or wrong base image.
Common Rationalizations
| Shortcut | Reality |
|---|
| "Just use :latest" | Unpinned images break reproducibility. Pin versions + digests. |
| "Root is easier" | Root in containers = privilege escalation risk. Always non-root. |
| "One stage is simpler" | Single-stage ships the entire SDK. Multi-stage shrinks 90-95%. |
| "Security scanning is overkill" | Known CVEs in base images are free attack surface. Scan in CI. |
Red Flags
:latest or unpinned base image tags
- Running as root
- Secrets in ARG/ENV (persisted in layer history)
- Single-stage build shipping SDK/toolchain to production
- No .dockerignore (sending entire repo as build context)
- No HEALTHCHECK defined
- Image significantly over size target
Verification