# ⚠️ Docker Compose v2 顶级 name 必须匹配正则 ^[a-z0-9][a-z0-9_-]*$ # 不能有大写、空格、括号、中文,否则会报 name Does not match pattern 错误 name: byw-voicehub services: # ======================================================================== # 应用本体 - Nuxt 4 (Node SSR) # - 使用两阶段构建 Dockerfile,构建阶段内存友好 # - PREBUILT=true:告诉 scripts/deploy.js 跳过 npm install 和 nuxt build # (因为第一阶段已经 build 好了,产物在 .output/ 里) # ======================================================================== voicehub: image: byw-voicehub:1.7.0.0 build: context: . dockerfile: Dockerfile args: BUILDKIT_INLINE_CACHE: "1" container_name: voicehub-app restart: unless-stopped ports: # 左边是宿主机端口(对外),右边是容器内端口(固定 3000) # 如果要套 Nginx,就只监听 127.0.0.1:4456:3000 不直接暴露外网 - "4456:3000" depends_on: postgres: condition: service_healthy redis: condition: service_healthy env_file: # 把密码、密钥都写在项目根的 .env 里,不要直接写进这个 yaml - .env environment: # ===== 运行时基础(可以被 .env 覆盖) ===== NODE_ENV: production PORT: 3000 HOST: 0.0.0.0 PREBUILT: "true" SKIP_INSTALL: "true" SKIP_BUILD: "true" NITRO_PRESET: node-server # ===== 数据库连接串(.env 写了就用 .env,没写就自动拼 compose 内部 postgres 服务) ===== DATABASE_URL: ${DATABASE_URL:-postgresql://${POSTGRES_USER:-voicehub}:${POSTGRES_PASSWORD:-voicehub}@postgres:5432/${POSTGRES_DB:-voicehub}?sslmode=disable} # ===== Redis 连接串(同上,自动拼内部 redis 服务) ===== REDIS_URL: ${REDIS_URL:-redis://${REDIS_PASSWORD:+:${REDIS_PASSWORD}@}redis:6379/0} # ===== 会话/Token(必须在 .env 里设,这里给一个占位提醒) ===== JWT_SECRET: ${JWT_SECRET:-请在.env里设置JWT_SECRET用openssl rand -hex 32生成} # ===== 应用默认(可在 .env 覆盖,不会覆盖 .env 里同名字段) ===== NUXT_PUBLIC_SITE_URL: ${NUXT_PUBLIC_SITE_URL:-http://127.0.0.1:4456} NUXT_PUBLIC_SITE_TITLE: ${NUXT_PUBLIC_SITE_TITLE:-校园广播站点歌系统} NUXT_PUBLIC_DEFAULT_THEME: ${NUXT_PUBLIC_DEFAULT_THEME:-dark} NUXT_PUBLIC_ENABLED_THEMES: ${NUXT_PUBLIC_ENABLED_THEMES:-dark,light} # ===== 日志/性能 ===== NODE_OPTIONS: ${NODE_OPTIONS:-"--max-old-space-size=768"} # 2C4G 机器的推荐配置(.env 可覆盖);小机器 1C2G 也能跑 # ⚠️ 注意:cpus 默认值不能加双引号!新版 Docker Compose v2 严格类型: # 加引号会解析为字符串 '"1.5"' → ParseFloat 失败报错 mem_limit: ${APP_MEM_LIMIT:-1400m} mem_reservation: ${APP_MEM_RESERVATION:-384m} cpus: ${APP_CPUS:-1.5} deploy: resources: limits: cpus: ${APP_CPUS_LIMIT:-2} memory: ${APP_MEM_LIMIT:-1400M} reservations: cpus: ${APP_CPUS_RESERVATION:-0.5} memory: ${APP_MEM_RESERVATION:-384M} healthcheck: # 30s 后开始检查,每 15s 一次,连续 3 次失败就重启 test: [ "CMD", "node", "-e", "fetch('http://127.0.0.1:3000/').then(r=>{process.exit(r.ok?0:1)}).catch(()=>process.exit(1))" ] interval: 15s timeout: 5s retries: 3 start_period: 30s networks: - voicehub-net volumes: # (可选)把自定义 logo/上传资源挂到宿主机 - voicehub-uploads:/app/app/public/uploads:rw # ======================================================================== # PostgreSQL 16 - 主数据库 # ======================================================================== postgres: image: postgres:16-alpine container_name: voicehub-postgres restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-voicehub} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-请在.env里改这个密码} POSTGRES_DB: ${POSTGRES_DB:-voicehub} PGDATA: /var/lib/postgresql/data/pgdata # .env 里没设 DATABASE_URL 时,自动拼一份给 app 用 # (如果 .env 里已经写了外部 Postgres,就以 .env 为准) healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-voicehub} -d ${POSTGRES_DB:-voicehub}"] interval: 5s timeout: 5s retries: 10 volumes: - postgres-data:/var/lib/postgresql/data # 如需从宿主机用 Navicat 连,取消下一行注释 # ports: # - "127.0.0.1:5433:5432" mem_limit: ${PG_MEM_LIMIT:-1200m} mem_reservation: ${PG_MEM_RESERVATION:-256m} cpus: ${PG_CPUS:-"1.0"} networks: - voicehub-net # ======================================================================== # Redis 7 - 缓存 / 会话 / 限流 / 队列 # ======================================================================== redis: image: redis:7-alpine container_name: voicehub-redis restart: unless-stopped command: > sh -c " if [ -n \"$$REDIS_PASSWORD\" ]; then redis-server --appendonly yes --requirepass \"$$REDIS_PASSWORD\" else redis-server --appendonly yes fi " environment: REDIS_PASSWORD: ${REDIS_PASSWORD:-} healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 10 volumes: - redis-data:/data mem_limit: ${REDIS_MEM_LIMIT:-384m} mem_reservation: ${REDIS_MEM_RESERVATION:-64m} cpus: ${REDIS_CPUS:-0.5} networks: - voicehub-net volumes: postgres-data: name: voicehub-postgres-data redis-data: name: voicehub-redis-data voicehub-uploads: name: voicehub-uploads networks: voicehub-net: name: voicehub-net driver: bridge