From 68aff93f4bfc8d544f3c63e77ad91f8e24f064ec Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sun, 3 May 2026 12:40:13 +0800 Subject: [PATCH] auto-sync: 2026-05-03 12:40:13 --- docs/06-nas-infrastructure.md | 662 ++++++++++++++++++++++++++++++++++ 1 file changed, 662 insertions(+) create mode 100644 docs/06-nas-infrastructure.md diff --git a/docs/06-nas-infrastructure.md b/docs/06-nas-infrastructure.md new file mode 100644 index 00000000..437324c7 --- /dev/null +++ b/docs/06-nas-infrastructure.md @@ -0,0 +1,662 @@ +# 06 - NAS 基础设施部署全纪录 + +**版本**: v1.0 +**日期**: 2026-05-03 +**作者**: 姜维(平台总督) + +--- + +## 1. 概述 + +本文档记录 sanguo_vnpy 项目在群晖 NAS(192.168.2.154)上的完整部署方案,包括需求、设计、构建、部署、测试、运维全流程,以及历史踩坑记录。 + +--- + +## 2. 需求定义 + +### 2.1 基础设施需求 + +| 编号 | 需求 | 优先级 | 状态 | +|------|------|--------|------| +| INF-001 | NAS Docker 容器化部署 vnpy 环境 | P0 | ✅ | +| INF-002 | 回测服务 API 化(HTTP 接口) | P0 | ✅ | +| INF-003 | Jupyter Lab 开发环境 | P1 | ✅ | +| INF-004 | SSH 运维通道 | P1 | ✅ | +| INF-005 | 数据自动增量更新 | P1 | ✅ | +| INF-006 | 容器异常自动重启 | P1 | ✅ | +| INF-007 | VS Code Server Web IDE | P2 | ❌ 跳过(网络问题) | + +### 2.2 硬件环境 + +| 项目 | 规格 | +|------|------| +| NAS 型号 | 群晖 DS220+ | +| NAS IP | 192.168.2.154 | +| CPU 架构 | x86_64 | +| 内核版本 | Linux 3.10.108(重要:影响 SSH 选型) | +| Docker | 群晖套件 Docker 20.x | +| 存储路径 | `/volume1/stock/` | + +### 2.3 网络拓扑 + +``` +Mac Mini (192.168.2.153) 群晖 NAS (192.168.2.154) +┌──────────────────────┐ ┌─────────────────────────────────────┐ +│ OpenClaw Gateway │ │ Docker: sanguo_vnpy 容器 │ +│ 开发机/调度中心 │ 局域网 │ ┌─ Jupyter Lab (8888) │ +│ │◄──────────────►│ ├─ 回测服务 (8088) │ +│ /Volumes/stock/ │ SMB 挂载 │ ├─ SSH/dropbear (22→2222) │ +│ (NAS SMB 挂载) │◄──────────────►│ └─ WebTrader (8000) 预留 │ +└──────────────────────┘ │ │ + │ 数据库: quant_trading.db (1.4GB) │ + │ 原始数据: /volume1/stock/A股数据/ │ + └─────────────────────────────────────┘ +``` + +--- + +## 3. 详细设计 + +### 3.1 Docker 镜像设计 + +#### 3.1.1 镜像分层策略 + +``` +镜像: sanguo_vnpy:with-scripts (4.08GB) +┌─────────────────────────────────────────┐ +│ Layer 1: python:3.10-slim (基础镜像) │ ← 永不重构建 +├─────────────────────────────────────────┤ +│ Layer 2: 系统工具 (git/curl/vim/sudo等) │ ← 极少重构建 +├─────────────────────────────────────────┤ +│ Layer 3: 编译工具链 (build-essential) │ ← 极少重构建 +├─────────────────────────────────────────┤ +│ Layer 4: 图形库 + OpenSSH │ ← 极少重构建 +├─────────────────────────────────────────┤ +│ Layer 5: pip 基础依赖 (vnpy/numpy等) │ ← 低频变更 +│ requirements-base.txt │ +├─────────────────────────────────────────┤ +│ Layer 6: pip 额外依赖 (akshare等) │ ← 可能变更 +│ requirements-extra.txt │ +├─────────────────────────────────────────┤ +│ Layer 7: 用户配置 + scripts 拷贝 │ ← 每次构建 +└─────────────────────────────────────────┘ +``` + +**关键原则**: +- 分层构建利用 Docker 缓存,修改额外依赖不需要重装 vnpy/numpy +- `with-scripts` 镜像在 `latest` 基础上增加了 `/app/scripts/backtest_service/` 目录 +- **禁止随意重构建镜像**,优先通过 volume 挂载更新代码 + +#### 3.1.2 当前镜像版本 + +| 镜像 | 大小 | 构建时间 | 说明 | +|------|------|----------|------| +| `sanguo_vnpy:latest` | 4.08GB | 2026-04-11 | 基础镜像(无回测服务代码) | +| `sanguo_vnpy:with-scripts` | 4.08GB | 2026-04-28 | 含回测服务代码(**当前使用**) | + +### 3.2 容器运行设计 + +#### 3.2.1 容器启动参数 + +```bash +docker run -d \ + --name sanguo_vnpy \ + --restart unless-stopped \ + --privileged \ + -p 2222:22 \ + -p 8000:8000 \ + -p 8088:8088 \ + -p 8888:8888 \ + -v /volume1/stock/sanguo_vnpy/bt-service:/app/scripts/backtest_service:ro \ + -v /volume1/stock/sanguo_vnpy/entrypoint.sh:/app/entrypoint.sh:ro \ + sanguo_vnpy:with-scripts +``` + +**参数说明**: + +| 参数 | 说明 | 选型理由 | +|------|------|----------| +| `--restart unless-stopped` | 异常自动重启 | NAS 重启后自动恢复服务 | +| `--privileged` | 特权模式 | 群晖内核 3.10 不支持 seccomp,SSH dropbear 需要特权执行 | +| `-p 2222:22` | SSH 端口映射 | 避免和 NAS 自身 SSH 冲突 | +| `-v bt-service:ro` | 回测服务代码挂载 | 代码更新不需要重建镜像 | +| `-v entrypoint.sh:ro` | 启动脚本挂载 | 配置变更不需要重建镜像 | + +#### 3.2.2 Volume 挂载设计 + +| NAS 路径 | 容器路径 | 权限 | 用途 | +|----------|----------|------|------| +| `/volume1/stock/sanguo_vnpy/bt-service/` | `/app/scripts/backtest_service/` | ro | 回测服务代码 | +| `/volume1/stock/sanguo_vnpy/entrypoint.sh` | `/app/entrypoint.sh` | ro | 容器启动脚本 | + +**设计理由**:代码通过 volume 挂载(非 commit),修改后 `docker restart` 即生效,无需重建镜像。 + +#### 3.2.3 端口映射 + +| 容器端口 | NAS 端口 | 服务 | 状态 | +|----------|----------|------|------| +| 22 | 2222 | SSH (dropbear) | ✅ 运行 | +| 8000 | 8000 | WebTrader (预留) | — | +| 8088 | 8088 | 回测 API (uvicorn) | ✅ 运行 | +| 8888 | 8888 | Jupyter Lab | ✅ 运行 | + +### 3.3 服务启动流程(entrypoint.sh) + +```bash +entrypoint.sh 执行顺序: + +1. pip3 install vnpy_ctastrategy vnpy_sqlite # 运行时依赖(容器层无持久化) +2. apt-get install dropbear-bin # SSH 替代方案 +3. 生成 SSH host keys + 配置 dropbear # SSH 服务启动 +4. jupyter lab & # Jupyter 开发环境 +5. uvicorn backtest_service.main:app & # 回测 API 服务 +6. 健康检查 # 验证服务就绪 +7. tail -f /dev/null # 保持容器运行 +``` + +**注意事项**: +- pip 包安装在容器可写层,容器重启后丢失,每次启动自动重装 +- dropbear 在 entrypoint 中自动安装,无需包含在镜像中 +- 回测服务代码通过 volume 挂载,代码更新 `docker restart` 即生效 + +### 3.4 数据层设计 + +#### 3.4.1 数据目录结构(NAS) + +``` +/volume1/stock/ +├── A股数据/ +│ ├── 日线数据/daily/ +│ │ ├── 2010/ # 按年份组织,每年 ~5000+ parquet 文件 +│ │ ├── 2011/ +│ │ └── ... /2026/ +│ ├── 分钟线数据/ +│ ├── 财务数据/financial/ +│ └── stock_info/ # 股票基础信息 CSV/JSON +│ +├── sanguo_vnpy/ +│ ├── data/ +│ │ ├── quant_trading.db # vnpy 交易数据库 (1.4GB) +│ │ ├── quant_trading.db.bak # 备份 +│ │ └── all_stocks.csv # 股票列表 +│ ├── bt-service/ # 回测服务代码 (volume 挂载) +│ ├── entrypoint.sh # 容器启动脚本 (volume 挂载) +│ ├── docker/ # Dockerfile + requirements +│ ├── scripts/ # 工具脚本 +│ ├── strategies/ # 策略代码 +│ └── config/ # 配置文件 +│ +├── 回测结果/ # 回测产出 +├── 代码库/ # 代码归档 +└── 临时文件/ +``` + +#### 3.4.2 vnpy 交易数据库 + +| 项目 | 详情 | +|------|------| +| 文件 | `quant_trading.db`(SQLite) | +| 大小 | 1.4 GB | +| 位置 | `/volume1/stock/sanguo_vnpy/data/` | +| 表 | `dbbardata`(K线数据)、`dbbaroverview`(5191条概览) | +| 数据类型 | 日线(interval=d) | +| 时间范围 | 2010-01-04 ~ 2026-03-27 | +| 覆盖股票 | 5191 只(SSE + SZSE 全 A 股) | + +#### 3.4.3 数据增量更新 + +``` +Mac Mini cron (每交易日 15:30) + → daily_update.sh + → 检查 NAS SMB 是否挂载 + → updater.py(腾讯 K 线 API → DB 增量写入) + → 清理 30 天前日志 +``` + +- **数据源**:腾讯 K 线 API(主源) +- **写入方式**:Mac 本机通过 SMB 直接读写 NAS 上的 DB 文件 +- **兜底**:NAS 未挂载时脚本检测到后跳过,不会损坏数据 +- **待改进**:改为容器内 API 触发,避免 SMB 依赖 + +--- + +## 4. 构建指南 + +### 4.1 构建基础镜像(极少执行) + +```bash +# 在 NAS 上执行 +cd /volume1/stock/sanguo_vnpy + +# 基础镜像 +docker build -t sanguo_vnpy:latest -f docker/Dockerfile . + +# 含回测代码的镜像(推荐) +# 在 Dockerfile 构建后,将 bt-service 目录拷入镜像 +docker build -t sanguo_vnpy:with-scripts -f docker/Dockerfile . +``` + +**⚠️ 纪律**:非必要不构建。代码更新走 volume 挂载 + `docker restart`。 + +### 4.2 依赖管理 + +| 文件 | 内容 | 变更频率 | +|------|------|----------| +| `requirements-base.txt` | vnpy, numpy, pandas, scipy, matplotlib, sklearn | 低 | +| `requirements-extra.txt` | akshare, tushare, debugpy, ipywidgets | 中 | +| entrypoint.sh `pip install` | vnpy_ctastrategy, vnpy_sqlite | 每次启动 | + +--- + +## 5. 部署指南 + +### 5.1 首次部署 + +```bash +# 1. 确保 NAS SSH 可用 +ssh admin@192.168.2.154 + +# 2. 确认镜像存在 +/usr/local/bin/docker images sanguo_vnpy + +# 3. 启动容器 +/usr/local/bin/docker run -d \ + --name sanguo_vnpy \ + --restart unless-stopped \ + --privileged \ + -p 2222:22 \ + -p 8000:8000 \ + -p 8088:8088 \ + -p 8888:8888 \ + -v /volume1/stock/sanguo_vnpy/bt-service:/app/scripts/backtest_service:ro \ + -v /volume1/stock/sanguo_vnpy/entrypoint.sh:/app/entrypoint.sh:ro \ + sanguo_vnpy:with-scripts + +# 4. 等待启动完成(约 40 秒,pip install 需要时间) +sleep 40 + +# 5. 验证 +curl http://192.168.2.154:8088/api/backtest/health +sshpass -p sanguo123 ssh -p 2222 vnpy@192.168.2.154 "echo OK" +``` + +### 5.2 代码更新(不需要重建镜像) + +```bash +# 1. 修改 NAS 上的代码(通过 SMB 挂载) +# /Volumes/stock/sanguo_vnpy/bt-service/ 下的文件 + +# 2. 重启容器 +ssh admin@192.168.2.154 "/usr/local/bin/docker restart sanguo_vnpy" + +# 3. 等待启动完成 +sleep 40 + +# 4. 验证 +curl http://192.168.2.154:8088/api/backtest/health +``` + +### 5.3 完全重建容器 + +当需要修改容器启动参数(端口、volume、安全选项)时: + +```bash +ssh admin@192.168.2.154 "/usr/local/bin/docker stop sanguo_vnpy && \ + /usr/local/bin/docker rm sanguo_vnpy && \ + /usr/local/bin/docker run -d \ + --name sanguo_vnpy \ + --restart unless-stopped \ + --privileged \ + -p 2222:22 -p 8000:8000 -p 8088:8088 -p 8888:8888 \ + -v /volume1/stock/sanguo_vnpy/bt-service:/app/scripts/backtest_service:ro \ + -v /volume1/stock/sanguo_vnpy/entrypoint.sh:/app/entrypoint.sh:ro \ + sanguo_vnpy:with-scripts" +``` + +**注意**:重建容器会丢失容器内 `/app/backtest_jobs/` 的历史任务数据(如有)。 + +--- + +## 6. 测试验证 + +### 6.1 服务健康检查 + +```bash +# 回测服务 +curl http://192.168.2.154:8088/api/backtest/health +# 预期: {"code":0,"msg":"ok","data":{...}} + +# Jupyter Lab +curl -s -o /dev/null -w "%{http_code}" http://192.168.2.154:8888/ +# 预期: 302 + +# SSH +sshpass -p sanguo123 ssh -o StrictHostKeyChecking=no -p 2222 vnpy@192.168.2.154 "echo OK" +# 预期: OK + +# Swagger 文档 +curl -s -o /dev/null -w "%{http_code}" http://192.168.2.154:8088/docs +# 预期: 200 +``` + +### 6.2 容器重启自动恢复测试 + +```bash +# 重启容器 +ssh admin@192.168.2.154 "/usr/local/bin/docker restart sanguo_vnpy" +sleep 40 + +# 验证所有服务 +curl http://192.168.2.154:8088/api/backtest/health +sshpass -p sanguo123 ssh -p 2222 vnpy@192.168.2.154 "echo OK" +``` + +### 6.3 回测功能测试 + +```bash +curl -X POST http://192.168.2.154:8088/api/backtest/submit \ + -H "Content-Type: application/json" \ + -d '{ + "strategy_name": "test_ma", + "strategy_code": "from vnpy_ctastrategy import CtaTemplate\n\nclass TestMA(CtaTemplate):\n fast_window = 5\n slow_window = 20\n parameters = [\"fast_window\", \"slow_window\"]\n variables = []\n def on_init(self): pass\n def on_start(self): pass\n def on_stop(self): pass\n def on_bar(self, bar): pass", + "symbol": "000001.SZSE", + "interval": "d", + "start_date": "2025-01-01", + "end_date": "2025-12-31", + "capital": 1000000, + "engine_type": "cta" + }' +``` + +--- + +## 7. 服务地址汇总 + +### 7.1 用户访问地址 + +| 服务 | 地址 | 账号 | 说明 | +|------|------|------|------| +| **Jupyter Lab** | `http://192.168.2.154:8888` | token: `sanguo123` | Python 开发环境 | +| **回测 API** | `http://192.168.2.154:8088` | — | 回测任务提交/查询 | +| **回测文档** | `http://192.168.2.154:8088/docs` | — | Swagger 交互式文档 | +| **SSH** | `ssh -p 2222 vnpy@192.168.2.154` | vnpy / `sanguo123` | 运维通道(dropbear) | + +### 7.2 管理命令(在 NAS 上执行) + +```bash +# 查看容器状态 +/usr/local/bin/docker ps | grep sanguo_vnpy + +# 查看容器日志 +/usr/local/bin/docker logs sanguo_vnpy --tail 50 + +# 重启容器 +/usr/local/bin/docker restart sanguo_vnpy + +# 进入容器 +/usr/local/bin/docker exec -it sanguo_vnpy bash + +# 查看容器内进程 +/usr/local/bin/docker exec sanguo_vnpy ps aux +``` + +### 7.3 Mac 端访问命令 + +```bash +# SSH 连接 +sshpass -p sanguo123 ssh -p 2222 vnpy@192.168.2.154 + +# 回测健康检查 +curl http://192.168.2.154:8088/api/backtest/health + +# NAS Docker 管理(通过 admin SSH) +ssh admin@192.168.2.154 "/usr/local/bin/docker ps" +``` + +--- + +## 8. 运维手册 + +### 8.1 日常巡检 + +```bash +# 一键检查所有服务 +echo "=== 回测 ===" && curl -s http://192.168.2.154:8088/api/backtest/health && \ +echo "" && echo "=== Jupyter ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://192.168.2.154:8888/ && \ +echo "" && echo "=== SSH ===" && sshpass -p sanguo123 ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -p 2222 vnpy@192.168.2.154 "echo OK" 2>&1 +``` + +### 8.2 故障排查 + +| 症状 | 检查方法 | 可能原因 | 解决方案 | +|------|----------|----------|----------| +| API 无响应 | `curl :8088/health` | uvicorn 未启动或已挂 | `docker restart` | +| SSH 连接被拒 | `ssh -p 2222 vnpy@NAS` | dropbear 未启动 | `docker exec -u root sanguo_vnpy bash -c 'dropbear -R -B -p 22'` | +| 容器未运行 | `docker ps` | NAS 重启或异常 | `docker start sanguo_vnpy` | +| pip 安装超时 | 查看容器日志 | NAS 网络问题 | 等待网络恢复后 restart | +| 数据更新失败 | `cat /Volumes/stock/.../logs/cron.log` | NAS SMB 未挂载 | 手动挂载后重跑 | + +### 8.3 数据备份 + +```bash +# vnpy DB 备份 +cp /Volumes/stock/sanguo_vnpy/data/quant_trading.db \ + /Volumes/stock/sanguo_vnpy/data/quant_trading.db.bak.$(date +%Y%m%d) +``` + +--- + +## 9. 历史 Q&A 与踩坑记录 + +### Q1: SSH 为什么不能用 OpenSSH,要用 dropbear? + +**问题现象**:SSH 连接返回 `Connection closed` 或 `Connection reset`,反复修过多次,每次重建容器就复发。 + +**排查过程**: + +``` +ssh -vvv → "kex_exchange_identification: banner line 0: Not allowed at this time" + → 以为是 PAM 问题 → 关闭 UsePAM → 还是挂 +sshd -ddd → "ssh_sandbox_child: prctl(PR_SET_SECCOMP): Invalid argument" + → mm_reap: preauth child terminated by signal 25 +``` + +**根因**:群晖 NAS 内核版本 3.10.108,不支持 `prctl(PR_SET_SECCOMP)` 系统调用。OpenSSH 10.0 的 `sshd-auth` 子进程硬编码使用 seccomp-bpf sandbox,在认证阶段调用 `prctl(PR_SET_SECCOMP)` 失败(`EINVAL`),preauth 子进程被信号 25 杀死。 + +**尝试过的方案**: +1. ❌ 创建 `/var/run/utmp` — 只修了 symptom,不解决 sandbox +2. ❌ 创建 sshd 系统用户 — 解决了 `Privilege separation user does not exist`,但 sandbox 还是挂 +3. ❌ 关闭 `UsePAM` — 和 sandbox 无关 +4. ❌ `--security-opt seccomp=unconfined` — 这是 Docker 层的 seccomp,和 OpenSSH 内部的 seccomp-bpf 无关 +5. ✅ **dropbear 替代 OpenSSH** — dropbear 不使用 seccomp sandbox,完美兼容 + +**最终方案**:用 `dropbear-bin` 替代 `openssh-server`,在 entrypoint.sh 中自动安装和配置。 + +--- + +### Q2: Mac 本地有一个同名废弃容器,和 NAS 容器混淆了 + +**问题现象**:Mac 上 `docker ps` 显示 sanguo_vnpy 运行 3 周,但容器内找不到回测服务。 + +**根因**:Mac 本地的 Docker Desktop 也运行了一个 `sanguo_vnpy` 容器(旧的 `latest` 镜像),和 NAS 上的 `with-scripts` 容器同名但完全不同。Mac 的 `docker` 命令操作的是本地 Docker,不是 NAS。 + +**教训**:检查远程 Docker 时必须通过 SSH 执行: +```bash +ssh admin@192.168.2.154 "/usr/local/bin/docker ps" +# 而不是本地的 docker ps +``` + +**解决**:清理 Mac 本地废弃容器 `docker stop sanguo_vnpy && docker rm sanguo_vnpy`。 + +--- + +### Q3: 为什么 entrypoint.sh 里要 pip install 而不是写进镜像? + +**问题**:vnpy_ctastrategy 和 vnpy_sqlite 没有写进 requirements.txt,而是在 entrypoint.sh 里每次启动时安装。 + +**原因**: +1. 这两个包在构建基础镜像时可能版本不匹配 +2. 容器可写层的 pip 包在容器删除后会丢失,但 `docker restart` 不会丢 +3. 灵活性:可以随时调整版本而不重建镜像 + +**代价**:每次容器重建后首次启动多约 30 秒安装时间。 + +--- + +### Q4: 为什么有 `latest` 和 `with-scripts` 两个镜像? + +**问题**:Mac 本地 `sanguo_vnpy:latest` 和 NAS `sanguo_vnpy:with-scripts` 的区别。 + +**说明**: +- `latest`:基础镜像,`/app/scripts/` 里只有 deployment/utils/verify 工具脚本,没有 `backtest_service` 目录 +- `with-scripts`:在 `latest` 基础上,将 `scripts/backtest-service/` 拷贝为 `/app/scripts/backtest_service/`,使回测服务可以从镜像内启动 + +**当前设计**:回测服务代码通过 volume 挂载(`bt-service → /app/scripts/backtest_service`),镜像内是否有已不重要。但 `with-scripts` 镜像确保即使 volume 没挂载,容器内也有基础代码。 + +--- + +### Q5: 为什么需要 `--privileged` 模式? + +**问题**:`--privileged` 安全性较差,为什么不用 `--security-opt seccomp=unconfined`? + +**尝试过程**: +1. 先用 `--security-opt seccomp=unconfined` — 不够,OpenSSH 内部的 seccomp-bpf 不受 Docker seccomp profile 控制 +2. 改用 `--privileged` — 解决了所有问题 + +**风险**:`--privileged` 给容器几乎完整的 host 权限。当前容器跑在内网 NAS 上,风险可接受。如果未来有安全需求,可以降级为 `--security-opt seccomp=unconfined` + `--cap-add ALL`,配合 dropbear 使用。 + +--- + +### Q6: 回测服务代码在 NAS 上有两份,`bt-service/` 和 `backtest-service-new/`,区别是什么? + +**说明**: +- `/volume1/stock/sanguo_vnpy/bt-service/` — **当前生效的**,volume 挂载到容器内使用 +- `/volume1/stock/sanguo_vnpy/backtest-service-new/` — 开发/备份目录 +- `/volume1/stock/sanguo_vnpy/scripts/backtest-service/` — 镜像内置的旧版 + +三者内容基本相同,**以 `bt-service/` 为准**。 + +--- + +### Q7: 容器内 SSH 的 host keys 每次重启都会变,导致 known_hosts 报错 + +**原因**:host keys 在容器可写层,容器删除重建后会重新生成。 + +**解决方案**: +1. 首次连接时用 `-o StrictHostKeyChecking=no` 跳过验证 +2. 或将 host keys 持久化到 NAS volume(待实现) + +--- + +### Q8: 数据增量更新走 SMB 而非容器 API,有什么问题? + +**当前状态**:Mac 端 cron 每交易日 15:30 触发 `daily_update.sh → updater.py`,通过 SMB 直接读写 NAS 上的 `quant_trading.db`。 + +**风险**: +1. Mac 重启后 SMB 未自动挂载,更新会跳过 +2. SMB 读写大文件(1.4GB DB)偶尔有锁文件问题 +3. 数据写入绕过了 vnpy 框架的数据接口 + +**待改进**:改为通过回测服务 API 触发数据更新,或直接在容器内跑 cron。 + +--- + +### Q9: Docker 镜像构建时为什么 scripts 目录总是少文件? + +**历史问题**(2026-04-14):Dockerfile 里 `COPY scripts /app/scripts` 拷贝的是本地仓库的 `scripts/` 目录,而 NAS 上的 `scripts/` 目录和本地不同步。 + +**根因**:代码仓库(gitee)和 NAS 上的文件不是同一份。Dockerfile 构建时用的是 NAS 上的文件,但 `COPY` 的路径是相对 Dockerfile 的。 + +**教训**:确保在正确的目录执行 `docker build`,且构建上下文中包含所有需要的文件。 + +--- + +### Q10: 为什么 code-server 没有启用? + +**原因**:Dockerfile 中注释掉了 code-server 安装(网络环境问题),entrypoint.sh 中的 `code-server &` 会静默失败。当前不影响使用,有 Jupyter Lab 足够。 + +--- + +## 10. 待改进项 + +| # | 问题 | 优先级 | 方案 | +|---|------|--------|------| +| 1 | `--privileged` 安全风险 | 低 | 内网环境可接受,未来可降级 | +| 2 | SSH host keys 不持久 | 低 | 挂载 volume 到 `/etc/dropbear/` | +| 3 | 数据更新走 SMB | 中 | 改为容器内 cron 或 API 触发 | +| 4 | NAS SMB 开机无自动挂载 | 中 | Mac 端配置 LaunchDaemon automount | +| 5 | DB 导入非全自动 | 中 | 编写导入脚本自动化 | +| 6 | 分钟线数据不完整 | 中 | 赵云补充分钟线数据导入 | +| 7 | DB 数据只到 2026-03-27 | 高 | cron 可能未持续跑,需检查 | +| 8 | pip 每次启动重装耗时 ~30s | 低 | 可接受,或写入镜像 | +| 9 | dropbear 安装需要 apt 联网 | 低 | 未来可写入镜像 | + +--- + +## 11. 附录 + +### 11.1 回测服务代码结构(bt-service/) + +``` +bt-service/ +├── main.py # FastAPI 应用入口 +├── api.py # API 路由定义 +├── executor.py # vnpy 回测执行器(核心) +├── models.py # Pydantic 数据模型 +├── config.py # 配置管理 +├── task_queue.py # 任务队列(线程池) +├── result_storage.py # 结果持久化 +└── README.md # 服务说明文档 +``` + +### 11.2 NAS 目录完整结构 + +``` +/volume1/stock/sanguo_vnpy/ +├── bt-service/ # 回测服务代码(volume 挂载,当前生效) +├── backtest-service-new/ # 回测服务代码(开发备份) +├── entrypoint.sh # 容器启动脚本(volume 挂载) +├── entrypoint.sh.backup # 旧版启动脚本备份 +├── data/ +│ ├── quant_trading.db # vnpy 交易数据库(1.4GB) +│ ├── quant_trading.db.bak # 备份 +│ └── all_stocks.csv # 股票列表 +├── docker/ +│ ├── Dockerfile # 镜像构建文件 +│ ├── entrypoint.sh # 镜像内置启动脚本 +│ └── requirements/ +│ ├── requirements-base.txt +│ └── requirements-extra.txt +├── scripts/ +│ ├── backtest-service/ # 旧版回测服务(镜像内置) +│ ├── deployment/ # 部署脚本 +│ ├── utils/ # 工具脚本 +│ └── verify/ # 验证脚本 +├── strategies/ # 策略代码 +├── config/ +│ ├── nginx/ # Nginx 配置(预留) +│ └── systemd/ # Systemd 配置(预留) +├── jiangwei-platform/ # 姜维平台脚本 +├── pangtong-value/ # 庞统价值策略 +├── zhangfei-technical/ # 张飞技术策略 +├── vnpy_webtrader/ # Web Trader 项目 +├── research/ # 研究资料 +├── test/ # 测试代码 +├── archives/ # 归档 +├── backup/ # 备份 +├── logs/ # 日志 +└── README-NAS-DEPLOY.md # NAS 部署说明 +``` + +### 11.3 关键环境变量 + +| 变量 | 值 | 说明 | +|------|-----|------| +| `PYTHONUNBUFFERED` | 1 | Python 输出不缓冲 | +| `PYTHONDONTWRITEBYTECODE` | 1 | 不生成 .pyc | +| `DEBIAN_FRONTEND` | noninteractive | apt 非交互 | +| `TZ` | Asia/Shanghai | 时区 | + +--- + +*三国量化团队 · 姜维(平台总督)*