Docker Containerization
Overview
Build production-ready Docker containers following best practices for security, performance, and maintainability.
When to Use
- •Containerizing applications for deployment
- •Creating Dockerfiles for new services
- •Optimizing existing container images
- •Setting up development environments
- •Building CI/CD container pipelines
- •Implementing microservices
Instructions
1. Multi-Stage Builds
dockerfile
# Multi-stage build for Node.js application # Stage 1: Build FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # Stage 2: Production FROM node:18-alpine WORKDIR /app # Copy only production dependencies and built files COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY package*.json ./ # Security: Run as non-root user RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 USER nodejs EXPOSE 3000 CMD ["node", "dist/index.js"]
2. Optimization Techniques
Layer Caching
dockerfile
# ❌ Poor caching - changes in source code invalidate dependency install FROM python:3.11-slim WORKDIR /app COPY . . RUN pip install -r requirements.txt # ✅ Good caching - dependencies cached separately FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . .
Minimize Image Size
dockerfile
# ❌ Large image (~800MB) FROM ubuntu:latest RUN apt-get update && apt-get install -y python3 python3-pip # ✅ Minimal image (~50MB) FROM python:3.11-alpine
3. Security Best Practices
dockerfile
FROM node:18-alpine # Update packages for security patches RUN apk update && apk upgrade # Don't run as root RUN addgroup -g 1001 appgroup && adduser -S -u 1001 -G appgroup appuser USER appuser # Use specific versions, not 'latest' WORKDIR /app # Scan for vulnerabilities # Run: docker scan your-image:tag
4. Environment Configuration
dockerfile
# Use build arguments for flexibility
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
CMD node healthcheck.js || exit 1
# Labels for metadata
LABEL maintainer="team@example.com" \
version="1.0.0" \
description="Production API service"
5. Docker Compose for Multi-Container
yaml
# docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
NODE_ENV: production
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
volumes:
- ./uploads:/app/uploads
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD: password
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
postgres-data:
redis-data:
6. .dockerignore File
code
# .dockerignore node_modules npm-debug.log dist .git .env .env.local *.md !README.md .DS_Store coverage .vscode .idea __pycache__ *.pyc .pytest_cache
Best Practices
✅ DO
- •Use official base images
- •Implement multi-stage builds
- •Run as non-root user
- •Use .dockerignore
- •Pin specific versions
- •Include health checks
- •Scan for vulnerabilities
- •Minimize layers
- •Use build caching effectively
❌ DON'T
- •Use 'latest' tag in production
- •Run as root user
- •Include secrets in images
- •Create unnecessary layers
- •Install unnecessary packages
- •Ignore security updates
- •Store data in containers
Examples by Language
Python (Django/Flask)
dockerfile
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN useradd -m appuser && chown -R appuser:appuser /app USER appuser CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Java (Spring Boot)
dockerfile
FROM eclipse-temurin:17-jdk-alpine AS build WORKDIR /app COPY pom.xml . COPY src ./src RUN ./mvnw package -DskipTests FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY --from=build /app/target/*.jar app.jar RUN addgroup -S spring && adduser -S spring -G spring USER spring ENTRYPOINT ["java", "-jar", "app.jar"]
Go
dockerfile
FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.* ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o main . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/main . CMD ["./main"]
Useful Commands
bash
# Build image docker build -t myapp:1.0.0 . # Build with cache disabled docker build --no-cache -t myapp:1.0.0 . # Run container docker run -d -p 3000:3000 --name myapp myapp:1.0.0 # View logs docker logs -f myapp # Execute command in container docker exec -it myapp sh # Inspect image layers docker history myapp:1.0.0 # Check image size docker images myapp # Clean up docker system prune -a
Troubleshooting
Container exits immediately:
bash
docker logs container-name docker inspect container-name
Build fails:
bash
docker build --progress=plain -t myapp .
Permission issues: Ensure proper user setup and volume permissions.
Large image size:
- •Use alpine base images
- •Implement multi-stage builds
- •Remove unnecessary files
- •Use .dockerignore