Add one-click deploy script for /opt production setup with PM2.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-12 13:32:06 +08:00
parent 5e95d3af2f
commit b38b821c35
5 changed files with 519 additions and 32 deletions
+127 -10
View File
@@ -2,12 +2,14 @@
本文档面向 **Ubuntu 物理服务器**(搭载 RTX 3060 Ti,已锁定 120W 功耗墙)的完整环境配置与 PM2 常驻部署流程。适用于首次安装或迁移重装场景。
**标准安装路径:** `/opt/Trading_Studio`root 用户)
**Git 仓库:** https://git.bz121.com/dekun/Trading_Studio.git
---
## 目录
0. [**一键部署(推荐)**](#0-一键部署推荐)
1. [硬件与系统前提](#1-硬件与系统前提)
2. [3060 Ti 120W 功耗墙配置](#2-3060-ti-120w-功耗墙配置)
3. [NVIDIA 驱动与 CUDA](#3-nvidia-驱动与-cuda)
@@ -21,6 +23,112 @@
---
## 0. 一键部署(推荐)
项目内置 `deploy.sh`,以 **root** 用户将 Trading Studio 部署到 `/opt/Trading_Studio`,并自动完成依赖安装、虚拟环境、PyTorch CUDA、PM2 常驻与开机自启。
### 0.1 前提条件
在运行脚本前,请确保服务器已满足:
| 项目 | 说明 |
|------|------|
| 系统 | Ubuntu 22.04 / 24.04 LTS |
| 用户 | **root**`sudo -i` 切换) |
| GPU 驱动 | `nvidia-smi` 可正常输出 |
| 网络 | 可访问 `git.bz121.com` 拉取代码 |
| Ollama | 局域网 `192.168.8.64:11434` 可达(润色功能) |
> **Git 认证:** 若 `git clone` 需要登录,请先在 root 下配置 HTTPS 凭据或 SSH 密钥,再执行部署脚本。
### 0.2 首次一键部署
```bash
# 切换 root
sudo -i
# 方式 A:从 Git 克隆后执行(推荐)
git clone https://git.bz121.com/dekun/Trading_Studio.git /opt/Trading_Studio
cd /opt/Trading_Studio
chmod +x deploy.sh
bash deploy.sh
# 方式 B:若已有本地代码目录,直接在该目录执行
cd /opt/Trading_Studio
chmod +x deploy.sh
bash deploy.sh
```
脚本自动执行以下步骤:
1. 安装系统依赖(python3、ffmpeg、libsndfile 等)
2. 安装 Node.js 20 + PM2
3. 克隆/更新代码到 `/opt/Trading_Studio`
4. 创建 `venv/` 并安装 PyTorch cu121 + requirements.txt
5. 创建 `logs/``uploads/``outputs/` 目录
6. 设置 GPU 120W 功耗墙(若 nvidia-smi 可用)
7. 放行防火墙端口 5683(若 ufw 已启用)
8. `pm2 start ecosystem.config.js` 并配置开机自启
部署成功后访问:
```
http://<服务器局域网IP>:5683
```
### 0.3 脚本命令速查
```bash
cd /opt/Trading_Studio
bash deploy.sh # 首次完整部署 + PM2 启动
bash deploy.sh update # git pull + 更新依赖 + PM2 重启
bash deploy.sh restart # 仅重启 PM2
bash deploy.sh stop # 停止 PM2
bash deploy.sh status # 查看 PM2 / GPU / 端口状态
bash deploy.sh logs # 查看 PM2 最近 80 行日志
bash deploy.sh help # 显示帮助
```
### 0.4 日常更新流程
代码推送到 Git 后,在服务器上执行:
```bash
sudo -i
cd /opt/Trading_Studio
bash deploy.sh update
```
### 0.5 PM2 运维(root 环境)
```bash
pm2 status # 进程状态
pm2 logs trading_studio # 实时日志
pm2 restart trading_studio # 手动重启
pm2 monit # 资源监控
# 应用日志
tail -f /opt/Trading_Studio/trading_studio.log
tail -f /opt/Trading_Studio/logs/pm2-out.log
```
### 0.6 目录布局(/opt 标准路径)
```
/opt/Trading_Studio/
├── deploy.sh # 一键部署脚本
├── app.py # Gradio 主入口
├── venv/ # Python 虚拟环境
├── logs/ # PM2 日志
├── uploads/ # 上传临时文件
├── outputs/ # 合成 wav 输出
├── speaker_emb.pt # 音色文件(Web UI 生成,需手动备份)
└── trading_studio.log # 应用日志
```
---
## 1. 硬件与系统前提
| 项目 | 要求 |
@@ -130,7 +238,7 @@ PyTorch cu121 wheel 通常自带运行时库。若 Whisper 报 cuDNN 错误:
```bash
# 克隆项目
cd ~
cd /opt
git clone https://git.bz121.com/dekun/Trading_Studio.git
cd Trading_Studio
@@ -184,7 +292,7 @@ GPU: NVIDIA GeForce RTX 3060 Ti
```bash
source venv/bin/activate
cd ~/Trading_Studio
cd /opt/Trading_Studio
# 安装其余依赖
pip install -r requirements.txt
@@ -270,7 +378,7 @@ curl http://192.168.8.64:11434/api/chat -d '{
```bash
source venv/bin/activate
cd ~/Trading_Studio
cd /opt/Trading_Studio
# 前台启动(调试)
python app.py
@@ -341,7 +449,7 @@ module.exports = {
启动:
```bash
cd ~/Trading_Studio
cd /opt/Trading_Studio
mkdir -p logs
pm2 start ecosystem.config.js
@@ -349,10 +457,12 @@ pm2 status
pm2 logs trading_studio --lines 50
```
> **推荐:** 直接使用 `bash deploy.sh` 一键完成上述步骤,见 [第 0 节](#0-一键部署推荐)。
### 9.3 方式 B:直接命令行
```bash
cd ~/Trading_Studio
cd /opt/Trading_Studio
pm2 start app.py \
--name "trading_studio" \
@@ -382,7 +492,14 @@ pm2 monit # 实时监控 CPU/内存
### 9.6 更新代码后重新部署
```bash
cd ~/Trading_Studio
cd /opt/Trading_Studio
bash deploy.sh update
```
或手动:
```bash
cd /opt/Trading_Studio
git pull
source venv/bin/activate
pip install -r requirements.txt # 若有新依赖
@@ -395,10 +512,10 @@ pm2 restart trading_studio
### 10.1 迁移到新机器
1. 复制 `speaker_emb.pt`(音色文件,`.gitignore` 中,需手动备份
2. 新机器按本文档完整部署
3.`speaker_emb.pt` 放回项目根目录
4. `pm2 restart trading_studio`
1. 备份 `/opt/Trading_Studio/speaker_emb.pt`(音色文件,不入 Git
2. 新机器执行 `bash deploy.sh` 一键部署
3.`speaker_emb.pt` 复制回 `/opt/Trading_Studio/`
4. `bash deploy.sh restart`
### 10.2 CUDA / 显存问题
+38 -16
View File
@@ -52,20 +52,36 @@ Trading Studio 是一套运行在 Ubuntu 物理服务器(RTX 3060 Ti)上的
> 完整环境配置请参阅 [DEPLOY.md](./DEPLOY.md)
```bash
# 1. 克隆仓库
git clone https://git.bz121.com/dekun/Trading_Studio.git
cd Trading_Studio
### 一键部署(生产环境推荐)
# 2. 创建虚拟环境并安装依赖(详见 DEPLOY.md)
**root** 用户部署到 `/opt/Trading_Studio` 并由 PM2 常驻:
```bash
sudo -i
git clone https://git.bz121.com/dekun/Trading_Studio.git /opt/Trading_Studio
cd /opt/Trading_Studio
chmod +x deploy.sh
bash deploy.sh
```
浏览器访问:`http://<服务器IP>:5683`
日常更新:
```bash
cd /opt/Trading_Studio && bash deploy.sh update
```
### 手动部署(开发调试)
```bash
git clone https://git.bz121.com/dekun/Trading_Studio.git /opt/Trading_Studio
cd /opt/Trading_Studio
python3 -m venv venv
source venv/bin/activate
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -r requirements.txt
# 3. 启动中控
python app.py
# 浏览器访问: http://<服务器IP>:5683
```
---
@@ -108,18 +124,21 @@ python app.py
## PM2 守护运行
```bash
# 方式 1ecosystem 配置
pm2 start ecosystem.config.js
标准路径 `/opt/Trading_Studio`root 用户:
# 方式 2:直接命令
pm2 start app.py --name "trading_studio" --interpreter ./venv/bin/python
```bash
# 一键部署 + PM2 启动(推荐)
cd /opt/Trading_Studio && bash deploy.sh
# 或手动 PM2
pm2 start ecosystem.config.js
# 常用管理
pm2 status
pm2 logs trading_studio
pm2 restart trading_studio
pm2 save && pm2 startup # 开机自
bash deploy.sh restart # 重启
bash deploy.sh update # 拉代码 + 更新依赖 + 重
pm2 save && pm2 startup # 开机自启(deploy.sh 已自动配置)
```
---
@@ -150,6 +169,7 @@ outputs/
```
Trading_Studio/
├── deploy.sh # 一键部署脚本(/opt + PM2
├── app.py # Gradio 主入口
├── config.py # 全局配置
├── whisper_service.py # Whisper CUDA 识别
@@ -158,13 +178,15 @@ Trading_Studio/
├── ecosystem.config.js # PM2 守护配置
├── requirements.txt # Python 依赖
├── README.md # 本文件
├── DEPLOY.md # 部署指南
├── DEPLOY.md # 部署指南(含一键部署教程)
├── .gitignore
├── speaker_emb.pt # 音色文件(运行时生成,不入库)
├── uploads/ # 上传临时目录
└── outputs/ # 合成 wav 输出
```
**生产标准路径:** `/opt/Trading_Studio`
---
## 硬件要求
+4 -1
View File
@@ -47,7 +47,10 @@ WHISPER_LANGUAGE = "zh"
# ---------------------------------------------------------------------------
# ChatTTS 配置
# ---------------------------------------------------------------------------
# 项目根目录
# 标准生产安装路径(/opt,root 部署)
INSTALL_DIR = Path("/opt/Trading_Studio")
# 项目根目录(开发/生产均自适应,以实际 app.py 所在目录为准)
BASE_DIR = Path(__file__).resolve().parent
# 固定音色 Embedding 存储路径
+340
View File
@@ -0,0 +1,340 @@
#!/usr/bin/env bash
# =============================================================================
# Trading Studio 一键部署脚本
# 安装路径: /opt/Trading_Studio
# 运行用户: root
# 功能: 系统依赖 → 代码拉取 → Python 虚拟环境 → PyTorch CUDA → PM2 常驻
#
# 用法:
# sudo bash deploy.sh # 首次完整部署并 PM2 启动
# sudo bash deploy.sh update # 拉取最新代码、更新依赖、重启 PM2
# sudo bash deploy.sh restart # 仅重启 PM2 进程
# sudo bash deploy.sh stop # 停止 PM2 进程
# sudo bash deploy.sh status # 查看 PM2 与 GPU 状态
# sudo bash deploy.sh logs # 查看 PM2 最近日志
# =============================================================================
set -euo pipefail
# ---------------------------------------------------------------------------
# 可配置常量
# ---------------------------------------------------------------------------
INSTALL_DIR="/opt/Trading_Studio"
GIT_REPO="https://git.bz121.com/dekun/Trading_Studio.git"
PM2_APP_NAME="trading_studio"
GRADIO_PORT=5683
GPU_POWER_LIMIT=120
PYTORCH_INDEX="https://download.pytorch.org/whl/cu121"
# ---------------------------------------------------------------------------
# 颜色输出
# ---------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
log_info() { echo -e "${CYAN}[INFO]${NC} $*"; }
log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
# ---------------------------------------------------------------------------
# 前置检查
# ---------------------------------------------------------------------------
require_root() {
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
log_error "请使用 root 用户运行: sudo bash deploy.sh"
exit 1
fi
}
check_gpu() {
if command -v nvidia-smi &>/dev/null; then
log_ok "检测到 NVIDIA GPU:"
nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader
else
log_warn "未检测到 nvidia-smiWhisper/ChatTTS CUDA 加速可能不可用。"
fi
}
set_gpu_power_limit() {
if command -v nvidia-smi &>/dev/null; then
log_info "设置 GPU 功耗上限为 ${GPU_POWER_LIMIT}W ..."
if nvidia-smi -pl "${GPU_POWER_LIMIT}" &>/dev/null; then
log_ok "GPU 功耗墙已设为 ${GPU_POWER_LIMIT}W"
else
log_warn "无法设置功耗墙,请手动执行: nvidia-smi -pl ${GPU_POWER_LIMIT}"
fi
fi
}
# ---------------------------------------------------------------------------
# 系统依赖
# ---------------------------------------------------------------------------
install_system_deps() {
log_info "安装系统依赖 ..."
apt-get update -qq
apt-get install -y \
git curl wget build-essential \
python3 python3-venv python3-dev python3-pip \
ffmpeg libsndfile1 portaudio19-dev \
ca-certificates gnupg
log_ok "系统依赖安装完成"
}
install_node_pm2() {
if command -v pm2 &>/dev/null; then
log_ok "PM2 已安装: $(pm2 -v)"
return
fi
log_info "安装 Node.js 20 LTS 与 PM2 ..."
if ! command -v node &>/dev/null; then
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
fi
npm install -g pm2
log_ok "PM2 安装完成: $(pm2 -v)"
}
# ---------------------------------------------------------------------------
# 代码部署
# ---------------------------------------------------------------------------
deploy_code() {
if [[ -d "${INSTALL_DIR}/.git" ]]; then
log_info "更新已有代码: ${INSTALL_DIR}"
git -C "${INSTALL_DIR}" pull --ff-only || {
log_warn "git pull 失败,尝试保留本地更改继续部署 ..."
}
elif [[ -d "${INSTALL_DIR}" ]]; then
log_error "${INSTALL_DIR} 已存在但不是 git 仓库,请手动处理后重试。"
exit 1
else
log_info "克隆仓库到 ${INSTALL_DIR} ..."
git clone "${GIT_REPO}" "${INSTALL_DIR}"
fi
log_ok "代码就绪: ${INSTALL_DIR}"
}
# ---------------------------------------------------------------------------
# Python 环境
# -------------------------------------------------------------------
setup_python_venv() {
local venv_path="${INSTALL_DIR}/venv"
if [[ ! -d "${venv_path}" ]]; then
log_info "创建 Python 虚拟环境 ..."
python3 -m venv "${venv_path}"
fi
# shellcheck disable=SC1091
source "${venv_path}/bin/activate"
log_info "升级 pip ..."
pip install --upgrade pip setuptools wheel -q
log_info "安装 PyTorch (CUDA 12.1) ..."
pip install torch torchvision torchaudio --index-url "${PYTORCH_INDEX}" -q
log_info "安装项目依赖 ..."
pip install -r "${INSTALL_DIR}/requirements.txt" -q
# 验证 CUDA
if python -c "import torch; assert torch.cuda.is_available()" 2>/dev/null; then
log_ok "PyTorch CUDA 可用: $(python -c 'import torch; print(torch.cuda.get_device_name(0))')"
else
log_warn "PyTorch CUDA 不可用,请检查 NVIDIA 驱动与 CUDA 运行时。"
fi
deactivate
log_ok "Python 虚拟环境配置完成"
}
create_runtime_dirs() {
mkdir -p "${INSTALL_DIR}/logs"
mkdir -p "${INSTALL_DIR}/uploads"
mkdir -p "${INSTALL_DIR}/outputs"
log_ok "运行时目录已创建 (logs, uploads, outputs)"
}
# ---------------------------------------------------------------------------
# 防火墙
# ---------------------------------------------------------------------------
configure_firewall() {
if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
log_info "放行 Gradio 端口 ${GRADIO_PORT} ..."
ufw allow "${GRADIO_PORT}/tcp" || true
log_ok "防火墙规则已更新"
else
log_info "ufw 未启用,跳过防火墙配置"
fi
}
# ---------------------------------------------------------------------------
# PM2 管理
# ---------------------------------------------------------------------------
pm2_start() {
log_info "通过 PM2 启动 Trading Studio ..."
cd "${INSTALL_DIR}"
# 若已有同名进程则先删除再启动,避免重复
if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then
pm2 delete "${PM2_APP_NAME}" || true
fi
pm2 start ecosystem.config.js
pm2 save
# 配置 root 用户开机自启
local startup_cmd
startup_cmd=$(pm2 startup systemd -u root --hp /root 2>&1 | grep "sudo env" || true)
if [[ -n "${startup_cmd}" ]]; then
eval "${startup_cmd}" || log_warn "PM2 startup 可能已配置过"
fi
pm2 save
log_ok "PM2 启动完成"
pm2 status
}
pm2_restart() {
cd "${INSTALL_DIR}"
if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then
pm2 restart "${PM2_APP_NAME}"
log_ok "PM2 已重启: ${PM2_APP_NAME}"
else
log_warn "进程不存在,执行完整启动 ..."
pm2_start
fi
pm2 status
}
pm2_stop() {
if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then
pm2 stop "${PM2_APP_NAME}"
log_ok "PM2 已停止: ${PM2_APP_NAME}"
else
log_warn "PM2 进程 ${PM2_APP_NAME} 不存在"
fi
pm2 status
}
pm2_status() {
echo ""
log_info "=== PM2 状态 ==="
pm2 status || true
echo ""
log_info "=== GPU 状态 ==="
nvidia-smi 2>/dev/null || log_warn "nvidia-smi 不可用"
echo ""
log_info "=== 端口 ${GRADIO_PORT} 监听 ==="
ss -tlnp | grep ":${GRADIO_PORT}" || log_warn "端口 ${GRADIO_PORT} 未监听,服务可能未启动"
echo ""
log_info "访问地址: http://$(hostname -I | awk '{print $1}'):${GRADIO_PORT}"
}
pm2_logs() {
pm2 logs "${PM2_APP_NAME}" --lines 80 --nostream || true
}
# ---------------------------------------------------------------------------
# 主流程
# ---------------------------------------------------------------------------
cmd_install() {
log_info "========== Trading Studio 一键部署开始 =========="
log_info "安装目录: ${INSTALL_DIR}"
log_info "运行用户: root"
install_system_deps
install_node_pm2
deploy_code
setup_python_venv
create_runtime_dirs
set_gpu_power_limit
configure_firewall
pm2_start
echo ""
log_ok "========== 部署完成 =========="
echo ""
echo -e " Web 中控: ${GREEN}http://$(hostname -I | awk '{print $1}'):${GRADIO_PORT}${NC}"
echo -e " 项目目录: ${INSTALL_DIR}"
echo -e " 查看日志: ${CYAN}pm2 logs ${PM2_APP_NAME}${NC}"
echo -e " 重启服务: ${CYAN}bash ${INSTALL_DIR}/deploy.sh restart${NC}"
echo ""
log_warn "首次使用请打开 Web UI「音色锁定」上传参考人声,生成 speaker_emb.pt"
}
cmd_update() {
log_info "========== 更新部署 =========="
deploy_code
setup_python_venv
create_runtime_dirs
pm2_restart
log_ok "更新完成"
}
print_usage() {
cat <<EOF
Trading Studio 一键部署脚本
用法:
sudo bash deploy.sh [命令]
命令:
(无参数) 首次完整部署到 /opt/Trading_Studio 并由 PM2 启动
install 同上
update 拉取最新代码、更新 Python 依赖、重启 PM2
restart 重启 PM2 进程
stop 停止 PM2 进程
status 查看 PM2 / GPU / 端口状态
logs 查看 PM2 最近日志
help 显示本帮助
示例:
cd /opt/Trading_Studio && sudo bash deploy.sh update
EOF
}
main() {
require_root
local cmd="${1:-install}"
case "${cmd}" in
install|"")
check_gpu
cmd_install
;;
update)
check_gpu
cmd_update
;;
restart)
pm2_restart
;;
stop)
pm2_stop
;;
status)
pm2_status
;;
logs)
pm2_logs
;;
help|-h|--help)
print_usage
;;
*)
log_error "未知命令: ${cmd}"
print_usage
exit 1
;;
esac
}
main "$@"
+10 -5
View File
@@ -1,14 +1,19 @@
/**
* PM2 进程守护配置
* 标准安装路径: /opt/Trading_Studio
* 用法: pm2 start ecosystem.config.js
*/
const path = require("path");
const APP_DIR = __dirname;
module.exports = {
apps: [
{
name: "trading_studio",
script: "app.py",
interpreter: "./venv/bin/python",
cwd: __dirname,
script: path.join(APP_DIR, "app.py"),
interpreter: path.join(APP_DIR, "venv/bin/python"),
cwd: APP_DIR,
instances: 1,
autorestart: true,
watch: false,
@@ -17,8 +22,8 @@ module.exports = {
PYTHONUNBUFFERED: "1",
CUDA_VISIBLE_DEVICES: "0",
},
error_file: "./logs/pm2-error.log",
out_file: "./logs/pm2-out.log",
error_file: path.join(APP_DIR, "logs/pm2-error.log"),
out_file: path.join(APP_DIR, "logs/pm2-out.log"),
log_date_format: "YYYY-MM-DD HH:mm:ss",
merge_logs: true,
},