Docker image optimization patterns including multi-stage builds, layer caching, security hardening, and size reduction techniques. Use when building Docker images, optimizing container size, improving build performance, or implementing Docker security best practices. Reduces image sizes by 70-90% and build times by 50-80%.
Add this skill
npx mdskills install applied-artificial-intelligence/docker-optimizationComprehensive Docker optimization guide with concrete examples showing 70-90% size reductions
Comprehensive guide to optimizing Docker images for size, build speed, and security. Covers multi-stage builds, layer caching strategies, security hardening, and production deployment patterns.
When to use this skill:
Common triggers:
Typical single-stage Dockerfile (800MB+ image):
FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Problems:
Optimized multi-stage Dockerfile (120MB image):
# Stage 1: Builder
FROM python:3.11-slim AS builder
WORKDIR /app
# Install build dependencies in separate layer
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy only requirements first (cache optimization)
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: Runtime
FROM python:3.11-slim
WORKDIR /app
# Copy only Python packages from builder
COPY --from=builder /root/.local /root/.local
# Copy only application code
COPY app.py .
COPY src/ ./src/
# Make sure scripts in .local are usable
ENV PATH=/root/.local/bin:$PATH
# Run as non-root user
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["python", "app.py"]
Result: 800MB → 120MB (85% reduction)
Stage 1: Builder (Throw away after build)
Stage 2: Runtime (Final image)
Each instruction creates a layer. Docker caches unchanged layers.
Bad Order (cache invalidated on every code change):
FROM python:3.11-slim
COPY . . # ❌ Copies everything
RUN pip install -r requirements.txt # ❌ Runs on every code change
Good Order (cache preserved):
FROM python:3.11-slim
COPY requirements.txt . # ✅ Only requirements
RUN pip install -r requirements.txt # ✅ Cached if requirements unchanged
COPY . . # ✅ Code changes don't invalidate pip cache
1. Order by change frequency (least to most):
# 1. System dependencies (rarely change)
RUN apt-get update && apt-get install -y curl
# 2. Language runtime (rarely changes)
FROM python:3.11-slim
# 3. Dependencies (change occasionally)
COPY requirements.txt .
RUN pip install -r requirements.txt
# 4. Application code (changes frequently)
COPY . .
2. Separate COPY operations:
# ❌ Bad: Invalidates cache on any file change
COPY . .
# ✅ Good: Cache preserved unless specific files change
COPY package.json package-lock.json ./
RUN npm ci
COPY src/ ./src/
COPY public/ ./public/
3. Use .dockerignore:
# .dockerignore
.git
.gitignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.env
.venv
__pycache__
*.pyc
tests/
docs/
Image Size Comparison:
python:3.11 → 1.01GB
python:3.11-slim → 130MB (87% smaller)
python:3.11-alpine → 50MB (95% smaller)
When to use each:
python:3.11): Never for productionpython:3.11-slim): Default choice, good compatibilitypython:3.11-alpine): Smallest, but can have glibc issuesNode.js Example (900MB → 150MB):
# Builder stage
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Result: 900MB → 150MB (83% reduction)
❌ Bad (creates large intermediate layers):
RUN apt-get update
RUN apt-get install -y build-essential
RUN rm -rf /var/lib/apt/lists/*
✅ Good (single layer, no intermediate garbage):
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential && \
rm -rf /var/lib/apt/lists/*
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc \
g++ \
make \
&& pip install --no-cache-dir -r requirements.txt \
&& apt-get purge -y --auto-remove \
gcc \
g++ \
make \
&& rm -rf /var/lib/apt/lists/*
❌ Bad (runs as root):
FROM python:3.11-slim
COPY app.py .
CMD ["python", "app.py"]
✅ Good (runs as non-root user):
FROM python:3.11-slim
# Create non-root user
RUN useradd -m -u 1000 appuser && \
mkdir -p /app && \
chown -R appuser:appuser /app
WORKDIR /app
USER appuser
COPY --chown=appuser:appuser app.py .
CMD ["python", "app.py"]
❌ Bad (secrets baked into image):
ENV DATABASE_PASSWORD=secret123
COPY .env .
✅ Good (secrets provided at runtime):
# Pass secrets via environment variables at runtime
# docker run -e DATABASE_PASSWORD=$DB_PASS myapp
✅ Also Good (Docker secrets):
# Use Docker secrets (Swarm/Kubernetes)
CMD ["sh", "-c", "python app.py"]
# Secrets mounted at /run/secrets/
# Using Docker Scout
docker scout cves myapp:latest
# Using Trivy
trivy image myapp:latest
# Using Snyk
snyk container test myapp:latest
❌ Bad (unpredictable):
FROM python:latest
✅ Good (reproducible):
FROM python:3.11.9-slim-bookworm
Enable BuildKit for faster builds:
export DOCKER_BUILDKIT=1
docker build -t myapp .
Benefits:
With BuildKit (cache pip downloads):
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
Benefits:
BuildKit automatically parallelizes independent stages:
# Stage 1: Frontend build (runs in parallel)
FROM node:20 AS frontend
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# Stage 2: Backend build (runs in parallel)
FROM python:3.11-slim AS backend
WORKDIR /app/backend
COPY backend/requirements.txt .
RUN pip install -r requirements.txt
# Stage 3: Final image (waits for both stages)
FROM python:3.11-slim
COPY --from=frontend /app/frontend/dist /app/static
COPY --from=backend /app/backend /app
FROM python:3.11-slim
COPY app.py .
# Add health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD ["python", "app.py"]
# Use exec form to ensure proper signal handling
CMD ["python", "app.py"] # ✅ Receives SIGTERM
# Not shell form
CMD python app.py # ❌ Shell doesn't forward signals
LABEL org.opencontainers.image.title="MyApp"
LABEL org.opencontainers.image.version="1.2.3"
LABEL org.opencontainers.image.authors="team@example.com"
LABEL org.opencontainers.image.source="https://github.com/org/repo"
FROM python:3.11-slim AS builder
# Prevent Python from writing pyc files
ENV PYTHONDONTWRITEBYTECODE=1
# Prevent Python from buffering stdout/stderr
ENV PYTHONUNBUFFERED=1
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
# Install to user site-packages
RUN pip install --user --no-cache-dir -r requirements.txt
# Runtime stage
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH=/root/.local/bin:$PATH
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0"]
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
# Install production dependencies only
RUN npm ci --only=production && \
# Remove npm cache
npm cache clean --force
# Runtime stage
FROM node:20-alpine
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodeuser -u 1001
WORKDIR /app
COPY --from=builder --chown=nodeuser:nodejs /app/node_modules ./node_modules
COPY --chown=nodeuser:nodejs . .
USER nodeuser
EXPOSE 3000
CMD ["node", "server.js"]
# Builder stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# Runtime stage - minimal scratch image
FROM scratch
# Copy CA certificates for HTTPS
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Copy binary
COPY --from=builder /app/main /main
EXPOSE 8080
ENTRYPOINT ["/main"]
Result: 1GB → 15MB (98.5% reduction!)
❌ Bad (installs hundreds of unnecessary packages):
RUN apt-get install curl
✅ Good (minimal installation):
RUN apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
❌ Bad (ADD has implicit behavior):
ADD requirements.txt . # Can extract tarballs, fetch URLs
✅ Good (COPY is explicit):
COPY requirements.txt . # Only copies files
❌ Bad (can't reference previous stages):
FROM python:3.11
RUN pip install -r requirements.txt
FROM python:3.11-slim
# Can't copy from previous stage!
✅ Good (named stages):
FROM python:3.11 AS builder
RUN pip install -r requirements.txt
FROM python:3.11-slim
COPY --from=builder /root/.local /root/.local
Without .dockerignore:
❌ Bad (no control over patch versions):
FROM python:3.11
✅ Good (pin exact version):
FROM python:3.11.9-slim-bookworm
Before (1.2GB image, 5min build):
FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["uvicorn", "app:app"]
After (140MB image, 2min build):
FROM python:3.11-slim AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
FROM python:3.11-slim
ENV PATH=/root/.local/bin:$PATH
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY app.py .
COPY src/ ./src/
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["uvicorn", "app:app", "--host", "0.0.0.0"]
Results:
Image Size:
apt-get install && rm -rf)--no-install-recommends with apt-getpip --no-cache-dir, npm cache clean)Build Speed:
Security:
Production:
Official Docker Documentation:
Security Scanning:
Base Images:
Best experience: Claude Code
/plugin marketplace add applied-artificial-intelligence/docker-optimizationThen /plugin menu → select skill → restart. Use /skill-name:init for first-time setup.
Other platforms
Install via CLI
npx mdskills install applied-artificial-intelligence/docker-optimizationDocker Optimization is a free, open-source AI agent skill. Docker image optimization patterns including multi-stage builds, layer caching, security hardening, and size reduction techniques. Use when building Docker images, optimizing container size, improving build performance, or implementing Docker security best practices. Reduces image sizes by 70-90% and build times by 50-80%.
Install Docker Optimization with a single command:
npx mdskills install applied-artificial-intelligence/docker-optimizationThis downloads the skill files into your project and your AI agent picks them up automatically.
Docker Optimization works with Claude Code, Claude Desktop, Cursor, Vscode Copilot, Windsurf, Continue Dev, Codex, Gemini Cli, Amp, Roo Code, Goose, Opencode, Trae, Qodo, Command Code. Skills use the open SKILL.md format which is compatible with any AI coding agent that reads markdown instructions.