fa65a401a5
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / PR Build API Image (pull_request) Failing after 23s
CI/CD Pipeline / PR Build Worker Image (pull_request) Failing after 23s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 56s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 1m26s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 1m27s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m47s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m44s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 5m13s
AI Code Review / AI Code Review (pull_request) Successful in 6m17s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 6m41s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 2s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m9s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 126h33m42s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 126h33m43s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 126h40m16s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 126h40m21s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 126h40m10s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 126h40m11s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 126h39m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 126h39m59s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 126h40m3s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 126h40m4s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 126h40m8s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 126h40m8s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 126h40m15s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 126h39m53s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 126h33m30s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 126h33m30s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 126h33m29s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 126h39m53s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 126h40m10s
Problem: web Dockerfile used ARG NGINX_CONF to bake a single nginx config at build time. CI always built from develop branch with nginx-staging.conf, so the production image also contained the staging nginx config pointing to xiaoxia-api-staging:8000, causing 502 in production after restarts. Fix: - Bake all 3 nginx configs (default/nginx.conf, nginx-staging.conf, nginx-production.conf) into the web image - Add nginx-entrypoint.sh that symlinks the correct config based on APP_ENV (staging/production) at container startup - Remove NGINX_CONF build arg from CI pipeline (3 occurrences) - Update deploy scripts to pass APP_ENV to web container - Update compose.yml to use APP_ENV instead of NGINX_ENV This ensures a single image artifact works for both staging and production, with the correct nginx upstream selected at runtime via environment variable.
232 lines
7.3 KiB
YAML
Executable File
232 lines
7.3 KiB
YAML
Executable File
# ===========================================
|
|
# 小虾剪辑 SaaS Docker Compose 配置
|
|
# ===========================================
|
|
#
|
|
# 用法:
|
|
# Staging: docker compose --env-file ../../.env -f compose.yml up -d
|
|
# Production: 设置相关环境变量后执行
|
|
#
|
|
# 环境变量说明:
|
|
# API_IMAGE - API 镜像名称 (默认: xiaoxia-saas-api:dev)
|
|
# WORKER_IMAGE - Worker 镜像名称 (默认: xiaoxia-saas-worker:dev)
|
|
# WEB_IMAGE - Web 镜像名称 (默认: xiaoxia-saas-web:dev)
|
|
# WEB_DOCKERFILE - Web Dockerfile 路径
|
|
# WEB_NGINX_CONF - Nginx 配置文件路径
|
|
# API_PORT - API 端口映射 (staging: 8000, production: 8001)
|
|
# WEB_PORT - Web 端口映射 (staging: 3001, production: 3002)
|
|
# GENERATED_FILES_HOST_DIR - 生成文件的主机目录
|
|
# WORKER_CONCURRENCY - Worker 并发数 (默认: 4)
|
|
# WORKER_MAX_TASKS_PER_CHILD - Worker 每个子进程最大任务数 (默认: 100)
|
|
#
|
|
# 重要:
|
|
# - 生产环境不要挂载 web-dist volume,否则会导致 403
|
|
# - 确保环境隔离网络已创建: docker network create xiaoxia-net-${ENV}
|
|
# - ENV=staging → xiaoxia-net-staging
|
|
# - ENV=production → xiaoxia-net-production
|
|
#
|
|
|
|
# ===========================================
|
|
# 日志轮转配置(所有服务共享)
|
|
# ===========================================
|
|
x-logging: &default-logging
|
|
driver: json-file
|
|
options:
|
|
max-size: "50m"
|
|
max-file: "3"
|
|
|
|
services:
|
|
# =========================================
|
|
# API 服务
|
|
# =========================================
|
|
api:
|
|
image: ${API_IMAGE:-xiaoxia-saas-api:dev}
|
|
# 不在生产环境构建镜像,使用预构建的镜像
|
|
# build:
|
|
# context: ../..
|
|
# dockerfile: infra/docker/api.Dockerfile
|
|
|
|
container_name: xiaoxia-api-${ENV:-staging}
|
|
restart: unless-stopped
|
|
stop_grace_period: 30s
|
|
stop_signal: SIGTERM
|
|
|
|
# 环境变量文件(包含数据库密码等敏感信息)
|
|
env_file:
|
|
- ../../.env
|
|
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-staging}
|
|
APP_VERSION: ${APP_VERSION:-unknown}
|
|
GENERATED_FILES_DIR: /app/generated
|
|
GENERATED_FILES_URL_PREFIX: /generated-files
|
|
PUBLIC_API_BASE_URL: ${PUBLIC_API_BASE_URL:-https://api.xiaoxiajianji.com}
|
|
|
|
# 端口映射
|
|
# Staging: 8000 -> 8000
|
|
# Production: 8001 -> 8000
|
|
ports:
|
|
- "127.0.0.1:${API_PORT:-8000}:8000"
|
|
|
|
# 共享生成文件目录
|
|
volumes:
|
|
- generated-files:/app/generated
|
|
|
|
networks:
|
|
- xiaoxia-net
|
|
|
|
# 健康检查配置
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health', timeout=5)"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
|
|
logging: *default-logging
|
|
|
|
# =========================================
|
|
# 资源限制建议(生产环境建议启用)
|
|
# =========================================
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '2.0'
|
|
memory: 2g
|
|
reservations:
|
|
cpus: '0.5'
|
|
memory: 512M
|
|
|
|
# =========================================
|
|
# Worker 服务(Celery 任务队列)
|
|
# =========================================
|
|
worker:
|
|
image: ${WORKER_IMAGE:-xiaoxia-saas-worker:dev}
|
|
|
|
container_name: xiaoxia-worker-${ENV:-staging}
|
|
restart: unless-stopped
|
|
stop_grace_period: 300s
|
|
stop_signal: SIGTERM
|
|
|
|
env_file:
|
|
- ../../.env
|
|
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-staging}
|
|
APP_VERSION: ${APP_VERSION:-unknown}
|
|
WORKER_CONCURRENCY: ${WORKER_CONCURRENCY:-4}
|
|
WORKER_MAX_TASKS_PER_CHILD: ${WORKER_MAX_TASKS_PER_CHILD:-100}
|
|
# #1714 队列隔离:generation 队列独占 worker(默认并发 2),其余并发给转码
|
|
GENERATION_CONCURRENCY: ${GENERATION_CONCURRENCY:-2}
|
|
GENERATED_FILES_DIR: /app/generated
|
|
GENERATED_FILES_URL_PREFIX: /generated-files
|
|
PUBLIC_API_BASE_URL: ${PUBLIC_API_BASE_URL:-https://api.xiaoxiajianji.com}
|
|
|
|
volumes:
|
|
- generated-files:/app/generated
|
|
|
|
networks:
|
|
- xiaoxia-net
|
|
|
|
# 健康检查配置
|
|
# 注:容器内无 pgrep/ps,扫描 /proc 所有进程的 cmdline 查找 celery 进程
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "grep -lq celery /proc/[0-9]*/cmdline 2>/dev/null || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
|
|
logging: *default-logging
|
|
|
|
# =========================================
|
|
# 资源限制建议(生产环境建议启用)
|
|
# =========================================
|
|
# 注意: Worker 需要处理视频,建议分配更多资源
|
|
# #1714 队列隔离后容器内运行 generation + transcode 两个 worker 进程,
|
|
# 总并发 = WORKER_CONCURRENCY(默认 4),4C8G 以上确保视频渲染不 OOM
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '4.0'
|
|
memory: 8g
|
|
reservations:
|
|
cpus: '1.0'
|
|
memory: 2G
|
|
|
|
# =========================================
|
|
# Web 服务(Nginx + 前端静态文件)
|
|
# =========================================
|
|
web:
|
|
image: ${WEB_IMAGE:-xiaoxia-saas-web:dev}
|
|
# 不在生产环境构建镜像,使用 web-artifact.Dockerfile
|
|
# build:
|
|
# context: ../..
|
|
# dockerfile: ${WEB_DOCKERFILE:-infra/docker/web.Dockerfile}
|
|
# args:
|
|
# (NGINX_CONF no longer needed - all configs baked into image)
|
|
|
|
container_name: xiaoxia-web-${ENV:-staging}
|
|
restart: unless-stopped
|
|
|
|
# 端口映射
|
|
# Staging: 3001 -> 80
|
|
# Production: 3002 -> 80 (通过 Nginx 反向代理)
|
|
ports:
|
|
- "127.0.0.1:${WEB_PORT:-3001}:80"
|
|
|
|
networks:
|
|
- xiaoxia-net
|
|
|
|
# =========================================
|
|
# Nginx 配置运行时覆盖(双保险:entrypoint 也按 APP_ENV 选择配置)
|
|
# 确保容器使用正确环境的 nginx 配置,即使镜像构建时使用了默认配置
|
|
# 注意: 只覆盖 /etc/nginx/conf.d/default.conf,不挂载 /usr/share/nginx/html
|
|
# =========================================
|
|
environment:
|
|
- APP_ENV=${ENV:-staging}
|
|
volumes:
|
|
- ./nginx-${ENV:-staging}.conf:/etc/nginx/conf.d/default.conf:ro
|
|
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:80"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
logging: *default-logging
|
|
|
|
# =========================================
|
|
# 资源限制建议
|
|
# =========================================
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '0.5'
|
|
memory: 512M
|
|
|
|
# ===========================================
|
|
# 共享卷配置
|
|
# ===========================================
|
|
volumes:
|
|
generated-files:
|
|
driver: local
|
|
driver_opts:
|
|
type: none
|
|
o: bind
|
|
# 重要: 确保主机目录存在且有正确权限
|
|
# Staging: /var/lib/xiaoxia-saas-staging/generated
|
|
# Production: /var/lib/xiaoxia-saas-production/generated
|
|
device: ${GENERATED_FILES_HOST_DIR:?GENERATED_FILES_HOST_DIR must be set in .env}
|
|
|
|
# ===========================================
|
|
# 网络配置
|
|
# ===========================================
|
|
networks:
|
|
xiaoxia-net:
|
|
external: true
|
|
# 网络名根据 ENV 变量区分,实现 staging/production 环境隔离
|
|
# staging: xiaoxia-net-staging
|
|
# production: xiaoxia-net-production
|
|
name: xiaoxia-net-${ENV:-staging}
|
|
|