Dockerizing Django and FastAPI Applications: A Complete Guide
Introduction
Docker has become the standard for containerizing applications, making deployment consistent across different environments. Whether you're working with Django or FastAPI, Dockerizing your application ensures it runs the same way on your local machine, CI/CD pipelines, and production servers.
🐳 Why Docker? Containerization solves the "it works on my machine" problem and simplifies deployment, scaling, and dependency management.
Prerequisites
Before we start, ensure you have:
- Docker Desktop installed (download here)
- Basic understanding of Django or FastAPI
- A project ready to containerize
Dockerizing a Django Application
Step 1: Create a Dockerfile
Create a Dockerfile in your Django project root:
# Use Python 3.11 slim image
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Install system dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy project
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# Expose port
EXPOSE 8000
# Run the application
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
Step 2: Create a .dockerignore File
Prevent unnecessary files from being copied into the image:
# .dockerignore
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env/
venv/
.venv
pip-log.txt
pip-delete-this-directory.txt
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.log
.git
.gitignore
.mypy_cache
.pytest_cache
.hypothesis
.DS_Store
*.db
*.sqlite3
.env
.env.local
Step 3: Create docker-compose.yml
For a complete setup with database and Redis:
version: '3.8'
services:
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=myproject
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
web:
build: .
command: gunicorn myproject.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
environment:
- DEBUG=0
- DATABASE_URL=postgresql://postgres:postgres@db:5432/myproject
depends_on:
- db
- redis
Step 4: Update Django Settings
Modify your settings.py to work with Docker:
import os
from pathlib import Path
# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent
# Security settings for production
DEBUG = os.getenv('DEBUG', '0') == '1'
SECRET_KEY = os.getenv('SECRET_KEY', 'your-secret-key-here')
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost').split(',')
# Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME', 'myproject'),
'USER': os.getenv('DB_USER', 'postgres'),
'PASSWORD': os.getenv('DB_PASSWORD', 'postgres'),
'HOST': os.getenv('DB_HOST', 'db'),
'PORT': os.getenv('DB_PORT', '5432'),
}
}
# Static files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
Dockerizing a FastAPI Application
Step 1: Create a Dockerfile for FastAPI
FROM python:3.11-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Install dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Expose port
EXPOSE 8000
# Run with Uvicorn
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Step 2: Multi-stage Build for Production
Optimize your Docker image size with 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 \
postgresql-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Runtime stage
FROM python:3.11-slim
WORKDIR /app
# Copy only necessary files from builder
COPY --from=builder /root/.local /root/.local
COPY . .
# Make sure scripts in .local are usable
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Step 3: FastAPI docker-compose.yml
version: '3.8'
services:
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=fastapi_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
ports:
- "5432:5432"
web:
build: .
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
volumes:
- .:/app
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/fastapi_db
depends_on:
- db
Best Practices for Docker
1. Use Specific Base Image Tags
# ❌ Bad
FROM python:latest
# ✅ Good
FROM python:3.11-slim
2. Leverage Layer Caching
Order your Dockerfile commands from least to most frequently changing:
# Install dependencies first (changes less frequently)
COPY requirements.txt .
RUN pip install -r requirements.txt
# Copy code last (changes frequently)
COPY . .
3. Use .dockerignore
Always include a .dockerignore file to reduce build context size and speed up builds.
4. Run as Non-Root User
# Create non-root user
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
5. Health Checks
Add health checks to your Dockerfile:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
Running Your Containerized Applications
Build and Run Django
# Build the image
docker build -t my-django-app .
# Run the container
docker run -p 8000:8000 my-django-app
# Or use docker-compose
docker-compose up --build
Build and Run FastAPI
# Build the image
docker build -t my-fastapi-app .
# Run the container
docker run -p 8000:8000 my-fastapi-app
# Or use docker-compose
docker-compose up --build
Debugging Docker Containers
View Logs
# View logs
docker-compose logs -f web
# View last 100 lines
docker-compose logs --tail=100 web
Execute Commands Inside Container
# Django
docker-compose exec web python manage.py migrate
docker-compose exec web python manage.py createsuperuser
# FastAPI
docker-compose exec web alembic upgrade head
Inspect Running Container
# Get shell access
docker-compose exec web bash
# Check environment variables
docker-compose exec web env
Production Considerations
1. Use Production WSGI/ASGI Servers
# Django - Use Gunicorn
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "4"]
# FastAPI - Use Uvicorn with workers
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
2. Environment Variables
Never hardcode secrets. Use environment variables or secrets management:
# docker-compose.prod.yml
services:
web:
environment:
- SECRET_KEY=${SECRET_KEY}
- DATABASE_URL=${DATABASE_URL}
env_file:
- .env.production
3. Volume Management
For production, use named volumes for persistent data:
volumes:
postgres_data:
static_volume:
media_volume:
Common Issues and Solutions
Issue: Database Connection Refused
Solution: Ensure the database service is ready before the web service starts:
services:
web:
depends_on:
db:
condition: service_healthy
# ... rest of config
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
Issue: Static Files Not Loading
Solution: Ensure static files are collected and served properly:
# settings.py
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATIC_URL = '/static/'
Issue: Slow Build Times
Solution: Use BuildKit and cache mounts:
# syntax=docker/dockerfile:1.4
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
Conclusion
Dockerizing your Django or FastAPI applications provides consistency, portability, and easier deployment. By following these best practices, you'll create production-ready containerized applications that are secure, efficient, and maintainable.
🚀 Next Steps: Consider deploying your containerized applications to platforms like AWS ECS, Google Cloud Run, or DigitalOcean App Platform.
Resources:
Related Articles: