Docker Architecture¶
Overview¶
flowchart TB
subgraph External["External Access"]
Internet([Internet])
end
subgraph Ports["Exposed Ports"]
P80[":80"]
P443[":443"]
end
Internet --> P80 & P443
subgraph Docker["Docker Compose Environment"]
subgraph Services["Services"]
Nginx[Nginx<br/>Reverse Proxy]
Frontend[Frontend<br/>React + Vite]
Backend[Backend<br/>Django REST]
Redis[(Redis<br/>Cache + Broker)]
CeleryWorker[Celery Worker<br/>Task Processor]
CeleryBeat[Celery Beat<br/>Scheduler]
end
P80 & P443 --> Nginx
Nginx -->|"/*"| Frontend
Nginx -->|"/api/*"| Backend
Backend --> Redis
CeleryWorker --> Redis
CeleryBeat --> Redis
CeleryBeat -.->|schedules| CeleryWorker
end
subgraph Volumes["Persistent Volumes"]
SSL[("SSL Certs<br/>nginx/data/ssl/")]
DB[("SQLite<br/>backend/db.sqlite3")]
RedisData[("Redis Data<br/>backend/.redis_data")]
end
Nginx -.-> SSL
Backend -.-> DB
Redis -.-> RedisData
subgraph Registry["GitHub Container Registry"]
FImg["frontend:latest"]
BImg["backend:latest"]
NImg["nginx:latest"]
end
Docker Compose Configurations¶
The project provides multiple Docker Compose configurations for different environments:
| File | Purpose | Use Case |
|---|---|---|
docker-compose.debug.yaml |
Development | Local development with hot reload |
docker-compose.test.yaml |
Testing | Cypress E2E testing |
docker-compose.prod.yaml |
Production | Production deployment |
docker-compose.release.yaml |
Release | Versioned release deployment |
Services¶
Frontend Service¶
frontend:
image: ghcr.io/kettleofketchup/draftforge/frontend:latest
# Development: mounts ./frontend/ for hot reload
volumes:
- ./frontend/:/app
- Dev Image:
frontend-dev:latest- Includes dev dependencies - Prod Image:
frontend:latest- Optimized production build
Backend Service¶
backend:
image: ghcr.io/kettleofketchup/draftforge/backend:latest
depends_on:
- redis
volumes:
- ./backend/:/app/backend
- Dev Image:
backend-dev:latest- Debug mode enabled - Prod Image:
backend:latest- Production optimized
Redis Service¶
Persistent data storage for cache across restarts.
Nginx Service¶
nginx:
image: ghcr.io/kettleofketchup/draftforge/nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.template.conf:/etc/nginx/templates/
- ./nginx/data/ssl/:/etc/letsencrypt/live/dota.kettle.sh/
Celery Worker Service¶
celery-worker:
image: ghcr.io/kettleofketchup/draftforge/backend:latest
command: celery -A config worker -l info
depends_on:
- redis
- backend
Processes background tasks from the Redis queue. Uses the same image as the backend service.
Celery Beat Service¶
celery-beat:
image: ghcr.io/kettleofketchup/draftforge/backend:latest
command: celery -A config beat -l info
depends_on:
- redis
- celery-worker
Scheduler that triggers periodic tasks (e.g., league match sync every 60 seconds).
Environment Files¶
| File | Description |
|---|---|
docker/.env.dev |
Development environment variables |
docker/.env.test |
Test environment variables |
docker/.env.prod |
Production environment variables |
docker/.env.release |
Release version and settings |
Environment Variables¶
| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Environment mode (dev/test/prod/release) | - |
DOMAIN |
Site domain | localhost |
FRONTEND_HOST |
Frontend host | localhost |
FRONTEND_PORT |
Frontend port | 3000 |
BACKEND_HOST |
Backend host | localhost |
BACKEND_PORT |
Backend port | 8000 |
SSR_API_URL |
Backend URL for SSR requests | http://backend:8000/api |
SSR_API_URL¶
The frontend uses Server-Side Rendering (SSR). During SSR, the Node.js server needs to reach the backend API. Since it runs inside Docker, it uses the Docker service name.
# Default - uses Docker Compose service name
SSR_API_URL=http://backend:8000/api
# Kubernetes example
SSR_API_URL=http://backend-service:8000/api
# External backend
SSR_API_URL=https://api.example.com/api
Why not /api?
On the client (browser), requests to /api are proxied by Nginx. But during SSR, the Node.js server makes requests directly - it needs the full internal URL to reach the backend container.
Image Registry¶
All images are hosted on GitHub Container Registry:
ghcr.io/kettleofketchup/draftforge/
├── frontend:latest
├── frontend-dev:latest
├── backend:latest
├── backend-dev:latest
└── nginx:latest
Common Docker Operations¶
source .venv/bin/activate
# Build all images
inv docker.all.build
# Push to registry
inv docker.all.push
# Pull latest images
inv docker.all.pull
# Start development
inv dev.debug
# Start production locally
inv dev.prod
Networking¶
Development Network¶
Services communicate via Docker's default bridge network.
Test Network¶
Creates an isolated test-network for E2E testing:
Volume Mounts¶
Development Volumes¶
- Source code mounted for hot reload
- Database files persisted locally
Production Volumes¶
- Only database and SSL certificates mounted
- No source code access
SSL Certificates¶
Development uses self-signed certificates in nginx/data/ssl/.
Production uses Let's Encrypt via Certbot: