version: '3.8' services: api: image: ${KGRAPH_IMAGE:-kgraph-mcp:prod-latest} container_name: kgraph-mcp-prod environment: - ENVIRONMENT=production - DATABASE_URL=${DATABASE_URL} - REDIS_URL=${REDIS_URL} - DEBUG=false - LOG_LEVEL=WARNING - SENTRY_DSN=${SENTRY_DSN} - SECRET_KEY=${SECRET_KEY} - ALLOWED_HOSTS=${ALLOWED_HOSTS:-api.kgraph-mcp.example.com} ports: - "8000:8000" volumes: - ./logs:/app/logs:rw - ./data:/app/data:ro depends_on: postgres: condition: service_healthy redis: condition: service_healthy restart: always networks: - kgraph-prod deploy: mode: replicated replicas: 3 resources: limits: cpus: '4' memory: 4G reservations: cpus: '2' memory: 2G update_config: parallelism: 1 delay: 10s failure_action: rollback restart_policy: condition: any delay: 5s max_attempts: 3 postgres: image: postgres:15-alpine container_name: kgraph-postgres-prod environment: - POSTGRES_USER=${DB_USER} - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=${DB_NAME:-kgraph_prod} - POSTGRES_INITDB_ARGS=--encoding=UTF8 --lc-collate=en_US.utf8 --lc-ctype=en_US.utf8 volumes: - postgres_data:/var/lib/postgresql/data - ./backups:/backups - ./postgres/postgresql.conf:/etc/postgresql/postgresql.conf:ro command: postgres -c config_file=/etc/postgresql/postgresql.conf healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME:-kgraph_prod}"] interval: 10s timeout: 5s retries: 5 networks: - kgraph-prod deploy: resources: limits: cpus: '4' memory: 8G redis: image: redis:7-alpine container_name: kgraph-redis-prod command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 2gb --maxmemory-policy allkeys-lru volumes: - redis_data:/data - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro healthcheck: test: ["CMD", "redis-cli", "--raw", "incr", "ping"] interval: 10s timeout: 5s retries: 5 networks: - kgraph-prod deploy: resources: limits: cpus: '2' memory: 2G nginx: image: nginx:alpine container_name: kgraph-nginx-prod ports: - "80:80" - "443:443" volumes: - ./nginx/prod.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro - ./static:/usr/share/nginx/html/static:ro depends_on: - api restart: always networks: - kgraph-prod deploy: resources: limits: cpus: '1' memory: 512M # Monitoring prometheus: image: prom/prometheus:latest container_name: kgraph-prometheus-prod volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/usr/share/prometheus/console_libraries' - '--web.console.templates=/usr/share/prometheus/consoles' ports: - "9090:9090" networks: - kgraph-prod restart: always grafana: image: grafana/grafana:latest container_name: kgraph-grafana-prod environment: - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD} - GF_USERS_ALLOW_SIGN_UP=false volumes: - grafana_data:/var/lib/grafana - ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro - ./grafana/datasources:/etc/grafana/provisioning/datasources:ro ports: - "3000:3000" depends_on: - prometheus networks: - kgraph-prod restart: always # Backup service postgres-backup: image: postgres:15-alpine container_name: kgraph-backup-prod environment: - PGUSER=${DB_USER} - PGPASSWORD=${DB_PASSWORD} - PGDATABASE=${DB_NAME:-kgraph_prod} - PGHOST=postgres volumes: - ./backups:/backups - ./scripts/backup.sh:/backup.sh:ro command: /bin/sh -c "while true; do /backup.sh; sleep 86400; done" depends_on: - postgres networks: - kgraph-prod volumes: postgres_data: driver: local redis_data: driver: local prometheus_data: driver: local grafana_data: driver: local networks: kgraph-prod: driver: bridge ipam: config: - subnet: 172.20.0.0/16