BlogDocker Optimization

⚡ Docker Performance Optimization

Learn how to build smaller, faster Docker images and optimize container performance for production.

Image Size Optimization

1. Use Alpine Base Images

# Instead of
FROM node:20          # ~1GB
 
# Use
FROM node:20-alpine   # ~150MB

2. Multi-Stage Builds

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
 
# Production stage
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
 
# Only copy what's needed
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
 
EXPOSE 3000
CMD ["node", "dist/server.js"]

3. Layer Optimization

# Bad - cache invalidation on any change
COPY . .
RUN npm install
 
# Good - leverage cache
COPY package*.json ./
RUN npm ci
COPY . .

4. Remove Unnecessary Files

Create .dockerignore:

node_modules
.git
.github
*.md
.env*
.vscode
coverage
tests
__tests__

Build Performance

Use BuildKit

# Enable BuildKit
export DOCKER_BUILDKIT=1
 
# Or in Docker daemon config
{
  "features": {
    "buildkit": true
  }
}

Cache Dependencies

# Cache npm packages
RUN --mount=type=cache,target=/root/.npm \
    npm ci --only=production

Parallel Builds

# docker-compose.yml
services:
  frontend:
    build:
      context: ./frontend
      cache_from:
        - myapp/frontend:cache
 
  backend:
    build:
      context: ./backend
      cache_from:
        - myapp/backend:cache
# Build in parallel
docker compose build --parallel

Runtime Performance

1. Resource Limits

# docker-compose.yml
services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 512M
        reservations:
          cpus: "0.5"
          memory: 256M

2. Health Checks

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

3. Logging Configuration

services:
  app:
    image: myapp
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Image Size Comparison

ApproachSize
node:20~1GB
node:20-slim~250MB
node:20-alpine~150MB
Multi-stage + Alpine~80MB
With .dockerignore~50MB

Security Best Practices

# Run as non-root user
RUN addgroup -g 1001 -S appgroup && \
    adduser -u 1001 -S appuser -G appgroup
 
USER appuser
 
# Use specific versions
FROM node:20.10.0-alpine3.18
 
# Scan for vulnerabilities
# docker scout cve myapp:latest

Quick Optimization Checklist

  • Use Alpine or distroless base images
  • Implement multi-stage builds
  • Create comprehensive .dockerignore
  • Order layers by change frequency
  • Enable BuildKit
  • Set resource limits
  • Configure health checks
  • Run as non-root user
  • Pin dependency versions
  • Scan images for vulnerabilities

Commands Reference

# Check image size
docker images myapp
 
# Analyze layers
docker history myapp
 
# Inspect image
docker inspect myapp
 
# Prune unused images
docker image prune -a
 
# Build with cache
docker build --cache-from myapp:latest -t myapp:new .

💡 Pro Tip: Use dive tool to analyze Docker image layers: dive myapp:latest


Published: December 10, 2024