| name | docker-deployment |
| description | Docker, docker-compose, and deployment configuration best practices. Use when writing Dockerfiles, docker-compose.yml, CI/CD configs, or setting up any containerized deployment. |
Docker Deployment Patterns
Production Dockerfile (Python)
FROM python:3.12-slim AS base
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
FROM base AS builder
RUN pip install --no-cache-dir uv
COPY requirements.txt .
RUN uv pip install --system --no-cache -r requirements.txt
FROM base AS runtime
COPY --from=builder /usr/local/lib/python3.12 /usr/local/lib/python3.12
COPY --from=builder /usr/local/bin /usr/local/bin
COPY . .
RUN useradd -m appuser && chown -R appuser /app
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"]
docker-compose.yml (Development)
services:
app:
build: .
ports: ["8000:8000"]
volumes: ["./:/app"]
env_file: [.env]
depends_on:
db: { condition: service_healthy }
redis: { condition: service_healthy }
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes: [postgres_data:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 5s
retries: 5
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
volumes:
postgres_data:
.env.example (Always provide this)
DB_HOST=db
DB_PORT=5432
DB_NAME=myapp
DB_USER=myapp
DB_PASSWORD=changeme_in_production
REDIS_URL=redis://redis:6379/0
SECRET_KEY=changeme_in_production
DEBUG=false
ALLOWED_ORIGINS=http://localhost:3000
Makefile
.PHONY: dev build test migrate
dev:
docker-compose up --build
build:
docker-compose build
test:
docker-compose run --rm app pytest
migrate:
docker-compose run --rm app alembic upgrade head
shell:
docker-compose exec app bash
Rules
- Multi-stage builds: keep final image small (no build tools)
- Never run as root — create appuser
- Health checks on ALL services
- Never hardcode secrets — always env vars
- .env.example with ALL required vars (no values)
- Volumes for persistent data (DB, uploads)
- Separate docker-compose.override.yml for dev overrides
- Pin image versions (postgres:16, not postgres:latest)