version: "3.8" # 天工智能体平台 — 预发布环境 (Staging) # 启动: docker compose -f docker-compose.staging.yml up -d # 与 prod 结构一致,但使用限流资源、简单密码,用于上线前验证 services: mysql: image: mysql:8.0 container_name: aiagent-staging-mysql restart: always environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-staging-db-pass} MYSQL_DATABASE: agent_db_staging MYSQL_CHARSET: utf8mb4 MYSQL_COLLATION: utf8mb4_unicode_ci ports: - "3307:3306" volumes: - staging_mysql_data:/var/lib/mysql - ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql:ro healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 start_period: 30s networks: - staging-net redis: image: redis:7-alpine container_name: aiagent-staging-redis restart: always command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru ports: - "6380:6379" volumes: - staging_redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 5 networks: - staging-net backend: build: context: ./backend dockerfile: Dockerfile container_name: aiagent-staging-backend restart: always environment: - ENVIRONMENT=staging - DEBUG=False - DATABASE_URL=mysql+pymysql://root:${MYSQL_ROOT_PASSWORD:-staging-db-pass}@mysql:3306/agent_db_staging?charset=utf8mb4 - REDIS_URL=redis://redis:6379/0 - JWT_SECRET_KEY=${JWT_SECRET_KEY:-staging-jwt-key} - SECRET_KEY=${SECRET_KEY:-staging-secret-key} - CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:8038,http://localhost:3000} - OPENAI_API_KEY=${OPENAI_API_KEY:-} - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-} - EXTERNAL_URL=${EXTERNAL_URL:-http://localhost} - WORKFLOW_MAX_STEPS_PER_RUN=500 ports: - "8039:8037" depends_on: mysql: condition: service_healthy redis: condition: service_healthy volumes: - staging_agent_workspaces:/app/agent_workspaces - staging_uploads:/app/uploads - staging_logs:/app/logs networks: - staging-net celery-worker: build: context: ./backend dockerfile: Dockerfile container_name: aiagent-staging-celery-worker restart: always command: celery -A app.core.celery_app worker --loglevel=info --concurrency=2 environment: - ENVIRONMENT=staging - DATABASE_URL=mysql+pymysql://root:${MYSQL_ROOT_PASSWORD:-staging-db-pass}@mysql:3306/agent_db_staging?charset=utf8mb4 - REDIS_URL=redis://redis:6379/0 - JWT_SECRET_KEY=${JWT_SECRET_KEY:-staging-jwt-key} - SECRET_KEY=${SECRET_KEY:-staging-secret-key} - OPENAI_API_KEY=${OPENAI_API_KEY:-} - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-} depends_on: mysql: condition: service_healthy redis: condition: service_healthy volumes: - staging_agent_workspaces:/app/agent_workspaces - staging_uploads:/app/uploads - staging_logs:/app/logs networks: - staging-net celery-beat: build: context: ./backend dockerfile: Dockerfile container_name: aiagent-staging-celery-beat restart: always command: celery -A app.core.celery_app beat --loglevel=info environment: - ENVIRONMENT=staging - DATABASE_URL=mysql+pymysql://root:${MYSQL_ROOT_PASSWORD:-staging-db-pass}@mysql:3306/agent_db_staging?charset=utf8mb4 - REDIS_URL=redis://redis:6379/0 - JWT_SECRET_KEY=${JWT_SECRET_KEY:-staging-jwt-key} - SECRET_KEY=${SECRET_KEY:-staging-secret-key} depends_on: mysql: condition: service_healthy redis: condition: service_healthy networks: - staging-net frontend: build: context: ./frontend dockerfile: Dockerfile container_name: aiagent-staging-frontend restart: always ports: - "8040:80" depends_on: - backend networks: - staging-net prometheus: image: prom/prometheus:v2.53.0 container_name: aiagent-staging-prometheus restart: always command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' - '--web.enable-lifecycle' ports: - "9091:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./prometheus-alert-rules.yml:/etc/prometheus/alert_rules.yml:ro - staging_prometheus_data:/prometheus networks: - staging-net grafana: image: grafana/grafana:11.0.0 container_name: aiagent-staging-grafana restart: always environment: - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-admin} - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin123} - GF_USERS_ALLOW_SIGN_UP=false ports: - "3001:3000" volumes: - ./grafana/datasources:/etc/grafana/provisioning/datasources:ro - ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro - ./grafana/dashboards/tiangong-overview.json:/var/lib/grafana/dashboards/tiangong-overview.json:ro - staging_grafana_data:/var/lib/grafana depends_on: - prometheus networks: - staging-net # ─── ELK 日志聚合 ───────────────────────────────────────────────── elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0 container_name: aiagent-staging-elasticsearch restart: always environment: - discovery.type=single-node - ES_JAVA_OPTS=-Xms256m -Xmx512m - xpack.security.enabled=false ports: - "9201:9200" volumes: - staging_es_data:/usr/share/elasticsearch/data healthcheck: test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health | grep -q 'green\|yellow'"] interval: 15s timeout: 10s retries: 10 networks: - staging-net kibana: image: docker.elastic.co/kibana/kibana:8.15.0 container_name: aiagent-staging-kibana restart: always environment: - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 ports: - "5602:5601" depends_on: elasticsearch: condition: service_healthy networks: - staging-net filebeat: image: docker.elastic.co/beats/filebeat:8.15.0 container_name: aiagent-staging-filebeat restart: always volumes: - ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro - staging_logs:/app/logs:ro depends_on: - elasticsearch networks: - staging-net volumes: staging_mysql_data: driver: local staging_redis_data: driver: local staging_agent_workspaces: driver: local staging_uploads: driver: local staging_logs: driver: local staging_prometheus_data: driver: local staging_grafana_data: driver: local staging_es_data: driver: local networks: staging-net: driver: bridge