Docker Image Layering
Each instruction in a Dockerfile creates a new layer. Understanding layering is important for optimization.
Layer Structure
+-------------------+
| COPY . . | <- Layer 4 (2 MB)
+-------------------+
| RUN npm install | <- Layer 3 (200 MB)
+-------------------+
| COPY pkg.json | <- Layer 2 (1 KB)
+-------------------+
| FROM node:18 | <- Layer 1 (300 MB)
+-------------------+
Total: 502 MB
Viewing Layers
# View image layers
docker history nginx:latest
# View layer details
docker inspect nginx:latest
Caching Mechanism
# Layer 1: Base image (cached)
FROM node:18-alpine
# Layer 2: Copy dependencies (cached if unchanged)
COPY package*.json ./
# Layer 3: Install dependencies (cached if package.json is unchanged)
RUN npm ci --only=production
# Layer 4: Copy source (always rebuilt if there are changes)
COPY . .
Layer Optimization
# Bad: Many layers
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN apt-get clean
# Good: Combine commands
RUN apt-get update && \
apt-get install -y curl wget && \
rm -rf /var/lib/apt/lists/*
Multi-Stage Build
# Stage 1: Build (large image)
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production (small image)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
Use Case
# Optimized Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
# Layer for dependencies
COPY package*.json ./
RUN npm ci --only=production
# Layer for source code
COPY . .
# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app .
EXPOSE 3000
CMD ["node", "server.js"]
Everyday Use Case
Case: Build time is too long.
# Check 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 .
Best Practices
- Order instructions correctly: Put what rarely changes on top
- Combine RUN commands: Reduce the number of layers
- Use multi-stage builds: For smaller images
- Use .dockerignore: Avoid copying unneeded files
- Cache dependencies: Copy package*.json before the source
Conclusion
Layering is the foundation of Docker images. With the right optimization, build time and image size can be significantly reduced.