Docker Build Optimization
Optimize Docker builds to reduce build time and image size.
1. Layer Caching
# Good: Copy dependencies first
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# Bad: Copy everything then install
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm ci --only=production
2. Multi-Stage Build
# 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 nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
3. Use BuildKit
# Enable BuildKit
DOCKER_BUILDKIT=1 docker build -t myapp .
# Or in daemon.json
# { "features": { "buildkit": true } }
4. Effective .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.env.local
*.md
docker-compose*.yml
Dockerfile*
.dockerignore
coverage
.nyc_output
dist
build
5. Reduce the Number of Layers
# Bad
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN apt-get clean
# Good
RUN apt-get update && \
apt-get install -y curl wget && \
rm -rf /var/lib/apt/lists/*
Use Case: Build Optimization
# Before: 250MB, 15-second build
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
# After: 120MB, 8-second build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
Everyday Use Case
Case: Build time is too long.
# View the layers that changed
docker history myapp:latest
# Build with cache
docker build -t myapp:latest .
# Build without cache
docker build --no-cache -t myapp:latest .
# View the build cache
docker builder du
Cache Invalidation
# Delete the build cache
docker builder prune
# Delete all caches
docker builder prune -a
# View cache size
docker system df -v
Best Practices
- Use .dockerignore: Avoid copying unneeded files
- Order instructions correctly: Put what rarely changes on top
- Use BuildKit: For parallel builds
- Multi-stage builds: For smaller images
- Cache dependencies: Copy package*.json first
Conclusion
Build optimization reduces development time and image size. Use layer caching, multi-stage builds, and .dockerignore for optimal results.