116 lines
9.0 KiB
Markdown
116 lines
9.0 KiB
Markdown
# 覆盖网络 · 「插件 vs 改内核」架构判断(2026-09-16)
|
||||
|
|
|
|||
|
|
> **性质**:只读架构评估。⛔ 未改任何代码、未动服务器。
|
|||
|
|
> **取证范围**:`D:\github\dsh_shenxian` 工作树(HEAD `4e3a1a4`)—— `src/supervisor/spawner.ts`(全读)· `src/worker/agent.ts`(头部 62 行 + 接口)· `src/` 结构清点 · 会合中继拆分方案 C1–C4。
|
|||
|
|
> **一句话判定**:**主力形态既不是"dsh 插件"也不是"把东西塞进平台主进程",而是"平台内模块化 + 独立进程/单元"** —— 因为要解决的问题(跨机可达、节点身份、寻址)**发生在实例之外**,dsh 插件机制在架构上够不到;而平台**已有**独立组件的先例(Manager / Worker 分体),顺着走即可。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、先拆概念:「插件」在这个项目里有两个完全不同的含义
|
|||
|
|
|
|||
|
|
| | (a) **dsh 官方插件**(profile 层业务插件) | (b) **平台自身的模块化** |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 跑在哪 | **用户实例内部**(dsh 进程内) | 平台进程 / 独立进程 |
|
|||
|
|
| 能做什么 | 加 UI 卡片与分区、注册工具、改实例内行为 | 任何事 |
|
|||
|
|
| 够得到 Worker↔Manager 隧道? | ❌ **架构上够不到**(实例是隔离的运行体,看不见宿主网络栈) | ✅ |
|
|||
|
|
| 发版与回滚 | 独立(候选池 → 用户自助启停) | 跟平台版本走 |
|
|||
|
|
| 现有先例 | `@dsh-local/portal-entry`、`business-plugins` | Manager / Worker 分体、`dshs-worker.service` |
|
|||
|
|
|
|||
|
|
**⇒ 概念澄清(很重要)**:覆盖网络**根本不涉及 `@deepseek-ai/dsh` 主程序** ⇒ **红线 R2 不构成约束**,这套东西整个发生在**平台侧**。所以"插件 vs 改代码"的真正对象是**平台自己的代码仓**,不是 dsh。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、三层归属:哪块该放哪
|
|||
|
|
|
|||
|
|
| 层 | 内容 | 建议形态 | 理由 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **数据面组件** | 会合(rendezvous)· 中继(relay)· **发布层**(对外服务暴露) | **独立进程 / 独立 systemd 单元**(可多实例、可换机) | ① 跨机、要碰宿主网络栈 ② 需独立扩缩容与**独立安全加固**(发布层要挡 DDoS)③ 塞进主进程 = 与平台同生共死,违反"控制面/数据面分离" |
|
|||
|
|
| **平台侧集成** | 寻址(`via`)· 节点身份与凭据 · 骨干资格签发 · 容量准入 | **改平台代码** | 必须与**归属 / 租约同源**(单点写),外置就是第二个权威源 = 脑裂 |
|
|||
|
|
| **实例内展示与工具** | 「我的网络 / 我的设备」面板 · agent 的文件互传工具 · 网络状态 | **dsh 插件**(唯一真正适合插件的地方) | 纯实例内 UI 与工具,正是插件机制的用途 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、三种形态的优劣
|
|||
|
|
|
|||
|
|
### A · dsh 插件形态(把覆盖网络做成插件)
|
|||
|
|
|
|||
|
|
**优点**:不动平台内核;可独立发版;用户可自助启停;回滚粒度细(禁用即可)。
|
|||
|
|
|
|||
|
|
**缺点**:**能力边界是硬的** —— 插件跑在实例内部,**看不见宿主网络栈、够不到 Worker↔Manager 隧道、无法参与控制面归属与租约**;覆盖网络的核心问题(跨机可达 / 节点身份 / 寻址)**一个都解决不了**;且插件加载失败会把实例拖进崩溃循环(已有探活回滚机制,但仍是额外风险面)。
|
|||
|
|
|
|||
|
|
**⇒ 判定:只能覆盖第三层(实例内展示与工具),不能承担主力。**
|
|||
|
|
|
|||
|
|
### B · 改内核形态(把会合/中继塞进平台主进程)
|
|||
|
|
|
|||
|
|
**优点**:改动集中;复用现有配置与日志;部署单元不增加;短期最快。
|
|||
|
|
|
|||
|
|
**缺点**:与平台**同生共死**(中继挂了平台一起受影响);中继要**独立扩缩容**时做不到;**对外暴露面与内核同进程**(发布层因此无法做独立安全加固);端口空间与 Manager 全局共享(就是现状的 C2 耦合);版本矩阵无法独立演进。
|
|||
|
|
|
|||
|
|
**⇒ 判定:现状就是这个形态,也正是要拆掉的那个问题。**
|
|||
|
|
|
|||
|
|
### C · 独立组件 + 平台内模块化(**推荐主力**)
|
|||
|
|
|
|||
|
|
**优点**:① **顺着现有架构走** —— 平台已有 Manager / Worker 分体与独立 systemd 单元的先例,不是新造范式;② 控制面/数据面**天然分离**,符合既有分层判据;③ 可独立换机、多实例、独立加固(发布层单独处理 DDoS);④ 每一步可独立回滚(S0–S4 已定)。
|
|||
|
|
|
|||
|
|
**缺点**:多一个部署单元与版本矩阵;本机开发环境要能跑起来(本机是 Windows,需容器或远程);会引入"组件间契约"这条新的维护面。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、现有项目代码评估:**设计基本合理,且为这个方向留了缝**
|
|||
|
|
|
|||
|
|
### 4.1 合理之处(有代码证据)
|
|||
|
|
|
|||
|
|
| # | 事实 | 为什么关键 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | `Spawner` 是干净的后端抽象缝(`launch / stop / status / endpointFor / restartAndProbe`,`src/supervisor/spawner.ts:94-149`) | **新增一种节点 = 多一个实现**,不是改内核;route 层只依赖接口 |
|
|||
|
|
| 2 | Worker agent 有**四条协议纪律**(单向拨入 / 幂等键 `operationId` / 最小接口白名单 / self-fencing,`src/worker/agent.ts:10-17`) | 这**就是**现成的"节点契约"—— 客户端节点可直接复用同一套语义 |
|
|||
|
|
| 3 | 归属 / 租约**只有 Manager 能写**(`epoch+1` fencing) | 与"客户端不可信"天然相容 ⇒ 客户端天生只能当数据面,不会有脑裂 |
|
|||
|
|
| 4 | `tunnelTarget === '' ⇒ 完全不建隧道`(`agent.ts:154`) | **扩展点是预留的**:同机形态零影响,跨机才启用 |
|
|||
|
|
| 5 | 全仓仅 **1 处** `process.platform` 分支(`supervisor/firewall.ts:42`) | 跨平台改造成本低 |
|
|||
|
|
| 6 | `instanceHost` 已是参数(注释:"跨机时填内网 IP") | 寻址**已经是参数化的**,不是写死 |
|
|||
|
|
|
|||
|
|
### 4.2 不足(4 处,均为**已知或有据**的具体欠账)
|
|||
|
|
|
|||
|
|
| # | 不足 | 证据 | 影响 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| 1 | **寻址只有 `{host, port}`,表达不了"经谁到达"** | `Endpoint = {host, port}`(`spawner.ts:80-83`);`hostsProvider` 把 `dsh_hosts.endpoint` 直接当 `agentUrl` | 换中继时表里无处表达 ⇒ **必须加 `via` 字段**(越晚改越贵) |
|
|||
|
|
| 2 | **共享 bearer token,无法按节点吊销** | `agent.ts:40` 注释自陈:"本版是 bearer 式比较,**HMAC/防重放留待后续**" | 公网上不成立;**这是项目自己记录的已知欠账**,正好是覆盖网络要补的 |
|
|||
|
|
| 3 | **中继与 Manager 同生共死** | 隧道落在 Manager 的 sshd(`32022`),端口空间与 Manager 全局共享 | 中继不可多实例、不可换机、单点 |
|
|||
|
|
| 4 | **控制面 PG 复用同一条隧道** | `DSHS_TUNNEL_STATIC_PORTS`,设计上含控制面 PG | 换中继时 DB 连接一起断 ⇒ **回滚面比看上去大** |
|
|||
|
|
|
|||
|
|
### 4.3 总评
|
|||
|
|
|
|||
|
|
> **合理程度:中上。** 它是"**为多节点预留了缝**"的设计 —— 抽象缝(Spawner)、协议纪律、参数化寻址、开关式隧道,这四样都在。
|
|||
|
|
> **但也正因为缝开对了,改造的成本主要在"补两个字段 + 分两步换绑定",而不是重构内核。**
|
|||
|
|
> 唯一的严肃欠账是**身份**(共享 token),而项目**自己已经在注释里写明了**这是待办 —— 说明设计者是清醒的,不是漏掉。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、能否支持这个方向的改造:**能,且不需要重构**
|
|||
|
|
|
|||
|
|
| 需要的改造 | 现有设计支持度 | 落点 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 新增一种节点类型(客户端/骨干) | ✅ **直接支持** —— 加一个 `Spawner` 实现 + 复用 agent 四纪律 | 新文件,不动内核 |
|
|||
|
|
| 寻址加 `via` | ⚠️ **需加字段**(向后兼容:有默认值,旧代码不受影响) | S2(方案已出) |
|
|||
|
|
| 会合地址出 env | ✅ **易**(`tunnelTarget` 已是配置;再加一个优先项即可) | S1 |
|
|||
|
|
| 中继独立成单元 | ✅ **易** —— 已定"不换协议、只换绑定关系" | S4 |
|
|||
|
|
| 节点身份(一机一钥) | ⚠️ **要新写**,但接口位置清楚(token 校验点集中) | 拆分方案之后 |
|
|||
|
|
| 发布层 | 🆕 **全新**,与平台主进程分开 = 天然适合独立单元 | 新组件 |
|
|||
|
|
|
|||
|
|
**⇒ 结论:改造路径与现有架构**不冲突**,是"顺着缝往下切",不是"推倒重来"。**会合中继拆分方案 S0–S4 已经把顺序定好了(S0 纯新增文件 + 可选字段,零行为变化)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、我选了什么(可推翻)
|
|||
|
|
|
|||
|
|
1. **主力形态 = 独立组件 + 平台内模块化**,不是 dsh 插件、也不是塞进主进程。
|
|||
|
|
2. **dsh 插件只承担第三层**(实例内的"我的网络/我的设备"面板与文件互传工具)—— 这是唯一适合插件的部分。
|
|||
|
|
3. **先"平台内模块化 + 独立 systemd 单元",暂不拆独立仓库** —— 现在只有两台机器,独立仓库会带来版本矩阵与同步成本;而 S0 的接口抽象已经让"以后再拆"变得便宜。
|
|||
|
|
4. **身份(一机一钥)放在拆分之后**,但它**必须排在任何公网暴露之前**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、本次未做
|
|||
|
|
|
|||
|
|
- ⛔ 未改任何代码、未动服务器、未写文档库(全局执行锁被 `修复轮-决策方法-2b` 占用)。
|
|||
|
|
- 📌 未新增上抛项 —— 待拍板仍是:骨干服务范围(A 自用 / B 全网)+ 发布层形态与成本。
|