Introduction
Advanced Docker techniques optimize image size, build times, and security. This tutorial covers multi-stage builds, layer optimization, and production-ready configurations.
Multi-Stage Builds
# Build stage
FROM python:3.11-slim as builder
WORKDIR /app
# Install build dependencies
RUN apt-get update && apt-get install -y \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Production stage
FROM python:3.11-slim
WORKDIR /app
# Copy only necessary files from builder
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# Copy application code
COPY --from=builder /app /app
# Create non-root user
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Layer Optimization
# Bad: Copy all files then install
COPY . .
RUN pip install -r requirements.txt
# Good: Install dependencies first, then copy code
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Best: Use pip cache
COPY requirements.txt .
RUN pip install --cache-dir /tmp/pip-cache -r requirements.txt
Production Dockerfile
FROM python:3.11-slim
# Install security updates
RUN apt-get update && \
apt-get upgrade -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Create user
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
# Copy requirements first (layer caching)
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# Copy application
COPY . .
RUN chown -R appuser:appgroup /app
USER appuser
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
ENVIRONMENT=production
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Docker Compose for Development
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
- .:/app
- pip-cache:/root/.cache/pip
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
volumes:
pgdata:
redis-data:
pip-cache:
Docker Compose for Production
version: '3.8'
services:
app:
build: .
restart: unless-stopped
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
networks:
- backend
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
db:
image: postgres:15
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- backend
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- backend
networks:
backend:
driver: bridge
volumes:
pgdata:
redis-data:
Practice Problems
- Create a multi-stage build for a Node.js application
- Optimize Docker build using build cache
- Add security scanning to Docker build process
- Implement health checks in Docker Compose
- Create a CI/CD pipeline for Docker builds