diff --git a/docker-compose.yml b/docker-compose.yml index 534f29d7..1ca8e9f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,54 +1,207 @@ +version: "3.9" + +# ============================================================================= +# LabGraph — Docker Compose Orchestration +# Services: web (Django/Gunicorn), db (PostgreSQL), redis, celery-worker, +# celery-beat (scheduler), flower (Celery monitoring) +# ============================================================================= + +x-django-env: &django-env + env_file: .env + environment: + DJANGO_SETTINGS_MODULE: config.settings.development + +x-healthcheck-defaults: &healthcheck-defaults + interval: 15s + timeout: 5s + retries: 5 + start_period: 20s + services: - app: - build: - context: . - dockerfile: .devcontainer/Dockerfile.backend - volumes: - - .:/workspace:cached - environment: - - DATABASE_URL=postgres://postgres:password@db:5432/labgraph - - REDIS_URL=redis://redis:6379/0 - networks: - - labgraph-net - depends_on: - - db - - redis - command: sleep infinity # Keeps the container alive for VS Code - + # --------------------------------------------------------------------------- + # PostgreSQL — Primary Datastore + # --------------------------------------------------------------------------- db: - image: postgres:18-alpine - environment: - - POSTGRES_DB=labgraph - - POSTGRES_PASSWORD=password + image: postgres:16-alpine + container_name: labgraph_db + restart: unless-stopped volumes: - - labgraph_pg_data:/var/lib/postgresql + - postgres_data:/var/lib/postgresql/data + - ./backend/scripts/init_db.sql:/docker-entrypoint-initdb.d/init_db.sql:ro + environment: + POSTGRES_DB: ${POSTGRES_DB:-labgraph} + POSTGRES_USER: ${POSTGRES_USER:-labgraph} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set} + ports: + - "5432:5432" + healthcheck: + <<: *healthcheck-defaults + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-labgraph} -d ${POSTGRES_DB:-labgraph}"] networks: - - labgraph-net + - labgraph_net + # --------------------------------------------------------------------------- + # Redis — Celery Broker + Result Backend + Cache Layer + # --------------------------------------------------------------------------- redis: image: redis:7-alpine - networks: - - labgraph-net - - worker: - build: - context: . - dockerfile: .devcontainer/Dockerfile.backend + container_name: labgraph_redis + restart: unless-stopped + command: > + redis-server + --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD must be set} + --maxmemory 256mb + --maxmemory-policy allkeys-lru + --save 60 1 + --loglevel warning volumes: - - .:/workspace:cached - environment: - - DATABASE_URL=postgres://postgres:password@db:5432/labgraph - - REDIS_URL=redis://redis:6379/0 - depends_on: - - db - - redis + - redis_data:/data + ports: + - "6379:6379" + healthcheck: + <<: *healthcheck-defaults + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] networks: - - labgraph-net - command: celery -A core worker --loglevel=info + - labgraph_net + + # --------------------------------------------------------------------------- + # Django Web — Gunicorn + DRF API + # --------------------------------------------------------------------------- + web: + build: + context: ./backend + dockerfile: Dockerfile + target: development + container_name: labgraph_web + restart: unless-stopped + <<: *django-env + command: > + sh -c "python manage.py migrate --noinput && + python manage.py collectstatic --noinput && + gunicorn config.wsgi:application + --bind 0.0.0.0:8000 + --workers 4 + --worker-class gthread + --threads 2 + --timeout 120 + --access-logfile - + --error-logfile -" + volumes: + - ./backend:/app + - static_volume:/app/staticfiles + - media_volume:/app/mediafiles + - wiki_data:/app/wiki_store + ports: + - "8000:8000" + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + healthcheck: + <<: *healthcheck-defaults + test: ["CMD-SHELL", "curl -fs http://localhost:8000/api/health/ || exit 1"] + networks: + - labgraph_net + + # --------------------------------------------------------------------------- + # Celery Worker — Discovery + Heartbeat Tasks + # --------------------------------------------------------------------------- + celery-worker: + build: + context: ./backend + dockerfile: Dockerfile + target: development + container_name: labgraph_celery_worker + restart: unless-stopped + <<: *django-env + command: > + celery -A config.celery worker + --loglevel=info + --concurrency=4 + --queues=discovery,heartbeat,default + --hostname=worker@%h + --max-tasks-per-child=100 + volumes: + - ./backend:/app + - wiki_data:/app/wiki_store + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + networks: + - labgraph_net + + # --------------------------------------------------------------------------- + # Celery Beat — Periodic Task Scheduler + # --------------------------------------------------------------------------- + celery-beat: + build: + context: ./backend + dockerfile: Dockerfile + target: development + container_name: labgraph_celery_beat + restart: unless-stopped + <<: *django-env + command: > + celery -A config.celery beat + --loglevel=info + --scheduler django_celery_beat.schedulers:DatabaseScheduler + volumes: + - ./backend:/app + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + networks: + - labgraph_net + + # --------------------------------------------------------------------------- + # Flower — Real-time Celery Task Monitor (Dev Only) + # --------------------------------------------------------------------------- + flower: + build: + context: ./backend + dockerfile: Dockerfile + target: development + container_name: labgraph_flower + restart: unless-stopped + <<: *django-env + command: > + celery -A config.celery flower + --port=5555 + --basic_auth=${FLOWER_USER:-admin}:${FLOWER_PASSWORD:-changeme} + --url_prefix=flower + ports: + - "5555:5555" + depends_on: + redis: + condition: service_healthy + networks: + - labgraph_net + profiles: + - dev-tools + +# ============================================================================= +# Volumes & Networks +# ============================================================================= +volumes: + postgres_data: + driver: local + redis_data: + driver: local + static_volume: + driver: local + media_volume: + driver: local + wiki_data: + driver: local networks: - labgraph-net: + labgraph_net: driver: bridge - -volumes: - labgraph_pg_data: \ No newline at end of file + ipam: + config: + - subnet: 172.20.0.0/16 \ No newline at end of file