Lesson 1: The Minimalist (Optimizing Docker Images)
A 2GB Docker image takes forever to pull, wastes disk space, and has a larger attack surface. Great DevOps engineers build small, efficient images. It's the art of minimalism.
The Size Problem
docker images --format 'table {{.Repository}}:{{.Tag}}\t{{.Size}}'
node:18 920MB 😱
node:18-slim 240MB 🤔
node:18-alpine 50MB ✅
Strategy 1: Choose Small Base Images
| Base Image | Size | When to Use |
|-----------|------|-------------|
| ubuntu | ~78 MB | Learning, full toolset needed |
| debian:slim | ~52 MB | Production, need apt |
| alpine | ~5 MB | Production, minimal |
| distroless | ~2 MB | Production, maximum security |
| scratch | 0 MB | Static binaries (Go, Rust) |
Strategy 2: Multi-Stage Builds
The most powerful optimization. Build in one stage, deploy from another:
# ===== Stage 1: Build =====
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ===== Stage 2: Production =====
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
Result: The final image only contains the built output, not the build tools, source code, or dev dependencies.
Without multi-stage: 920MB (includes compilers, source, dev deps)
With multi-stage: 85MB (only runtime + built code)
Strategy 3: Minimize Layers
Each RUN command creates a layer. Combine them:
# ❌ BAD: 3 layers
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# ✅ GOOD: 1 layer
RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*
Strategy 4: Use .dockerignore
Like .gitignore for Docker builds. Prevents unnecessary files from being sent to the build context:
node_modules
.git
*.md
.env
.vscode
Dockerfile
docker-compose.yml
Strategy 5: Don't Install Unnecessary Packages
# ❌ Installs recommended packages too
RUN apt-get install python3
# ✅ Only install what's needed
RUN apt-get install --no-install-recommends python3
Mission Objective
Optimize like a pro:
- Audit: Compare image sizes with
docker images --format 'table {{.Repository}}:{{.Tag}}\t{{.Size}}'. - Analyze: View layers with
docker history nginx --no-trunc. - Ignore: Create a
.dockerignorewithecho 'node_modules\n.git\n*.md\n.env' > .dockerignore.