Internal
Public Access
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:
co-authored by
Claude Sonnet 4.5
parent
a2097dcad3
commit
71399e54b8
@@ -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
|
||||
@@ -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
|
||||
@@ -17,6 +17,7 @@ media/
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.docker
|
||||
*.env.local
|
||||
|
||||
# IDE
|
||||
|
||||
+65
@@ -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"]
|
||||
@@ -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"]
|
||||
@@ -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"
|
||||
@@ -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,17 +29,50 @@ if DEBUG:
|
||||
|
||||
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
|
||||
|
||||
# Database - PostgreSQL for self-hosted
|
||||
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'),
|
||||
# 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': 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')
|
||||
|
||||
@@ -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}"
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+103
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user