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%.
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: