On this page
Docker best practices for Python applications
Docker is central to development and deployment. Here are solid practices for containerizing Python apps.
Dockerfile structure
1. Multi-stage builds
# Stage 1: Builder
FROM python:3.10-slim as builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: Production
FROM python:3.10-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Benefits:
- Smaller final image
- Better security (no build tools in prod)
- Faster rebuilds when only app code changes
2. Prefer slim images
❌ Avoid:
FROM python:3.10 # ~900 MB
✅ Prefer:
FROM python:3.10-slim # ~120 MB
3. Layer cache optimization
# Copy requirements first (changes less often)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code last (changes more often)
COPY . .
Security
1. Non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
2. Do not bake in secrets
❌ Bad:
ENV API_KEY=secret123
✅ Good:
# Use Docker secrets or runtime environment variables
# docker run -e API_KEY=secret123
3. Scan for vulnerabilities
trivy image myapp:latest
Performance
1. .dockerignore
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env/
venv/
.git/
.gitignore
README.md
2. Health checks
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health || exit 1
3. Labels for metadata
LABEL maintainer="Daya SYLLA <dev@example.com>"
LABEL version="1.0"
LABEL description="Flask Portfolio Application"
Docker Compose
Example service
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
environment:
- FLASK_ENV=production
volumes:
- ./app:/app
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
CI/CD integration
GitHub Actions
name: Build and Push
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Push to registry
run: docker push myapp:${{ github.sha }}
Monitoring
Structured logs
import logging
import json
logging.basicConfig(
format='%(asctime)s %(levelname)s %(message)s',
level=logging.INFO
)
Metrics
- Expose Prometheus metrics
- Add a
/metricsendpoint - Visualize with Grafana
Conclusion
These practices help you build Docker images that are lean, secure, and easy to operate—improving both development and deployment workflows.