Docker Deployment
Containerize Fastpy with Docker.
Dockerfile
dockerfile
# Dockerfile
FROM python:3.11-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Set work directory
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn uvicorn[standard]
# Copy application
COPY . .
# Create non-root user
RUN adduser --disabled-password --gecos '' appuser
RUN chown -R appuser:appuser /app
USER appuser
# Expose port
EXPOSE 8000
# Run application
CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"]Docker Compose
Development
yaml
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
environment:
- DEBUG=true
- DATABASE_URL=postgresql://postgres:postgres@db:5432/fastpy
depends_on:
- db
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=fastpy
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
postgres_data:Production
yaml
# docker-compose.prod.yml
version: '3.8'
services:
api:
build:
context: .
dockerfile: Dockerfile
restart: always
environment:
- ENVIRONMENT=production
- DEBUG=false
- DATABASE_URL=${DATABASE_URL}
- SECRET_KEY=${SECRET_KEY}
depends_on:
- db
networks:
- backend
db:
image: postgres:15-alpine
restart: always
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- backend
nginx:
image: nginx:alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./certs:/etc/nginx/certs
depends_on:
- api
networks:
- backend
networks:
backend:
volumes:
postgres_data:Commands
bash
# Build
docker-compose build
# Start development
docker-compose up
# Start production
docker-compose -f docker-compose.prod.yml up -d
# View logs
docker-compose logs -f api
# Run migrations
docker-compose exec api fastpy db:migrate
# Access shell
docker-compose exec api bash
# Stop
docker-compose down
# Stop and remove volumes
docker-compose down -vMulti-Stage Build
Optimized Dockerfile for smaller images:
dockerfile
# Build stage
FROM python:3.11-slim as builder
WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev
COPY requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
# Production stage
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/wheels /wheels
RUN pip install --no-cache /wheels/*
COPY . .
RUN adduser --disabled-password --gecos '' appuser
USER appuser
EXPOSE 8000
CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"]Health Checks
yaml
services:
api:
# ...
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health/ready"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40sEnvironment Variables
bash
# .env.docker
DATABASE_URL=postgresql://postgres:postgres@db:5432/fastpy
SECRET_KEY=your-secret-key
ENVIRONMENT=production
DEBUG=falseLoad with:
yaml
services:
api:
env_file:
- .env.dockerDocker with MySQL
yaml
services:
db:
image: mysql:8.0
restart: always
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=fastpy
- MYSQL_USER=fastpy
- MYSQL_PASSWORD=fastpypassword
volumes:
- mysql_data:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password
volumes:
mysql_data:CI/CD with Docker
GitHub Actions
yaml
# .github/workflows/docker.yml
name: Docker Build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t fastpy .
- name: Run tests
run: docker run fastpy pytest
- name: Push to registry
run: |
docker tag fastpy registry.example.com/fastpy:latest
docker push registry.example.com/fastpy:latestBest Practices
- Use non-root user - Security
- Multi-stage builds - Smaller images
- Pin versions - Reproducible builds
- Health checks - Container orchestration
- Secrets management - Don't bake secrets into images
- .dockerignore - Exclude unnecessary files