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: # --------------------------------------------------------------------------- # PostgreSQL — Primary Datastore # --------------------------------------------------------------------------- db: image: postgres:16-alpine container_name: labgraph_db restart: unless-stopped volumes: - 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 # --------------------------------------------------------------------------- # Redis — Celery Broker + Result Backend + Cache Layer # --------------------------------------------------------------------------- redis: image: redis:7-alpine 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: - redis_data:/data ports: - "6379:6379" healthcheck: <<: *healthcheck-defaults test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] networks: - 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: driver: bridge ipam: config: - subnet: 172.20.0.0/16