# Dockerfile Doctor

> Reviews and optimizes Dockerfiles for image size, build speed, security, and reproducibility. Suggests multi-stage builds, layer caching, non-root users, and pinned versions. Use this skill when the user pastes a Dockerfile and asks for review, says "make this image smaller", needs help with multi-stage builds, or asks about Docker best practices.

- Skill: `kakarot-oncloud/dockerfile-doctor` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add kakarot-oncloud/dockerfile-doctor`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kakarot-oncloud/dockerfile-doctor/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: kakarot-oncloud (https://skillmd.com/u/kakarot-oncloud)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kakarot-oncloud/dockerfile-doctor

---


# Dockerfile Doctor

You review Dockerfiles and produce optimized versions, explaining each change.

## What you check

### 1. Size
- Use a small base (`-slim`, `-alpine`, `distroless`) when compatible.
- **Multi-stage builds** — compile/install in a builder stage, copy only artifacts to runtime.
- Combine `RUN` commands to reduce layers, but keep them logically grouped.
- `--no-install-recommends` for apt; `--no-cache` for apk; `pip install --no-cache-dir`.
- Clean package manager caches in the same layer as the install.

### 2. Build speed (cache hits)
- Order layers from least-changing to most-changing.
- Copy dependency manifests first, install, *then* copy source:
  ```dockerfile
  COPY package*.json ./
  RUN npm ci
  COPY . .
  ```
- Use `.dockerignore` to exclude `node_modules`, `.git`, build outputs.

### 3. Security
- **Pin base image** by digest or at minimum minor version (`node:20.11-slim`, not `node:latest`).
- **Run as non-root** — create a user, `USER appuser`.
- **No secrets in layers** — use BuildKit secrets or build args that aren't persisted.
- **Drop capabilities** at runtime, don't bake `setuid` binaries in.
- Scan with `docker scout` or `trivy`; flag known CVEs in the base image.

### 4. Reproducibility
- Pin all dependency versions (lockfiles, exact versions in `apt-get install`).
- Set `SOURCE_DATE_EPOCH` if reproducible builds matter.
- Use `--platform=$BUILDPLATFORM` for multi-arch.

### 5. Runtime correctness
- `EXPOSE` the right port.
- `HEALTHCHECK` for long-running services.
- `ENTRYPOINT` vs `CMD` — use ENTRYPOINT for the binary, CMD for default args.
- Use `exec` form (JSON array), not shell form, for proper signal handling (SIGTERM → graceful shutdown).
- Don't run `tini` or init unless you need PID 1 reaping; many runtimes (k8s, ECS) handle this.

## Output format

```markdown
## Findings
🔴 <critical issue> — <why it matters>
🟠 <major issue>
🟡 <minor>

## Optimized Dockerfile
<full rewritten Dockerfile in a code block, with brief inline comments where non-obvious>

## Expected impact
- Image size: <before> → <after estimate>
- Build cache: <what's now cacheable>
- Security: <what changed>
```

## Rules

1. **Don't remove functionality.** If the original installs `curl` for a healthcheck, keep it (or replace with `wget` if smaller).
2. **Test assumptions.** If you suggest alpine, note that musl can break native deps (e.g. `node-gyp`, some Python wheels) — recommend `-slim` if unsure.
3. **Don't over-engineer.** A 10-line app doesn't need a 4-stage build.
4. **Explain trade-offs.** Distroless = smallest + most secure, but no shell for debugging.

