# 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 与踩坑记录

> ⚠️ **安全提示**：本文档中出现的 SSH 密码（sanguo123）仅限内网使用，**严禁**通过端口转发等方式暴露到公网。

### 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. 灵活性：可以随时调整版本而不重建镜像

**已缓解**：entrypoint.sh 已移除 `set -e`，即使安装失败也不会导致容器退出，其他服务仍可正常启动。

**改进方向**（司马懿评审）：将 `vnpy_ctastrategy`、`vnpy_sqlite` 加入 `requirements-extra.txt`，`dropbear-bin` 加入 Dockerfile apt 安装层，彻底消除网络依赖。

---

### 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`——结果**失败**。去掉后容器在 dropbear 配置阶段退出，进入重启循环。原因：entrypoint 中 sudo/apt-get 等操作需要完整权限能力。

**风险**：`--privileged` 给容器几乎完整的 host 权限。当前容器跑在内网 NAS 上，风险可接受。未来如需收紧，需先将 dropbear 安装写入镜像以避免 entrypoint 中的 sudo 操作。

---

### Q6: 回测服务代码已统一为一份

**说明**：
- `/volume1/stock/sanguo_vnpy/bt-service/` — **当前生效的**，volume 挂载到容器内使用
- `/volume1/stock/sanguo_vnpy/backtest-service-new/` — 开发/备份目录
- `/volume1/stock/sanguo_vnpy/scripts/backtest-service/` — 镜像内置的旧版

**已解决**（2026-05-03）：`backtest-service-new/` 和 `scripts/backtest-service/` 已打包归档到 `archives/`，NAS 上只保留 `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 框架的数据接口

**待更新**：赵云已出新的每日增量更新方案（`daily_all_update.py`），覆盖日线+15min。详见赵云的数据平台文档。

**待改进**：改为通过回测服务 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~~ | — | ✅ 已确认数据实际更新到 2026-04-30，dbbaroverview 表未刷新但实际数据正常 |
| 8 | pip 每次启动重装耗时 ~30s | 低 | 可接受，或写入镜像 |
| 9 | dropbear 安装需要 apt 联网 | 中 | 断网时容器无法启动，应写入镜像（司马懿评审问题1） |
| 10 | entrypoint pip 依赖网络 | 中 | 同上，应写入镜像 |
| 11 | ~~废弃代码目录未清理~~ | — | ✅ 已清理归档（2026-05-03） |

---

## 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 | 时区 |

---

*三国量化团队 · 姜维（平台总督）*
