diff --git a/docker-compose.yml b/docker-compose.yml index adfb0cb..cdb22dc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,9 @@ version: '3.8' +# ── 生产部署配置(含 health check、资源限制) ── + services: + # ── MySQL 8.0 ── mysql: image: mysql:8.0 container_name: zhixi-mysql @@ -22,7 +25,16 @@ services: retries: 5 networks: - zhixi-net + deploy: + resources: + limits: + cpus: '2' + memory: 2G + reservations: + cpus: '0.5' + memory: 512M + # ── Redis 7 ── redis: image: redis:7-alpine container_name: zhixi-redis @@ -38,7 +50,16 @@ services: retries: 5 networks: - zhixi-net + deploy: + resources: + limits: + cpus: '0.5' + memory: 256M + reservations: + cpus: '0.1' + memory: 64M + # ── API Server (NestJS) ── api: build: context: . @@ -65,6 +86,8 @@ services: JWT_SECRET: ${JWT_SECRET:-change_me_in_production} JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-1h} JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-7d} + INTERNAL_API_KEY: ${INTERNAL_API_KEY:-change_me_runtime_key} + CREDENTIAL_ENCRYPTION_KEY: ${CREDENTIAL_ENCRYPTION_KEY:-change_me_32_bytes_key!!} DEV_SECRET: ${DEV_SECRET:-} APPLE_BUNDLE_ID: ${APPLE_BUNDLE_ID:-cloud.longde.AIStudyApp} APPLE_ISSUER: ${APPLE_ISSUER:-https://appleid.apple.com} @@ -84,9 +107,24 @@ services: condition: service_healthy redis: condition: service_healthy + healthcheck: + test: ['CMD', 'wget', '-qO-', 'http://localhost:3000/health'] + interval: 15s + timeout: 5s + retries: 3 + start_period: 30s networks: - zhixi-net + deploy: + resources: + limits: + cpus: '2' + memory: 1G + reservations: + cpus: '0.5' + memory: 256M + # ── API Worker (Prisma CRON / Queue) ── worker: build: context: . @@ -102,12 +140,10 @@ services: REDIS_PASSWORD: '' REDIS_DB: '0' AI_PROVIDER: ${AI_PROVIDER:-mock} - AI_DEFAULT_TIER: ${AI_DEFAULT_TIER:-primary} DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-} DEEPSEEK_BASE_URL: ${DEEPSEEK_BASE_URL:-https://api.deepseek.com} - MINIMAX_API_KEY: ${MINIMAX_API_KEY:-} - MINIMAX_BASE_URL: ${MINIMAX_BASE_URL:-https://api.minimaxi.com} JWT_SECRET: ${JWT_SECRET:-change_me_in_production} + INTERNAL_API_KEY: ${INTERNAL_API_KEY:-change_me_runtime_key} STORAGE_DRIVER: ${STORAGE_DRIVER:-cos} STORAGE_COS_SECRET_ID: ${STORAGE_COS_SECRET_ID:-} STORAGE_COS_SECRET_KEY: ${STORAGE_COS_SECRET_KEY:-} @@ -121,7 +157,53 @@ services: condition: service_healthy networks: - zhixi-net + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.25' + memory: 128M + # ── Heavy Runtime (Rust AI Worker) ── + heavy-runtime: + build: + context: ../zhixi-heavy-runtime + dockerfile: Dockerfile + image: zhixi-heavy-runtime:latest + container_name: zhixi-heavy-runtime + restart: unless-stopped + environment: + RUST_LOG: ${RUNTIME_LOG_LEVEL:-info} + RUNTIME_INSTANCE_ID: heavy-runtime-1 + API_INTERNAL_BASE_URL: http://api:3000 + RUNTIME_SERVICE_TOKEN: ${INTERNAL_API_KEY:-change_me_runtime_key} + DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-} + MAX_CONCURRENCY: '4' + POLL_INTERVAL_MS: '5000' + JOB_TIMEOUT_SECONDS: '120' + HTTP_TIMEOUT_SECONDS: '30' + depends_on: + - api + healthcheck: + test: ['CMD', 'wget', '-qO-', 'http://localhost:8080/health'] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + networks: + - zhixi-net + deploy: + resources: + limits: + cpus: '2' + memory: 1G + reservations: + cpus: '0.5' + memory: 256M + + # ── NGINX ── nginx: image: nginx:1.25-alpine container_name: zhixi-nginx @@ -134,8 +216,21 @@ services: - ./nginx/conf.d:/etc/nginx/conf.d:ro depends_on: - api + healthcheck: + test: ['CMD', 'wget', '-qO-', 'http://localhost/health'] + interval: 15s + timeout: 5s + retries: 3 networks: - zhixi-net + deploy: + resources: + limits: + cpus: '0.5' + memory: 128M + reservations: + cpus: '0.1' + memory: 32M volumes: mysql_data: