dockerfile-optimizer
active0xa5d28a1dc7881ecc7feae0d6b7167fd6168056a757cdeab1d101d04af02c878e
Analyze and optimize Dockerfiles: reduce image size, improve build cache usage, fix security issues (running as root, secrets in layers), apply multi-stage patterns, pin versions, and lint against best practices. Returns optimized Dockerfile + explanation of every change.
Skill body
Dockerfile Optimizer
Analyze, lint, and optimize Dockerfiles for size, cache efficiency, and security.
Procedure
1. Parse the Dockerfile
Read and parse each instruction. Track:
- Base image and its size
- Layer count and estimated sizes
- Cache-busting patterns
- Dependency installation steps
- COPY/ADD patterns
- User and permissions
- Exposed ports and volumes
2. Size optimization checks
a) Base image selection:
| Current Base | Suggested Alternative | Savings |
|---------------------|---------------------------|---------------|
| ubuntu:22.04 | debian:bookworm-slim | ~50MB |
| debian:bookworm | debian:bookworm-slim | ~30MB |
| node:20 | node:20-slim or alpine | 600MB-900MB |
| python:3.12 | python:3.12-slim | ~700MB |
| python:3.12-slim | python:3.12-alpine | ~80MB (risky) |
| golang:1.22 | Multi-stage + scratch | ~1GB |
b) Layer consolidation:
# BAD: 3 layers
RUN apt-get update
RUN apt-get install -y curl git
RUN apt-get clean
# GOOD: 1 layer + cleanup
RUN apt-get update && \
apt-get install -y --no-install-recommends curl git && \
rm -rf /var/lib/apt/lists/*
c) Multi-stage build pattern:
# Build stage
FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --production=false
COPY . .
RUN npm run build
# Production stage
FROM node:20-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package.json ./
USER node
CMD ["node", "dist/main.js"]
d) .dockerignore check: Flag if missing. Suggest:
node_modules
.git
*.md
.env
.DS_Store
__pycache__
*.pyc
dist
build
coverage
.pytest_cache
3. Cache efficiency checks
a) Dependency layer ordering:
# BAD: Any source change invalidates npm install cache
COPY . .
RUN npm install
# GOOD: Dependencies cached separately from source
COPY package*.json ./
RUN npm ci
COPY . .
b) Apt cache mount (BuildKit):
# syntax=docker/dockerfile:1
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y curl
c) Pip cache mount:
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
4. Security audit
Check for these issues (severity in brackets):
- [CRITICAL]
USER rootor no USER instruction at runtime - [CRITICAL] Secrets in ENV, ARG, or COPY (passwords, tokens, keys)
- [CRITICAL]
ADDwith remote URL (prefercurl+ verification) - [HIGH] Unpinned base image tag (
:latestor bare name) - [HIGH]
apt-get installwithout--no-install-recommends - [HIGH] Running as PID 1 without signal handling (use
tiniordumb-init) - [MEDIUM]
COPY . .without.dockerignore(may copy secrets) - [MEDIUM] No
HEALTHCHECKinstruction - [MEDIUM] Package versions not pinned
- [LOW] Missing
LABELmetadata - [LOW] No
WORKDIRset (defaults to/)
5. Version pinning
# BAD
FROM python:3
RUN pip install flask requests
# GOOD
FROM python:3.12.4-slim@sha256:abc123...
RUN pip install flask==3.0.3 requests==2.32.3
For apt packages:
# Find exact version
docker run --rm debian:bookworm-slim apt-cache policy curl
# Pin it
RUN apt-get install -y curl=7.88.1-10+deb12u5
6. Scoring
Score the Dockerfile 0-100:
| Category | Weight | Criteria |
|---|---|---|
| Size efficiency | 30 | Slim base, multi-stage, layer consolidation |
| Cache efficiency | 20 | Proper ordering, mount caches, minimal invalidation |
| Security | 30 | Non-root, no secrets, pinned versions, healthcheck |
| Best practices | 20 | Labels, .dockerignore, signal handling, WORKDIR |
7. Output format
{
"optimized_dockerfile": "FROM python:3.12.4-slim\n...",
"changes": [
{
"line": 1,
"type": "size",
"severity": "high",
"original": "FROM python:3.12",
"optimized": "FROM python:3.12.4-slim",
"explanation": "Slim variant saves ~700MB; pinned patch version for reproducibility",
"size_impact_mb": -700
}
],
"size_estimate": {
"original_mb": 1200,
"optimized_mb": 180,
"reduction_pct": 85
},
"security_findings": [
{
"severity": "critical",
"issue": "Container runs as root",
"fix": "Add 'USER appuser' after creating the user"
}
],
"score": {
"original": 35,
"optimized": 88,
"breakdown": {
"size": 25,
"cache": 18,
"security": 27,
"practices": 18
}
}
}
Pitfalls
- Alpine images break glibc-dependent apps (Python, Node native modules). Prefer
-slimvariants unless you've tested. - Multi-stage builds increase build time but reduce image size. Worth it for production but maybe not for dev images.
COPY --chownis more efficient thanCOPY+RUN chown(avoids double layer).- BuildKit features (
--mount=type=cache) needDOCKER_BUILDKIT=1or Docker 23+. - Hadolint can catch some issues automatically:
docker run --rm -i hadolint/hadolint < Dockerfile