Files
sanguo_vnpy_v2/docs/deployment/nas-deploy-plan.md
T
claude_dev f6ca85e937 docs(audit): 文档审计吸收批——P0×2+P1×4 修复 [nas]
- P0-2 触及面矩阵修正(three-env §12): sanguo_api+frontend→🔴——VPS 常驻
  sanguo-api 生产控制台(runbook §7.1/§7.6 09-25 勘误「本就常驻跑纯 API」,
  vps-deploy.yml 每次部署重启 sanguo-api 实证)+公网前端 dist; sanguo_web=legacy
  平行后端非「前端」; orchestrator→🟡 随 api 常驻加载(app.py:15 import 实证)。
  同病 .claude/CLAUDE.md 判定行+reload 节一并修正(两处)
- P0-1 README 入口: 生产命令勘误(勿起 sanguo_web legacy 后端,架构审计 P0-3
  定性危险)+admin123 凭据指引删除+api/user_guide 断链节改指文档中心
- P1 reload 旧任务名 sanguo-bs-eod→sanguo-bs-daily(three-env §4+session-guide
  §6, 2026-08-20 重组遗留)
- P1 session-guide: smoke_e2e.py 死引用(da32cca 审计卫生批已删)→CI nas-verify
  手动等效探针(免凭据版);dispatch 样例补 confirm 必填字段
- P1 nas-deploy-plan §四: docker run 补 --init+数据挂载/删 8080(现役容器
  docker inspect 实证 Init=true 仅 8000 双挂载);§五外网链路标废(首尔入口 502)
- env-version-matrix VPS 角色+ops-README BRIDGE_URL: miniQMT/FastAPI-bridge
  退役标注(09-08)
- three-env §1 NAS 路径 stock→homes/admin(promote.sh:19 实证)+§3.1 模块
  计数 13→15

审计源: audit/20261001_docs_audit/(P0-1/P0-2/P1-1~4) +
audit/20261001_architecture_code_audit/(P0-1)

Co-Authored-By: Claude Code <notify@anthropic.com>
2026-10-01 09:08:18 +08:00

7.7 KiB
Raw Blame History

Sanguo VeighNa — NAS Docker 迭代部署方案

维护人:诸葛亮 · 最后更新:2026-07-04 基于实机查证(Synology NAS cfeasynas 216+II) 首次安装见 synology-nas.md,本文只讲日常迭代与运维。

2026-07-07 Phase 3b 更新:容器 uvicorn 目标从 sanguo_web.api:app(旧实盘交易 API)切到 sanguo_api.main:create_app --factory(研究/回测 API + Vue SPA),单 worker(orchestrator 任务状态在内存)。Vue 前端构建产物 frontend/dist/ 由 FastAPI StaticFiles 挂在 /。公网 vnpy.mysanguo.top 现为研究控制台(登录 admin/admin,默认密码部署后改)。旧实盘交易路由(trading/gateway/market)本期下线,D 期接国金 QMT 时合并回来。端口 8000 / frpc / socat / Caddy 全程未动。


一、核心思路:应用层与镜像层分离

代码不打进镜像运行时,而是 bind-mount 挂进容器。绝大多数迭代不需要重新 build 镜像。

层次 内容 变更频率 变更方式
镜像层 sanguo_vnpy_v2:latest (6.9GB) Python 3.10 + pip 依赖 + TA-Lib + entrypoint.sh 低 docker build
应用层 bind-mount → /app 项目源码(sanguo_web、vnpy_v4.4.0…) 高 rsync + docker restart
数据层 /app/data SQLite、日志(持久化) — 不要覆盖

容器启动时 /app 被宿主机目录整体覆盖,镜像内 COPY 的代码运行时不生效。改代码 = 改宿主机目录 + 重启容器。


二、当前部署实况(已查证)

项目 值
NAS cfeasynas 192.168.2.154
SSH admin@192.168.2.154
Docker 路径 /var/packages/Docker/target/usr/bin/docker(不在 PATH)
权限 admin 在 docker 组,无需 sudo
容器/镜像 sanguo_vnpy_v2 / sanguo_vnpy_v2:latest
端口 8000→8000、8080→8080
代码挂载 /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2 → /app
启动 /app/entrypoint.sh → python /app/run_web.py(run_web.py 跑 uvicorn sanguo_api.main:create_app --factory,单 worker,Phase 3b 起)
重启策略 unless-stopped
启动方式 docker run(非 compose)

三、常规迭代(只改代码)— 90% 场景

# 在 Mac Mini 执行(ssh sanguo-nas 已 key 免密,见 ~/.ssh/config;不用 sshpass)
DOCKER="/var/packages/Docker/target/usr/bin/docker"
SRC=~/.openclaw/sanguo_projects/sanguo_vnpy_v2/
DEST=sanguo-nas:/volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/

# 1) 同步代码(已排除数据/缓存/venv/entrypoint/配置——配置含部署态密码,不覆盖)
#    ⚠️ 每个 pattern 必须单独一个 --exclude=PATTERN(见下方警告框)
rsync -avz --delete \
  --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' --exclude='.pytest_cache' \
  --exclude='data/' --exclude='data_cache/' --exclude='logs/' --exclude='temp/' \
  --exclude='*.log' --exclude='.DS_Store' \
  --exclude='.venv/' --exclude='venv/' --exclude='venv311/' \
  --exclude='node_modules/' --exclude='config/' \
  --exclude='entrypoint.sh' \
  -e ssh \
  "$SRC" "$DEST"

⚠️ rsync --exclude 写法警告(2026-07-14 dry-run 实测固化)

旧写法 --exclude='.git' '__pycache__' '*.pyc' ...(一个 --exclude 后紧挨多个 bare pattern)实测排除失效——rsync 把 bare pattern 当源路径处理(报 lstat: No such file or directory),--delete 因此会误删 NAS 上:

  • data_cache/ 全量 staging parquet(万级文件,dev/NAS 差约 1 万个)
  • /app/entrypoint.sh(容器 Entrypoint,删除后 docker restart 启动失败)
  • 以及 venv/ 等 dev-only 目录被误推上去

必须用每 pattern 单独 --exclude=PATTERN 写法(如上命令)。每次改排除列表后建议先 rsync -avzn ...(dry-run)确认 deleting 列表无意外项再实跑。

# 2) 重启容器
ssh sanguo-nas "$DOCKER restart sanguo_vnpy_v2"

# 3) 看日志 + 冒烟
sleep 8
ssh sanguo-nas "$DOCKER logs --tail 20 sanguo_vnpy_v2"
curl -s http://192.168.2.154:8000/api/v1/auth/login -X POST \
  -H 'Content-Type: application/json' -d '{"username":"admin","password":"<部署态密码>"}'
验证项 期望
ssh sanguo-nas "$DOCKER ps" Up
POST /api/v1/auth/login 返回 {"token":...}

附:entrypoint.sh 根因说明(2026-07-14 dry-run + docker inspect 实证)

docker inspect sanguo_vnpy_v2 显示容器 Entrypoint=[/app/entrypoint.sh]、Cmd=[], 即容器启动必须找到 /app/entrypoint.sh。但 dev 仓库根目录已无此文件(已移到 docker/entrypoint.sh)。若 rsync 带 --delete 且不排除,会删掉 NAS 上的 /app/entrypoint.sh → 下次 docker restart 直接启动失败(entrypoint not found)。

  • 短期保护(已落实):上方步骤 1 命令加了 --exclude='entrypoint.sh',NAS 现有文件 不会被删,容器可继续启动。代价:dev 侧对 entrypoint 的改动不会自动同步(需手动处理)。
  • 根治方案(✅ 2026-08-01 已实施方案①):dev 根目录恢复 entrypoint.sh(git mv 自 docker/entrypoint.sh,单一权威),promote 全量 rsync 自动推送(RSYNC_EXCLUDE 不排除 entrypoint.sh),NAS 宿主孤儿遗留被覆盖、可复现。Dockerfile COPY entrypoint.sh /app/ + ENV PYTHONPATH=/app:/app/vnpy_v4.4.0 同步固化。方案②(镜像层提供)弃用——bind-mount 必然覆盖 /app,镜像层 entrypoint 无法生效,只能靠宿主(promote 推送的)那份。

四、依赖变更(改 requirements-docker.txt)— 偶尔

# 1) 先同步代码(含新 requirements)到 NAS,同第三节步骤 1
# 2) 在 NAS 重新 build
ssh sanguo-nas \
  "cd /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2 && \
   /var/packages/Docker/target/usr/bin/docker build -f docker/Dockerfile -t sanguo_vnpy_v2:latest ."

# 3) 用相同参数重启容器
ssh sanguo-nas << 'EOF'
D=/var/packages/Docker/target/usr/bin/docker
$D stop sanguo_vnpy_v2 && $D rm sanguo_vnpy_v2
$D run -d --init --name sanguo_vnpy_v2 --restart unless-stopped \
  -p 8000:8000 \
  -v /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2:/app \
  -v /volume1/stock:/volume1/stock \
  sanguo_vnpy_v2:latest
EOF

⚠️ NAS CPU 弱,build 编 TA-Lib + 大包约 30–60 分钟。 ⚠️ 2026-10-01 勘误(audit P1-3):旧命令漏 --init——无 init 的容器后台进程会被 docker 清杀(曾实杀 02 长任务,铁律见 three-env §9);同漏 -v /volume1/stock 数据挂载、多挂了不存在的 8080。现役容器参数以 docker inspect sanguo_vnpy_v2 实查为准。


五、外网链路(⚠️ 已废弃,勿按此排障)

2026-10-01 勘误(audit):本节描述的「vnpy.mysanguo.top → VPS Caddy :18000 → frps → Mac frpc → socat → NAS 容器」链路已废弃(.top 首尔入口 502 残留)。现行外网入口=VPS 常驻 sanguo-api 直绑 vnpy.mysanguo.top(runbook §7.1);NAS 容器仅内网 192.168.2.154:8000。此节仅存档排障历史。


六、已知问题

问题 影响 处理
threads can only be started once VeighNa 引擎在 2 workers 下重复初始化 Web/登录/查询正常;真实交易需改 1 worker
/health 返回 degraded 引擎未初始化的降级 非致命
Docker 不在 PATH — 一律用全路径
admin 密码硬编码 安全 后续改 SSH key

七、回滚

代码层(镜像未动):git checkout <旧commit> 后重跑第三节步骤 1-2。 镜像层:docker images sanguo_vnpy_v2 找旧 tag,重 docker run。