api-server/docker-compose.yml
wangdl 094f00553a
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 45s
feat: production docker-compose with health checks + resource limits (API-AI-077)
- Add health checks: api (GET /health), worker, heavy-runtime, nginx
- Add resource limits (deploy.resources) for all 6 services
- Add heavy-runtime service (Rust AI Worker)
- Add INTERNAL_API_KEY + CREDENTIAL_ENCRYPTION_KEY env vars
- nginx health check via GET /health

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 13:53:24 +08:00

244 lines
6.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

version: '3.8'
# ── 生产部署配置(含 health check、资源限制 ──
services:
# ── MySQL 8.0 ──
mysql:
image: mysql:8.0
container_name: zhixi-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword}
MYSQL_DATABASE: zhixi
MYSQL_USER: zhixi_user
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Zhixi@2026!App}
ports:
- '3307:3306'
volumes:
- mysql_data:/var/lib/mysql
- ./prisma/init:/docker-entrypoint-initdb.d
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 10s
timeout: 5s
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
restart: unless-stopped
ports:
- '6379:6379'
volumes:
- redis_data:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 5s
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: .
dockerfile: Dockerfile
image: zhixi-api:latest
container_name: zhixi-api
restart: unless-stopped
ports:
- '3000:3000'
environment:
NODE_ENV: production
PORT: '3000'
DATABASE_URL: mysql://zhixi_user:${MYSQL_PASSWORD:-Zhixi@2026!App}@mysql:3306/zhixi
REDIS_HOST: redis
REDIS_PORT: '6379'
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}
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}
APPLE_JWKS_URL: ${APPLE_JWKS_URL:-https://appleid.apple.com/auth/keys}
ENABLE_SWAGGER: ${ENABLE_SWAGGER:-false}
SWAGGER_USER: ${SWAGGER_USER:-admin}
SWAGGER_PASSWORD: ${SWAGGER_PASSWORD:-}
STORAGE_DRIVER: ${STORAGE_DRIVER:-cos}
STORAGE_LOCAL_PATH: ./uploads
STORAGE_COS_SECRET_ID: ${STORAGE_COS_SECRET_ID:-}
STORAGE_COS_SECRET_KEY: ${STORAGE_COS_SECRET_KEY:-}
STORAGE_COS_BUCKET: ${STORAGE_COS_BUCKET:-}
STORAGE_COS_REGION: ${STORAGE_COS_REGION:-ap-beijing}
STORAGE_COS_DOMAIN: ${STORAGE_COS_DOMAIN:-}
depends_on:
mysql:
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: .
dockerfile: Dockerfile.worker
image: zhixi-worker:latest
container_name: zhixi-worker
restart: unless-stopped
environment:
NODE_ENV: production
DATABASE_URL: mysql://zhixi_user:${MYSQL_PASSWORD:-Zhixi@2026!App}@mysql:3306/zhixi
REDIS_HOST: redis
REDIS_PORT: '6379'
REDIS_PASSWORD: ''
REDIS_DB: '0'
AI_PROVIDER: ${AI_PROVIDER:-mock}
DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-}
DEEPSEEK_BASE_URL: ${DEEPSEEK_BASE_URL:-https://api.deepseek.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:-}
STORAGE_COS_BUCKET: ${STORAGE_COS_BUCKET:-}
STORAGE_COS_REGION: ${STORAGE_COS_REGION:-ap-beijing}
STORAGE_COS_DOMAIN: ${STORAGE_COS_DOMAIN:-}
depends_on:
mysql:
condition: service_healthy
redis:
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
restart: unless-stopped
ports:
- '80:80'
- '443:443'
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./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:
driver: local
redis_data:
driver: local
networks:
zhixi-net:
driver: bridge