Add Docker deployment configuration

- Add Dockerfile for production (multi-stage build)
- Add Dockerfile.dev for development with hot reload
- Add docker-compose.yml with 5 services (web, mariadb, redis, celery-worker, celery-beat)
- Add docker-compose.dev.yml for development overrides
- Add .dockerignore for optimized builds
- Add docker/entrypoint.sh startup script
- Add .env.docker.example template
- Add Makefile for common commands
- Add deploy.sh for one-command deployment
- Update config/settings/selfhosted.py to support MariaDB via DATABASE_URL
- Add mysqlclient to requirements.txt for MariaDB support
- Update .gitignore to exclude .env.docker

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Keith Smith
2025-12-26 15:59:09 -07:00
co-authored by Claude Sonnet 4.5
parent a2097dcad3
commit 71399e54b8
12 changed files with 865 additions and 12 deletions
+66
View File
@@ -0,0 +1,66 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg
*.egg-info/
dist/
build/
*.log
# Virtual environments
venv/
.venv/
env/
ENV/
# Django
db.sqlite3
*.sqlite3
staticfiles/
media/
# Environment files
.env
.env.*
!.env.docker.example
# Git
.git/
.gitignore
.gitattributes
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Docker
Dockerfile
Dockerfile.dev
docker-compose.yml
docker-compose.dev.yml
.dockerignore
# Documentation
README.md
*.md
docs/
# CI/CD
.github/
.gitlab-ci.yml
# Testing
.coverage
htmlcov/
.pytest_cache/
.tox/
# OS
.DS_Store
Thumbs.db
+129
View File
@@ -0,0 +1,129 @@
# ===================================================================
# KeepItGoing Server - Docker Environment Configuration
# ===================================================================
# Copy this file to .env.docker and fill in your values
# DO NOT commit .env.docker to version control!
# ===================================================================
# Django Core Settings
# ===================================================================
# SECURITY WARNING: Generate a strong secret key!
# Generate with: python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
SECRET_KEY=CHANGE_ME_GENERATE_A_STRONG_SECRET_KEY_50_PLUS_CHARACTERS
# Debug mode (MUST be False in production)
DEBUG=False
# Comma-separated list of allowed hosts
# Example: api.yourdomain.com,localhost
ALLOWED_HOSTS=yourdomain.com,localhost
# Comma-separated list of trusted origins for CSRF (must include https://)
# Example: https://api.yourdomain.com,https://yourdomain.com
CSRF_TRUSTED_ORIGINS=https://yourdomain.com
# Domain used in email links
SITE_DOMAIN=yourdomain.com
# ===================================================================
# Database Configuration (MariaDB)
# ===================================================================
DB_NAME=keepitgoing
DB_USER=keepitgoing
DB_PASSWORD=CHANGE_ME_STRONG_DATABASE_PASSWORD
DB_ROOT_PASSWORD=CHANGE_ME_STRONG_ROOT_PASSWORD
DB_HOST=mariadb
DB_PORT=3306
# ===================================================================
# Redis Configuration
# ===================================================================
REDIS_URL=redis://redis:6379/0
# ===================================================================
# Email Configuration
# ===================================================================
# Required for user registration (email verification)
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
# Gmail Example (use App Password, not regular password):
# EMAIL_HOST=smtp.gmail.com
# EMAIL_PORT=587
# EMAIL_USE_TLS=True
# EMAIL_HOST_USER=your-email@gmail.com
# EMAIL_HOST_PASSWORD=your-app-password
# SendGrid Example:
# EMAIL_HOST=smtp.sendgrid.net
# EMAIL_PORT=587
# EMAIL_USE_TLS=True
# EMAIL_HOST_USER=apikey
# EMAIL_HOST_PASSWORD=your-sendgrid-api-key
# AWS SES Example:
# EMAIL_HOST=email-smtp.us-east-1.amazonaws.com
# EMAIL_PORT=587
# EMAIL_USE_TLS=True
# EMAIL_HOST_USER=your-aws-access-key
# EMAIL_HOST_PASSWORD=your-aws-secret-key
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
DEFAULT_FROM_EMAIL=KeepItGoing <noreply@yourdomain.com>
SERVER_EMAIL=server@yourdomain.com
# ===================================================================
# Email Verification Settings
# ===================================================================
EMAIL_VERIFICATION_TOKEN_EXPIRY_HOURS=24
# ===================================================================
# CORS Configuration
# ===================================================================
# Comma-separated list of allowed origins
# Example: https://yourdomain.com,https://app.yourdomain.com
CORS_ALLOWED_ORIGINS=https://yourdomain.com
# ===================================================================
# SaaS Mode
# ===================================================================
# Set to True for SaaS deployment with billing/usage limits
# Set to False for self-hosted deployment (no limits)
SAAS_MODE=False
# ===================================================================
# Gunicorn Configuration
# ===================================================================
GUNICORN_WORKERS=3
GUNICORN_TIMEOUT=60
# ===================================================================
# Push Notifications (Optional)
# ===================================================================
# Leave empty if not using push notifications
# Firebase Cloud Messaging (FCM)
FCM_CREDENTIALS_PATH=
# Web Push (VAPID keys)
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
VAPID_ADMIN_EMAIL=
# ===================================================================
# Additional Settings
# ===================================================================
# Django settings module (usually don't need to change)
DJANGO_SETTINGS_MODULE=config.settings.selfhosted
+1
View File
@@ -17,6 +17,7 @@ media/
# Environment
.env
.env.docker
*.env.local
# IDE
+65
View File
@@ -0,0 +1,65 @@
# ===================================================================
# Stage 1: Builder - Install dependencies
# ===================================================================
FROM python:3.12-slim-bookworm AS builder
# Install build dependencies for mysqlclient and other packages
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
default-libmysqlclient-dev \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt /tmp/
RUN pip install --user --no-cache-dir -r /tmp/requirements.txt \
&& pip install --user --no-cache-dir mysqlclient gunicorn
# ===================================================================
# Stage 2: Runtime - Minimal production image
# ===================================================================
FROM python:3.12-slim-bookworm
# Install runtime dependencies only
RUN apt-get update && apt-get install -y --no-install-recommends \
default-mysql-client \
curl \
&& rm -rf /var/lib/apt/lists/*
# Create django user (non-root for security)
RUN useradd -m -u 1000 -s /bin/bash django
# Set working directory
WORKDIR /app
# Copy Python dependencies from builder stage
COPY --from=builder /root/.local /home/django/.local
# Copy application code
COPY --chown=django:django . /app/
# Create directories for media and static files
RUN mkdir -p /app/media /app/staticfiles && \
chown -R django:django /app/media /app/staticfiles
# Switch to django user
USER django
# Add .local/bin to PATH for installed packages
ENV PATH=/home/django/.local/bin:$PATH
# Set Python to run in unbuffered mode (better for Docker logs)
ENV PYTHONUNBUFFERED=1
# Expose port 8000 for Gunicorn
EXPOSE 8000
# Health check - ping the API endpoint
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/api/ || exit 1
# Entrypoint script handles migrations, static collection, and service startup
ENTRYPOINT ["/app/docker/entrypoint.sh"]
# Default command is to run Gunicorn
CMD ["gunicorn"]
+45
View File
@@ -0,0 +1,45 @@
# ===================================================================
# Development Dockerfile - Fast builds with development tools
# ===================================================================
FROM python:3.12-slim-bookworm
# Install build and runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
default-libmysqlclient-dev \
default-mysql-client \
pkg-config \
curl \
vim \
&& rm -rf /var/lib/apt/lists/*
# Create django user
RUN useradd -m -u 1000 -s /bin/bash django
# Set working directory
WORKDIR /app
# Install Python dependencies
# Note: In dev mode, code is mounted as volume, so we just install deps
COPY requirements.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements.txt \
&& pip install --no-cache-dir mysqlclient gunicorn
# Create directories
RUN mkdir -p /app/media /app/staticfiles && \
chown -R django:django /app
# Switch to django user
USER django
# Set Python to run in unbuffered mode
ENV PYTHONUNBUFFERED=1
# Expose port 8000
EXPOSE 8000
# Entrypoint script handles service startup
ENTRYPOINT ["/app/docker/entrypoint.sh"]
# Default command for dev is Django runserver
CMD ["runserver"]
+111
View File
@@ -0,0 +1,111 @@
.PHONY: help dev dev-build prod build deploy logs logs-web logs-celery shell migrate makemigrations createsuperuser test clean stop restart status backup
# Default target
help:
@echo "KeepItGoing Server - Docker Commands"
@echo "====================================="
@echo ""
@echo "Development:"
@echo " make dev - Start development environment with live reload"
@echo " make dev-build - Rebuild and start development environment"
@echo " make shell - Access Django shell"
@echo " make test - Run tests"
@echo ""
@echo "Production:"
@echo " make prod - Start production environment"
@echo " make build - Build production containers"
@echo " make deploy - Deploy to production (pull, build, migrate, restart)"
@echo ""
@echo "Database:"
@echo " make migrate - Run database migrations"
@echo " make makemigrations - Create new migrations"
@echo " make createsuperuser - Create Django superuser"
@echo " make backup - Backup database"
@echo " make dbshell - Access MariaDB shell"
@echo ""
@echo "Logs & Monitoring:"
@echo " make logs - View all container logs"
@echo " make logs-web - View web container logs"
@echo " make logs-celery - View celery worker logs"
@echo " make status - Show container status"
@echo ""
@echo "Control:"
@echo " make stop - Stop all containers"
@echo " make restart - Restart all containers"
@echo " make clean - Stop and remove containers, networks, volumes"
@echo ""
# Development
dev:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
dev-build:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up --build
# Production
prod:
docker-compose up -d
build:
docker-compose build --no-cache
deploy:
@echo "Deploying to production..."
git pull
docker-compose build
docker-compose up -d
docker-compose exec web python manage.py migrate
docker-compose exec web python manage.py collectstatic --noinput
docker-compose restart web
@echo "Deployment complete!"
@make status
# Database operations
migrate:
docker-compose exec web python manage.py migrate
makemigrations:
docker-compose exec web python manage.py makemigrations
createsuperuser:
docker-compose exec web python manage.py createsuperuser
dbshell:
docker-compose exec mariadb mysql -u keepitgoing -p keepitgoing
backup:
@echo "Creating database backup..."
@mkdir -p backups
docker-compose exec mariadb mysqldump -u root -p keepitgoing > backups/backup-$$(date +%Y%m%d-%H%M%S).sql
@echo "Backup created in backups/ directory"
# Django shell and tests
shell:
docker-compose exec web python manage.py shell
test:
docker-compose exec web python manage.py test
# Logs
logs:
docker-compose logs -f
logs-web:
docker-compose logs -f web
logs-celery:
docker-compose logs -f celery-worker
# Control
stop:
docker-compose down
restart:
docker-compose restart
status:
docker-compose ps
clean:
docker-compose down -v
@echo "Containers, networks, and volumes removed"
+41 -7
View File
@@ -6,6 +6,7 @@ Use this for users running their own instance.
import os
import sys
import dj_database_url
from .base import *
# Security
@@ -28,18 +29,51 @@ if DEBUG:
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
# Database - PostgreSQL for self-hosted
# Database - Support both PostgreSQL and MariaDB/MySQL via DATABASE_URL
# DATABASE_URL format examples:
# PostgreSQL: postgresql://user:password@host:5432/dbname
# MariaDB/MySQL: mysql://user:password@host:3306/dbname
database_url = os.environ.get('DATABASE_URL')
if database_url:
# Use DATABASE_URL for flexible database backend (PostgreSQL, MariaDB, MySQL, etc.)
DATABASES = {
'default': dj_database_url.config(
default=database_url,
conn_max_age=600,
conn_health_checks=True,
)
}
# Add MariaDB/MySQL specific options if using MySQL backend
if 'mysql' in database_url.lower():
DATABASES['default']['OPTIONS'] = {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
}
else:
# Fallback to manual configuration (backwards compatibility)
# Supports both PostgreSQL and MariaDB/MySQL
db_engine = os.environ.get('DB_ENGINE', 'django.db.backends.postgresql')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('POSTGRES_DB', 'keepitgoing'),
'USER': os.environ.get('POSTGRES_USER', 'keepitgoing'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', 'keepitgoing'),
'HOST': os.environ.get('POSTGRES_HOST', 'db'),
'PORT': os.environ.get('POSTGRES_PORT', '5432'),
'ENGINE': db_engine,
'NAME': os.environ.get('DB_NAME', os.environ.get('POSTGRES_DB', 'keepitgoing')),
'USER': os.environ.get('DB_USER', os.environ.get('POSTGRES_USER', 'keepitgoing')),
'PASSWORD': os.environ.get('DB_PASSWORD', os.environ.get('POSTGRES_PASSWORD', 'keepitgoing')),
'HOST': os.environ.get('DB_HOST', os.environ.get('POSTGRES_HOST', 'db')),
'PORT': os.environ.get('DB_PORT', os.environ.get('POSTGRES_PORT', '5432')),
}
}
# Add MariaDB/MySQL specific options if using MySQL backend
if 'mysql' in db_engine:
DATABASES['default']['OPTIONS'] = {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
}
# Redis/Celery
REDIS_URL = os.environ.get('REDIS_URL', 'redis://redis:6379/0')
CELERY_BROKER_URL = REDIS_URL
Executable
+96
View File
@@ -0,0 +1,96 @@
#!/bin/bash
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}KeepItGoing Server - Deployment Script${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
# Check if .env.docker exists
if [ ! -f ".env.docker" ]; then
echo -e "${RED}ERROR: .env.docker file not found!${NC}"
echo -e "${YELLOW}Please copy .env.docker.example to .env.docker and configure it.${NC}"
exit 1
fi
# Step 1: Pull latest code
echo -e "${YELLOW}[1/6] Pulling latest code from git...${NC}"
if git pull; then
echo -e "${GREEN}✓ Code updated${NC}"
else
echo -e "${RED}✗ Git pull failed${NC}"
exit 1
fi
echo ""
# Step 2: Build containers
echo -e "${YELLOW}[2/6] Building Docker containers...${NC}"
if docker-compose build; then
echo -e "${GREEN}✓ Containers built${NC}"
else
echo -e "${RED}✗ Build failed${NC}"
exit 1
fi
echo ""
# Step 3: Start containers
echo -e "${YELLOW}[3/6] Starting containers...${NC}"
if docker-compose up -d; then
echo -e "${GREEN}✓ Containers started${NC}"
else
echo -e "${RED}✗ Failed to start containers${NC}"
exit 1
fi
echo ""
# Step 4: Wait for services to be ready
echo -e "${YELLOW}[4/6] Waiting for services to be ready...${NC}"
sleep 10
echo -e "${GREEN}✓ Services ready${NC}"
echo ""
# Step 5: Run migrations
echo -e "${YELLOW}[5/6] Running database migrations...${NC}"
if docker-compose exec -T web python manage.py migrate --noinput; then
echo -e "${GREEN}✓ Migrations complete${NC}"
else
echo -e "${RED}✗ Migrations failed${NC}"
exit 1
fi
echo ""
# Step 6: Collect static files
echo -e "${YELLOW}[6/6] Collecting static files...${NC}"
if docker-compose exec -T web python manage.py collectstatic --noinput; then
echo -e "${GREEN}✓ Static files collected${NC}"
else
echo -e "${RED}✗ Failed to collect static files${NC}"
exit 1
fi
echo ""
# Restart web service for good measure
echo -e "${YELLOW}Restarting web service...${NC}"
docker-compose restart web
echo -e "${GREEN}✓ Web service restarted${NC}"
echo ""
# Show status
echo -e "${BLUE}========================================${NC}"
echo -e "${GREEN}Deployment Complete!${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
echo -e "${YELLOW}Container Status:${NC}"
docker-compose ps
echo ""
echo -e "${YELLOW}Recent logs:${NC}"
docker-compose logs --tail=20 web
echo ""
echo -e "${GREEN}Deployment successful! ✓${NC}"
+54
View File
@@ -0,0 +1,54 @@
version: '3.8'
# =================================================================
# Development Overrides
# Use with: docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# =================================================================
services:
# Web service overrides for development
web:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
# Mount source code for live reload
- ./:/app
# Override media and static with the same mounts
- ./media:/app/media
- static_files:/app/staticfiles
environment:
# Enable debug mode
DEBUG: "True"
# Use development settings (optional - can still use selfhosted)
DJANGO_SETTINGS_MODULE: config.settings.development
command: runserver
# Remove healthcheck in dev mode (optional)
healthcheck:
disable: true
# Celery worker overrides for development
celery-worker:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
# Mount source code for live reload
- ./:/app
environment:
DEBUG: "True"
DJANGO_SETTINGS_MODULE: config.settings.development
# Celery beat overrides for development
celery-beat:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
# Mount source code for live reload
- ./:/app
environment:
DEBUG: "True"
DJANGO_SETTINGS_MODULE: config.settings.development
# Note: mariadb and redis services inherit from base docker-compose.yml
+148
View File
@@ -0,0 +1,148 @@
version: '3.8'
services:
# =================================================================
# MariaDB Database Service
# =================================================================
mariadb:
image: mariadb:11.2
container_name: keepitgoing-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_NAME:-keepitgoing}
MYSQL_USER: ${DB_USER:-keepitgoing}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_CHARACTER_SET_SERVER: utf8mb4
MYSQL_COLLATION_SERVER: utf8mb4_unicode_ci
volumes:
- db_data:/var/lib/mysql
networks:
- backend
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
# =================================================================
# Redis Service - Message broker for Celery
# =================================================================
redis:
image: redis:7-alpine
container_name: keepitgoing-redis
restart: unless-stopped
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# =================================================================
# Django/Gunicorn Web Service
# =================================================================
web:
build:
context: .
dockerfile: Dockerfile
container_name: keepitgoing-web
restart: unless-stopped
env_file:
- .env.docker
environment:
DJANGO_SETTINGS_MODULE: config.settings.selfhosted
DATABASE_URL: mysql://${DB_USER:-keepitgoing}:${DB_PASSWORD}@mariadb:3306/${DB_NAME:-keepitgoing}
REDIS_URL: redis://redis:6379/0
volumes:
- ./media:/app/media
- static_files:/app/staticfiles
ports:
- "8000:8000"
networks:
- frontend
- backend
depends_on:
mariadb:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# =================================================================
# Celery Worker Service - Background task processor
# =================================================================
celery-worker:
build:
context: .
dockerfile: Dockerfile
container_name: keepitgoing-celery-worker
restart: unless-stopped
env_file:
- .env.docker
environment:
DJANGO_SETTINGS_MODULE: config.settings.selfhosted
DATABASE_URL: mysql://${DB_USER:-keepitgoing}:${DB_PASSWORD}@mariadb:3306/${DB_NAME:-keepitgoing}
REDIS_URL: redis://redis:6379/0
networks:
- backend
depends_on:
mariadb:
condition: service_healthy
redis:
condition: service_healthy
command: celery-worker
# =================================================================
# Celery Beat Service - Scheduled task scheduler
# =================================================================
celery-beat:
build:
context: .
dockerfile: Dockerfile
container_name: keepitgoing-celery-beat
restart: unless-stopped
env_file:
- .env.docker
environment:
DJANGO_SETTINGS_MODULE: config.settings.selfhosted
DATABASE_URL: mysql://${DB_USER:-keepitgoing}:${DB_PASSWORD}@mariadb:3306/${DB_NAME:-keepitgoing}
REDIS_URL: redis://redis:6379/0
networks:
- backend
depends_on:
mariadb:
condition: service_healthy
redis:
condition: service_healthy
command: celery-beat
# =================================================================
# Named Volumes
# =================================================================
volumes:
db_data:
name: keepitgoing_db_data
redis_data:
name: keepitgoing_redis_data
static_files:
name: keepitgoing_static_files
# =================================================================
# Networks
# =================================================================
networks:
frontend:
name: keepitgoing_frontend
backend:
name: keepitgoing_backend
+103
View File
@@ -0,0 +1,103 @@
#!/bin/bash
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}KeepItGoing Docker Entrypoint${NC}"
echo -e "${GREEN}========================================${NC}"
# Extract database host from DATABASE_URL or use DB_HOST env var
DB_HOST=${DB_HOST:-mariadb}
# Wait for MariaDB to be ready
echo -e "${YELLOW}Waiting for MariaDB at ${DB_HOST}...${NC}"
max_attempts=30
attempt=0
while ! mysqladmin ping -h"${DB_HOST}" --silent 2>/dev/null; do
attempt=$((attempt + 1))
if [ $attempt -eq $max_attempts ]; then
echo -e "${RED}ERROR: MariaDB did not become available in time${NC}"
exit 1
fi
echo "Waiting for MariaDB... ($attempt/$max_attempts)"
sleep 2
done
echo -e "${GREEN}✓ MariaDB is ready!${NC}"
# Function to run migrations
run_migrations() {
echo -e "${YELLOW}Running database migrations...${NC}"
python manage.py migrate --noinput
echo -e "${GREEN}✓ Migrations complete${NC}"
}
# Function to collect static files
collect_static() {
echo -e "${YELLOW}Collecting static files...${NC}"
python manage.py collectstatic --noinput
echo -e "${GREEN}✓ Static files collected${NC}"
}
# Determine which service to start based on command argument
case "$1" in
"gunicorn")
echo -e "${GREEN}Starting Gunicorn WSGI server...${NC}"
run_migrations
collect_static
# Get Gunicorn config from environment or use defaults
WORKERS=${GUNICORN_WORKERS:-3}
TIMEOUT=${GUNICORN_TIMEOUT:-60}
echo -e "${GREEN}Configuration:${NC}"
echo " Workers: $WORKERS"
echo " Timeout: $TIMEOUT"
echo " Bind: 0.0.0.0:8000"
exec gunicorn config.wsgi:application \
--bind 0.0.0.0:8000 \
--workers $WORKERS \
--timeout $TIMEOUT \
--access-logfile - \
--error-logfile - \
--log-level info
;;
"celery-worker")
echo -e "${GREEN}Starting Celery worker...${NC}"
# Wait a bit more for web service to run migrations
sleep 5
exec celery -A config worker \
--loglevel=info \
--concurrency=2
;;
"celery-beat")
echo -e "${GREEN}Starting Celery beat scheduler...${NC}"
# Wait for web service to run migrations and create database tables
sleep 10
exec celery -A config beat \
--loglevel=info \
--scheduler django_celery_beat.schedulers:DatabaseScheduler
;;
"runserver")
echo -e "${GREEN}Starting Django development server...${NC}"
run_migrations
collect_static
exec python manage.py runserver 0.0.0.0:8000
;;
*)
# If command is not recognized, just execute it
echo -e "${YELLOW}Executing custom command: $@${NC}"
exec "$@"
;;
esac
+3 -2
View File
@@ -9,8 +9,9 @@ djangorestframework>=3.14.0
djangorestframework-simplejwt>=5.3.0
# Database
psycopg2-binary>=2.9.9
dj-database-url>=2.1.0
psycopg2-binary>=2.9.9 # PostgreSQL driver
mysqlclient>=2.2.0 # MariaDB/MySQL driver
dj-database-url>=2.1.0 # Universal database URL parser
# Task queue
celery>=5.3.0