Docker Deployment¶
This guide covers deploying the School Clubs Management System using Docker and Docker Compose.
Overview¶
The application is containerized using Docker for consistent deployment across environments. The setup includes:
- Flask application container
- SQLite database with persistent volume
- Traefik reverse proxy for HTTPS
- Automated deployment via GitHub Actions
Prerequisites¶
Required Software¶
- Docker (v20.10+)
- Docker Compose (v2.0+)
Optional¶
- Domain name with DNS configured
- Traefik reverse proxy (for HTTPS)
Quick Start¶
1. Clone Repository¶
2. Configure Environment¶
Create .env file:
cat > .env << EOF
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
DATABASE_URI=sqlite:////data/data.db
FLASK_ENV=production
EOF
3. Build and Start¶
4. Access Application¶
Application Running
- Local: http://localhost:5000
- Production: https://se.unilu.dev
- Docs: https://docs.unilu.dev
Docker Configuration¶
Dockerfile¶
FROM python:3.12-slim
WORKDIR /app
# Install dependencies
COPY deliverable-2/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY deliverable-2/school_clubs /app/school_clubs
# Create instance directory
RUN mkdir -p /data
# Set environment variables
ENV FLASK_APP=school_clubs
ENV PYTHONUNBUFFERED=1
# Expose port
EXPOSE 5000
# Run application
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "school_clubs:create_app()"]
Key Points:
- Uses Python 3.12 slim image
- Installs dependencies from requirements.txt
- Creates
/datadirectory for SQLite database - Uses Gunicorn as WSGI server
- Exposes port 5000
docker-compose.yml¶
version: '3.8'
services:
app:
build: .
container_name: school-clubs-app
restart: unless-stopped
ports:
- "5000:5000"
volumes:
- school-clubs-data:/data
environment:
- SECRET_KEY=${SECRET_KEY:-only-set-server-side}
- DATABASE_URI=sqlite:////data/data.db
- FLASK_ENV=production
labels:
- "traefik.enable=true"
- "traefik.http.routers.school-clubs.rule=Host(`se.unilu.dev`)"
- "traefik.http.routers.school-clubs.entrypoints=websecure"
- "traefik.http.routers.school-clubs.tls.certresolver=letsencrypt"
- "traefik.http.services.school-clubs.loadbalancer.server.port=5000"
networks:
- traefik-network
docs:
image: squidfunk/mkdocs-material:latest
container_name: school-clubs-docs
restart: unless-stopped
volumes:
- ./docs:/docs
command: serve --dev-addr=0.0.0.0:8000
ports:
- "8000:8000"
labels:
- "traefik.enable=true"
- "traefik.http.routers.school-clubs-docs.rule=Host(`docs.unilu.dev`)"
- "traefik.http.routers.school-clubs-docs.entrypoints=websecure"
- "traefik.http.routers.school-clubs-docs.tls.certresolver=letsencrypt"
- "traefik.http.services.school-clubs-docs.loadbalancer.server.port=8000"
networks:
- traefik-network
volumes:
school-clubs-data:
driver: local
networks:
traefik-network:
external: true
Environment Variables¶
Application Variables¶
| Variable | Required | Default | Description |
|---|---|---|---|
SECRET_KEY |
Yes | - | Flask secret key for sessions |
DATABASE_URI |
No | sqlite:////data/data.db |
Database connection string |
FLASK_ENV |
No | production |
Environment: development/production |
Setting Variables¶
Option 1: .env File
Option 2: Environment Variables
export SECRET_KEY="your-secret-key-here"
export DATABASE_URI="sqlite:////data/data.db"
docker compose up -d
Option 3: docker-compose.yml
services:
app:
environment:
- SECRET_KEY=your-secret-key-here
- DATABASE_URI=sqlite:////data/data.db
Security Warning
Never commit .env files or secrets to version control!
Persistent Data¶
Database Volume¶
The SQLite database is stored in a Docker volume for persistence:
Location: /var/lib/docker/volumes/school-clubs-data/_data/
Backup Database¶
# Copy from container
docker compose exec app cat /data/data.db > backup.db
# Or directly from volume
docker run --rm -v school-clubs-data:/data \
-v $(pwd):/backup alpine \
cp /data/data.db /backup/backup.db
Restore Database¶
# Copy to container
docker compose cp backup.db app:/data/data.db
# Restart application
docker compose restart app
Traefik Integration¶
Traefik Configuration¶
The application uses Traefik for automatic HTTPS with Let's Encrypt.
Labels Explained:
labels:
# Enable Traefik
- "traefik.enable=true"
# Route traffic from domain
- "traefik.http.routers.school-clubs.rule=Host(`se.unilu.dev`)"
# Use HTTPS entrypoint
- "traefik.http.routers.school-clubs.entrypoints=websecure"
# Enable TLS with Let's Encrypt
- "traefik.http.routers.school-clubs.tls.certresolver=letsencrypt"
# Forward to port 5000
- "traefik.http.services.school-clubs.loadbalancer.server.port=5000"
Without Traefik¶
If not using Traefik, expose ports directly:
Docker Commands¶
Build and Start¶
# Build and start all services
docker compose up -d --build
# Start without building
docker compose up -d
# Start specific service
docker compose up -d app
Stop and Remove¶
# Stop all services
docker compose stop
# Stop and remove containers
docker compose down
# Remove containers and volumes
docker compose down -v
View Logs¶
# All services
docker compose logs -f
# Specific service
docker compose logs -f app
# Last 100 lines
docker compose logs --tail=100 app
Execute Commands¶
# Open shell in container
docker compose exec app /bin/bash
# Run Flask command
docker compose exec app flask seed-db
# Check Python version
docker compose exec app python --version
Inspect Containers¶
# List running containers
docker compose ps
# Container details
docker inspect school-clubs-app
# Resource usage
docker stats school-clubs-app
CI/CD with GitHub Actions¶
Automated Deployment¶
Changes pushed to dev branch automatically deploy via GitHub Actions.
Workflow File: .github/workflows/deploy.yml
name: Deploy to Server
on:
push:
branches: [dev]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /path/to/SE1
git pull origin dev
docker compose up -d --build
Required Secrets:
HOST: Server hostname or IPUSERNAME: SSH usernameSSH_KEY: Private SSH key
Manual Deployment¶
# SSH to server
ssh user@server
# Navigate to project
cd /path/to/SE1
# Pull latest changes
git pull origin dev
# Rebuild and restart
docker compose up -d --build
Production Deployment¶
Security Checklist¶
- Use strong SECRET_KEY from environment variable
- Enable HTTPS with Traefik or reverse proxy
- Restrict exposed ports
- Use non-root user in container
- Enable Docker security scanning
- Configure firewall rules
- Set up monitoring and logging
- Regular database backups
- Update base images regularly
Performance Optimization¶
Gunicorn Workers:
services:
app:
command: >
gunicorn
--bind 0.0.0.0:5000
--workers 4
--threads 2
--timeout 60
"school_clubs:create_app()"
Worker Formula: (2 × CPU cores) + 1
Resource Limits:
services:
app:
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
Health Checks¶
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Monitoring¶
Container Logs¶
Application Metrics¶
Consider adding monitoring tools:
- Prometheus: Metrics collection
- Grafana: Visualization dashboards
- ELK Stack: Log aggregation and analysis
Example Prometheus Integration¶
services:
app:
environment:
- PROMETHEUS_MULTIPROC_DIR=/tmp
volumes:
- prometheus-data:/tmp
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
Troubleshooting¶
Container Won't Start¶
Check logs:
Common issues:
- Missing environment variables
- Port already in use
- Invalid configuration
- Database locked
Database Issues¶
Check database file:
Reset database:
Permission Issues¶
Fix volume permissions:
Network Issues¶
Check network:
Recreate network:
Alternative Deployment¶
Docker Swarm¶
# Initialize swarm
docker swarm init
# Deploy stack
docker stack deploy -c docker-compose.yml school-clubs
# List services
docker stack services school-clubs
# Remove stack
docker stack rm school-clubs
Kubernetes¶
For Kubernetes deployment, create deployment and service manifests.
Example Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: school-clubs
spec:
replicas: 3
selector:
matchLabels:
app: school-clubs
template:
metadata:
labels:
app: school-clubs
spec:
containers:
- name: app
image: school-clubs:latest
ports:
- containerPort: 5000
env:
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: school-clubs-secret
key: secret-key
Next Steps¶
- Configuration Guide - Configure application
- Architecture - Understand the codebase
- Installation - Local development setup