feat(web): T-WEB-010 部署脚本(Docker Compose,不含 MySQL)

This commit is contained in:
2026-09-14 19:00:55 +08:00
parent 640736c77b
commit 5a8b77b0a4
8 changed files with 475 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
# ============================================================
# OpenDance Studio Web 服务端 —— 部署环境变量
# 复制为 .env 后填写,.env 已被 .gitignore 忽略,禁止提交。
# ============================================================
# ---- 现有 MySQL / MariaDB 实例(本项目不部署、不管理数据库)----
DB_HOST=<existing-mysql-host>
DB_PORT=3306
DB_USER=opendance_app
DB_PASS=<部署方提供>
DB_NAME=opendance
DB_LOGGING=false
# ---- 端口映射(宿主机端口)----
API_PORT=3000
ADMIN_PORT=8080
# ---- 上传与预处理 ----
# 单文件上限(字节),默认 512 MiB
UPLOAD_MAX_BYTES=536870912
# 可选:Assimp 可执行文件(FBX/glTF 动作预处理需要)
ASSIMP_BIN=assimp
+68
View File
@@ -0,0 +1,68 @@
# OpenDance Studio Web 服务端 —— Docker Compose 部署
#
# 重要:本文件**不包含 MySQL 服务**。
# 数据库为部署方提供的现有 MySQL/MariaDB 实例,连接信息由 .env 注入
# (见 contracts/database.md)。
#
# 用法:
# cp .env.example .env # 填写数据库连接信息
# ./install.sh
services:
api:
build:
context: ../web-server
dockerfile: Dockerfile
image: opendance-web-server:0.1.0
container_name: opendance-api
env_file:
- .env
environment:
NODE_ENV: production
PORT: "3000"
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT:-3306}
DB_USER: ${DB_USER}
DB_PASS: ${DB_PASS}
DB_NAME: ${DB_NAME}
# 契约要求:生产环境禁止 synchronize
DB_SYNCHRONIZE: "false"
DB_LOGGING: ${DB_LOGGING:-false}
STORAGE_DIR: /data/storage
UPLOAD_MAX_BYTES: ${UPLOAD_MAX_BYTES:-536870912}
ASSIMP_BIN: ${ASSIMP_BIN:-assimp}
# 挂载的契约快照目录,/health 与 /api/catalog/version 会读取其实时版本
CONTRACTS_DIR: /contracts
ports:
- "${API_PORT:-3000}:3000"
volumes:
- storage:/data/storage
- ../contracts:/contracts:ro
restart: unless-stopped
healthcheck:
test:
- CMD
- node
- -e
- "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
interval: 30s
timeout: 5s
start_period: 20s
retries: 3
admin:
build:
context: ../web-server/admin
dockerfile: Dockerfile
image: opendance-admin:0.1.0
container_name: opendance-admin
ports:
- "${ADMIN_PORT:-8080}:80"
depends_on:
api:
condition: service_healthy
restart: unless-stopped
volumes:
storage:
name: opendance-storage
+104
View File
@@ -0,0 +1,104 @@
#!/bin/bash
# ============================================================
# OpenDance Studio Web 服务端 —— 一键部署脚本
#
# 部署内容:API(NestJS)+ 管理端(静态站点)
# 不部署内容:MySQL —— 数据库为部署方提供的现有实例(见 contracts/database.md)
#
# 用法:
# cp .env.example .env && vi .env
# ./install.sh
# ============================================================
set -euo pipefail
cd "$(dirname "$0")"
log() { printf '\033[1;34m[install]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
# ---------- 1. 前置检查 ----------
if [ ! -f .env ]; then
die "缺少 .env 文件,请从 .env.example 复制并填写数据库连接信息:
cp .env.example .env && vi .env"
fi
# shellcheck disable=SC1091
set -a; . ./.env; set +a
[ -n "${DB_HOST:-}" ] || die ".env 中 DB_HOST 未设置"
[ -n "${DB_USER:-}" ] || die ".env 中 DB_USER 未设置"
[ -n "${DB_NAME:-}" ] || die ".env 中 DB_NAME 未设置"
[ -n "${DB_PASS:-}" ] || die ".env 中 DB_PASS 未设置"
if docker compose version >/dev/null 2>&1; then
DC="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
DC="docker-compose"
else
die "未找到 docker compose 或 docker-compose,请先安装 Docker"
fi
command -v docker >/dev/null 2>&1 || die "未找到 docker"
log "目标数据库:${DB_HOST}:${DB_PORT:-3306}/${DB_NAME}(现有实例,本脚本不会创建或管理 MySQL)"
# ---------- 2. 构建镜像 ----------
log "构建镜像(API + Admin)..."
$DC build
# ---------- 3. 执行数据库迁移 ----------
# 表结构由 TypeORM migration 创建;DB_SYNCHRONIZE 恒为 false
log "执行 TypeORM 迁移..."
$DC run --rm api npm run migration:run
# ---------- 4. 启动服务 ----------
log "启动服务..."
$DC up -d
# ---------- 5. 健康检查 ----------
API_PORT="${API_PORT:-3000}"
ADMIN_PORT="${ADMIN_PORT:-8080}"
HEALTH_URL="http://127.0.0.1:${API_PORT}/health"
log "等待 API 健康检查:${HEALTH_URL}"
ok=0
for i in $(seq 1 30); do
if command -v curl >/dev/null 2>&1; then
if curl -fsS -m 3 "$HEALTH_URL" >/dev/null 2>&1; then ok=1; break; fi
else
if $DC exec -T api node -e "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" >/dev/null 2>&1; then
ok=1; break
fi
fi
sleep 2
done
if [ "$ok" -ne 1 ]; then
warn "健康检查未在 60 秒内通过,最近日志:"
$DC logs --tail=50 api || true
die "部署未通过健康检查"
fi
if command -v curl >/dev/null 2>&1; then
log "健康检查响应:$(curl -fsS -m 5 "$HEALTH_URL")"
fi
HOST_HINT="${DEPLOY_HOST:-<host>}"
cat <<EOF
============================================================
OpenDance Studio Web 服务端已启动
API: http://${HOST_HINT}:${API_PORT}
Admin: http://${HOST_HINT}:${ADMIN_PORT}
健康检查:http://${HOST_HINT}:${API_PORT}/health
数据库:使用现有实例 ${DB_HOST}:${DB_PORT:-3306}/${DB_NAME}
上传存储:Docker 卷 opendance-storage → /data/storage
契约快照:./contracts → 容器内 /contracts(只读)
============================================================
常用命令:
$DC logs -f api # 查看 API 日志
$DC ps # 查看服务状态
$DC down # 停止服务(保留数据卷)
EOF
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# 停止服务(默认保留数据卷)
set -euo pipefail
cd "$(dirname "$0")"
if docker compose version >/dev/null 2>&1; then
DC="docker compose"
else
DC="docker-compose"
fi
$DC down "$@"
echo "服务已停止。数据卷 opendance-storage 未被删除。"
echo "如需一并删除上传数据:$DC down -v"