572 lines
14 KiB
Markdown
572 lines
14 KiB
Markdown
# Dashboard Nanobot 远端节点管理设计(方案 A)
|
||
|
||
本文档定义 Dashboard Nanobot 的多节点远端管理方案,目标是在尽量少侵入 nanobot 核心源码的前提下,让当前面板可以统一管理部署在其它电脑上的 nanobot 实例,并保持与本机 Bot 相近的操作体验。
|
||
|
||
## 1. 目标与边界
|
||
|
||
### 1.1 目标
|
||
|
||
- 中心面板统一管理多台机器上的 nanobot 实例。
|
||
- 远端 Bot 支持:
|
||
- 查看运行状态
|
||
- 启动、停止、重启
|
||
- 下发控制命令,如 `/new`、`/stop`、`/restart`
|
||
- 查看实时日志和结构化运行事件
|
||
- 读取和编辑工作区文件
|
||
- 创建新 Bot、升级已有 Bot 核心
|
||
- 远端机器既支持 Docker 部署,也支持宿主机直接安装运行。
|
||
- 尽量不修改 nanobot 核心,只复用自定义 `dashboard.py` channel。
|
||
|
||
### 1.2 非目标
|
||
|
||
- 不让中心面板直接通过 SSH 管理远端机器。
|
||
- 不让中心面板直接操作远端 Docker Remote API。
|
||
- 不在 nanobot 核心中引入“多节点”或“集群”概念。
|
||
- 不要求用户手工编辑远端 `config.json`。
|
||
|
||
### 1.3 设计原则
|
||
|
||
- 控制平面与执行平面分离。
|
||
- 远端机器自治,中心只负责编排与聚合。
|
||
- nanobot 核心零或极低侵入。
|
||
- Docker 与宿主机直装都作为一等运行模式支持。
|
||
- 面向逐步上线,优先跑通命令与状态链路,再补管理能力。
|
||
|
||
## 2. 总体方案
|
||
|
||
采用“中心控制面 + 远端节点代理”的双层结构。
|
||
|
||
- 中心控制面:
|
||
- 当前 dashboard 的 frontend + backend
|
||
- 负责统一 UI、数据库、权限、审计、聚合视图
|
||
- 远端节点代理:
|
||
- 每台远端机器部署一个轻量 `dashboard-edge`
|
||
- 负责本机 Bot 生命周期、工作区、日志流、命令投递
|
||
- nanobot 实例:
|
||
- 继续使用自定义 `dashboard.py`
|
||
- 对外只暴露本地 Dashboard Channel
|
||
|
||
### 2.1 架构图
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
UI["Dashboard Frontend"] --> CP["Central Backend"]
|
||
CP <--> DB["Central DB"]
|
||
CP <--> EDGE1["Node Agent A"]
|
||
CP <--> EDGE2["Node Agent B"]
|
||
EDGE1 <--> BOT1["Nanobot (Host Process)"]
|
||
EDGE1 <--> BOT2["Nanobot (Docker)"]
|
||
EDGE2 <--> BOT3["Nanobot (Host Process)"]
|
||
```
|
||
|
||
### 2.2 关键结论
|
||
|
||
- 不扩展 nanobot 去理解“远端管理”。
|
||
- 不要求面板直接连接远端 Bot 的文件系统或 Docker。
|
||
- 所有远端执行动作都先到节点代理,再由节点代理在本机执行。
|
||
|
||
## 3. 为什么选择方案 A
|
||
|
||
相对于“中心直接 SSH 管理远端机器”或“每台机器都跑一套完整 dashboard 后端”,方案 A 更适合当前项目:
|
||
|
||
- 与现有架构兼容性最高。
|
||
- 可以同时覆盖 Docker 和宿主机直装。
|
||
- 中心端仍保留统一数据库与统一 UI,不会产生多套后台状态漂移。
|
||
- 节点代理可以封装平台差异,如 macOS、Linux、Windows 的进程管理差异。
|
||
- 自定义 `dashboard.py` 可以直接复用,不需要重新定义 bot 内部协议。
|
||
|
||
## 4. 与现有代码的关系
|
||
|
||
当前代码默认“控制端和执行端在同一台机器”:
|
||
|
||
- `backend/core/docker_manager.py`
|
||
- 直接调用本机 Docker
|
||
- `backend/core/config_manager.py`
|
||
- 直接写本机 workspace 和 `.nanobot/config.json`
|
||
- `backend/main.py`
|
||
- `start/stop/command/workspace/monitor` 全部默认操作本机资源
|
||
|
||
因此,多节点能力不应直接在这些逻辑上继续叠加条件分支,而应先抽象出执行层接口,再分别实现本地与远端两类 Provider。
|
||
|
||
## 5. 运行模式设计
|
||
|
||
每个 Bot 必须明确声明运行模式:
|
||
|
||
- `docker`
|
||
- `host`
|
||
|
||
节点代理内部为两种模式提供统一执行接口。
|
||
|
||
### 5.1 Docker 模式
|
||
|
||
- Bot 运行在本机 Docker 容器中。
|
||
- 节点代理负责:
|
||
- 启停容器
|
||
- 监控容器日志
|
||
- 发送命令到容器内 dashboard channel
|
||
- 管理挂载的 `.nanobot/workspace`
|
||
|
||
### 5.2 Host 模式
|
||
|
||
- Bot 直接运行在宿主机进程中。
|
||
- 节点代理负责:
|
||
- 启停本机进程或系统服务
|
||
- 捕获 stdout/stderr
|
||
- 发送命令到本机 dashboard channel
|
||
- 管理本机工作区
|
||
|
||
### 5.3 Host 模式的关键约束
|
||
|
||
宿主机直装时,多个 Bot 不能共用固定端口,因此 Dashboard Channel 端口必须由节点代理自动分配并持久化。
|
||
|
||
推荐策略:
|
||
|
||
- Docker 模式:
|
||
- 容器内可继续使用 `0.0.0.0:9000`
|
||
- Host 模式:
|
||
- 使用 `127.0.0.1:{auto_assigned_port}`
|
||
- 例如 `19101`、`19102`、`19103`
|
||
|
||
原因:
|
||
|
||
- 直装场景下避免端口冲突
|
||
- 避免把 Bot 的本地控制端口暴露给局域网
|
||
- 只允许节点代理本机访问
|
||
|
||
## 6. nanobot 侧侵入边界
|
||
|
||
### 6.1 保持不变
|
||
|
||
nanobot 核心本身不需要感知节点、中心控制面或跨机调度。
|
||
|
||
### 6.2 仅要求保留的自定义能力
|
||
|
||
- 自定义 `dashboard.py` channel 可用
|
||
- `start()` 和 `stop()` 使用基类状态字段 `self._running`
|
||
- 支持 `config.json` 中启用 `channels.dashboard`
|
||
- `dashboard.py` 支持:
|
||
- `POST /chat` 入站命令
|
||
- 结构化 stdout 出站消息
|
||
|
||
### 6.3 dashboard.py 的定位
|
||
|
||
它仍然只是“本机 Bot 控制通道”,不是中心与远端节点之间的通信协议。
|
||
|
||
分工如下:
|
||
|
||
- 中心与节点代理通信:Node Agent API / WebSocket
|
||
- 节点代理与 Bot 通信:本机 `dashboard.py`
|
||
|
||
## 7. 中心端改造方案
|
||
|
||
中心端不直接继续依赖本机 Docker 和本机文件系统,而是抽象出执行接口。
|
||
|
||
### 7.1 建议新增 Provider 抽象
|
||
|
||
- `RuntimeProvider`
|
||
- `start_bot`
|
||
- `stop_bot`
|
||
- `restart_bot`
|
||
- `send_command`
|
||
- `get_status`
|
||
- `get_recent_logs`
|
||
- `stream_monitor`
|
||
- `WorkspaceProvider`
|
||
- `list_tree`
|
||
- `read_file`
|
||
- `write_markdown`
|
||
- `upload_files`
|
||
- `download_file`
|
||
- `BotProvisionProvider`
|
||
- `create_bot`
|
||
- `upgrade_bot`
|
||
- `delete_bot`
|
||
- `sync_config`
|
||
|
||
### 7.2 Provider 实现建议
|
||
|
||
- `LocalRuntimeProvider`
|
||
- 复用当前 `docker_manager.py`
|
||
- `LocalWorkspaceProvider`
|
||
- 复用当前本地 workspace 读写逻辑
|
||
- `RemoteRuntimeProvider`
|
||
- 通过节点代理 API / WebSocket 调用远端动作
|
||
- `RemoteWorkspaceProvider`
|
||
- 通过节点代理文件接口访问远端 workspace
|
||
|
||
### 7.3 中心端路由层原则
|
||
|
||
前端 API 尽量保持稳定,例如:
|
||
|
||
- `/api/bots/{bot_id}/start`
|
||
- `/api/bots/{bot_id}/stop`
|
||
- `/api/bots/{bot_id}/command`
|
||
- `/api/bots/{bot_id}/workspace/tree`
|
||
|
||
但这些接口在后端内部根据 `bot.node_id` 和 `bot.runtime_kind` 路由到不同 Provider。
|
||
|
||
这样可以减少前端改动,并保持本机 Bot 与远端 Bot 的统一交互模型。
|
||
|
||
## 8. 节点代理设计
|
||
|
||
### 8.1 职责
|
||
|
||
远端节点代理 `dashboard-edge` 负责:
|
||
|
||
- 本机 Bot 注册和枚举
|
||
- Bot 创建、升级、删除
|
||
- Bot 启停与重启
|
||
- 命令下发
|
||
- 日志采集与结构化事件解析
|
||
- 工作区文件读写
|
||
- Dashboard Channel 配置自动注入
|
||
- 向中心汇报节点状态和 Bot 状态
|
||
|
||
### 8.2 统一执行接口
|
||
|
||
节点代理内部也需要抽象执行器:
|
||
|
||
- `DockerExecutor`
|
||
- `HostProcessExecutor`
|
||
|
||
两者都实现:
|
||
|
||
- `start_bot`
|
||
- `stop_bot`
|
||
- `restart_bot`
|
||
- `send_command`
|
||
- `read_logs`
|
||
- `read_workspace_file`
|
||
- `write_workspace_file`
|
||
- `get_resource_snapshot`
|
||
|
||
### 8.3 HostProcessExecutor 推荐实现
|
||
|
||
首版建议使用“节点代理托管子进程”的方式,而不是一开始就深度接入系统服务管理器。
|
||
|
||
优点:
|
||
|
||
- 首版开发快
|
||
- 可直接拿到 stdout/stderr
|
||
- 更容易复用现有 dashboard channel 日志解析逻辑
|
||
|
||
后续可演进为:
|
||
|
||
- Linux: `systemd`
|
||
- macOS: `launchd`
|
||
- Windows: Service
|
||
|
||
## 9. 节点与中心的通信模型
|
||
|
||
建议采用“节点主动连中心”的反向长连接优先模型,同时兼容同网环境下的 HTTPS 直连。
|
||
|
||
### 9.1 推荐默认模式
|
||
|
||
- 节点启动后主动向中心注册
|
||
- 建立长期 WebSocket
|
||
- 中心通过该连接发送控制命令
|
||
- 节点通过该连接回传:
|
||
- 心跳
|
||
- Bot 状态
|
||
- 结构化事件
|
||
- 日志摘要
|
||
|
||
### 9.2 为什么优先反向长连接
|
||
|
||
- 适配 NAT 与家庭宽带场景
|
||
- 远端节点无需开放入站端口
|
||
- 更适合公网分散机器接入
|
||
|
||
### 9.3 可选直连模式
|
||
|
||
当节点与中心在同一内网或 VPN 内时,可允许中心通过 HTTPS 直接调用节点代理 API。
|
||
|
||
## 10. Bot 元数据模型调整
|
||
|
||
当前 `bot_instance` 只适合单机场景,需要扩展节点信息。
|
||
|
||
### 10.1 新增 node_instance
|
||
|
||
建议新增 `node_instance` 表:
|
||
|
||
- `id`
|
||
- `name`
|
||
- `status`
|
||
- `agent_version`
|
||
- `last_seen_at`
|
||
- `connection_mode`
|
||
- `auth_token_hash`
|
||
- `host_name`
|
||
- `os_type`
|
||
- `capabilities_json`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
### 10.2 扩展 bot_instance
|
||
|
||
建议为 `bot_instance` 增加:
|
||
|
||
- `node_id`
|
||
- `runtime_kind`
|
||
- `remote_bot_id`
|
||
- `dashboard_host`
|
||
- `dashboard_port`
|
||
- `runtime_meta_json`
|
||
|
||
说明:
|
||
|
||
- `node_id` 标识该 Bot 归属哪个节点
|
||
- `runtime_kind` 表示 `docker` 或 `host`
|
||
- `dashboard_port` 用于 Host 模式的本地控制端口映射
|
||
- `remote_bot_id` 允许未来节点端使用独立内部 ID
|
||
|
||
### 10.3 Bot ID 策略
|
||
|
||
建议中心平台继续保持 `bot_instance.id` 全局唯一。
|
||
|
||
如果远端已有同名 Bot,可:
|
||
|
||
- 中心分配平台级 ID
|
||
- 节点侧保留原始 `remote_bot_id`
|
||
|
||
这样可避免跨节点命名冲突。
|
||
|
||
## 11. Dashboard Channel 配置策略
|
||
|
||
### 11.1 配置自动注入
|
||
|
||
所有由中心或节点代理创建、升级、同步的 Bot,都由节点代理自动保证 `channels.dashboard` 存在。
|
||
|
||
用户不需要手工编辑 `config.json`。
|
||
|
||
### 11.2 生成策略
|
||
|
||
Docker 模式建议写入:
|
||
|
||
```json
|
||
{
|
||
"enabled": true,
|
||
"host": "0.0.0.0",
|
||
"port": 9000,
|
||
"allowFrom": ["*"]
|
||
}
|
||
```
|
||
|
||
Host 模式建议写入:
|
||
|
||
```json
|
||
{
|
||
"enabled": true,
|
||
"host": "127.0.0.1",
|
||
"port": 19101,
|
||
"allowFrom": ["127.0.0.1", "::1"]
|
||
}
|
||
```
|
||
|
||
其中 `port` 由节点代理自动分配,不能写死。
|
||
|
||
### 11.3 面板行为约束
|
||
|
||
中心面板与节点代理都应把 `dashboard` 视为内建保留渠道:
|
||
|
||
- 自动存在
|
||
- 不允许删除
|
||
- 不允许普通用户手改关键监听参数
|
||
|
||
## 12. 关键数据流
|
||
|
||
### 12.1 命令下发流
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant UI as Frontend
|
||
participant CP as Central Backend
|
||
participant EDGE as Node Agent
|
||
participant BOT as Nanobot Dashboard Channel
|
||
|
||
UI->>CP: POST /api/bots/{id}/command
|
||
CP->>EDGE: send_command(bot_id, command)
|
||
EDGE->>BOT: POST /chat
|
||
BOT-->>EDGE: 200 OK
|
||
EDGE-->>CP: accepted
|
||
CP-->>UI: success
|
||
```
|
||
|
||
### 12.2 运行事件回传流
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant BOT as Nanobot
|
||
participant EDGE as Node Agent
|
||
participant CP as Central Backend
|
||
participant UI as Frontend
|
||
|
||
BOT->>EDGE: stdout structured packet
|
||
EDGE->>EDGE: parse packet
|
||
EDGE->>CP: runtime event push
|
||
CP->>CP: persist message/state/event
|
||
CP->>UI: websocket broadcast
|
||
```
|
||
|
||
### 12.3 工作区文件流
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant UI as Frontend
|
||
participant CP as Central Backend
|
||
participant EDGE as Node Agent
|
||
|
||
UI->>CP: GET /api/bots/{id}/workspace/file
|
||
CP->>EDGE: read_workspace_file(bot_id, path)
|
||
EDGE-->>CP: file content
|
||
CP-->>UI: markdown/text payload
|
||
```
|
||
|
||
## 13. 节点代理 API 草案
|
||
|
||
首版建议具备如下能力。
|
||
|
||
### 13.1 节点管理
|
||
|
||
- `POST /agent/handshake`
|
||
- `POST /agent/heartbeat`
|
||
- `GET /agent/capabilities`
|
||
|
||
### 13.2 Bot 管理
|
||
|
||
- `GET /agent/bots`
|
||
- `POST /agent/bots`
|
||
- `POST /agent/bots/{bot_id}/upgrade`
|
||
- `DELETE /agent/bots/{bot_id}`
|
||
- `POST /agent/bots/{bot_id}/start`
|
||
- `POST /agent/bots/{bot_id}/stop`
|
||
- `POST /agent/bots/{bot_id}/restart`
|
||
- `POST /agent/bots/{bot_id}/command`
|
||
|
||
### 13.3 工作区与文件
|
||
|
||
- `GET /agent/bots/{bot_id}/workspace/tree`
|
||
- `GET /agent/bots/{bot_id}/workspace/file`
|
||
- `PUT /agent/bots/{bot_id}/workspace/file`
|
||
- `POST /agent/bots/{bot_id}/workspace/upload`
|
||
- `GET /agent/bots/{bot_id}/logs`
|
||
|
||
### 13.4 推送通道
|
||
|
||
- `WS /agent/ws`
|
||
|
||
推送内容包括:
|
||
|
||
- 节点上线/离线
|
||
- 心跳
|
||
- Bot 状态
|
||
- 结构化运行消息
|
||
- 运维事件
|
||
|
||
## 14. 安全模型
|
||
|
||
### 14.1 基础要求
|
||
|
||
- 节点与中心之间必须使用 HTTPS 或 WSS。
|
||
- 节点首次接入使用一次性注册码。
|
||
- 注册完成后发放长期令牌。
|
||
- 中心只保存令牌摘要,不保存明文。
|
||
|
||
### 14.2 权限边界
|
||
|
||
- 中心不能直接访问远端文件系统,只能经节点代理。
|
||
- 节点代理只能操作本机所属 Bot 工作区。
|
||
- 所有文件接口必须保留路径越界校验。
|
||
|
||
### 14.3 命令幂等
|
||
|
||
每次命令下发都应带 `request_id`,节点代理应避免因网络重试导致重复执行。
|
||
|
||
### 14.4 审计
|
||
|
||
中心端应记录:
|
||
|
||
- 谁对哪个 Bot 下发了什么命令
|
||
- 命令发往哪个节点
|
||
- 节点是否接受和执行
|
||
- 最终结果和错误原因
|
||
|
||
## 15. 分阶段实施计划
|
||
|
||
### 15.1 第一阶段:跑通远端控制链路
|
||
|
||
目标:
|
||
|
||
- 节点注册
|
||
- 节点在线状态
|
||
- 远端 Bot 列表
|
||
- `start/stop/restart`
|
||
- `/new`、`/stop`、`/restart` 下发
|
||
- 实时日志与状态回传
|
||
|
||
特点:
|
||
|
||
- 优先打通“像本机一样可通讯、可下发指令”
|
||
- 暂不强求全部文件管理能力
|
||
|
||
### 15.2 第二阶段:补齐远端 Bot 生命周期管理
|
||
|
||
目标:
|
||
|
||
- 新建远端 Bot
|
||
- 升级旧 Bot 到新核心
|
||
- 自动补 `dashboard` 配置
|
||
- 支持 Docker 与 Host 两类运行模式
|
||
|
||
### 15.3 第三阶段:补齐工作区能力
|
||
|
||
目标:
|
||
|
||
- 文件树浏览
|
||
- Markdown 在线编辑与保存
|
||
- 文件上传下载
|
||
- 技能包管理
|
||
|
||
### 15.4 第四阶段:稳定性与权限强化
|
||
|
||
目标:
|
||
|
||
- 节点断线恢复
|
||
- 节点版本兼容检查
|
||
- 审计日志完善
|
||
- 权限分级
|
||
- 节点灰度升级
|
||
|
||
## 16. 风险与注意事项
|
||
|
||
### 16.1 最大技术风险
|
||
|
||
- Host 模式的端口分配与持久化管理
|
||
- 节点代理重启后的进程状态恢复
|
||
- 不同操作系统上的进程守护差异
|
||
- 网络抖动下的命令幂等与状态一致性
|
||
|
||
### 16.2 兼容性风险
|
||
|
||
- 不同版本 nanobot 核心对 channel 生命周期字段要求可能不同
|
||
- `dashboard.py` 需要继续保持与 post5 的 `self._running` 兼容
|
||
- 老版本 Bot 升级时必须自动补全 `channels.dashboard`
|
||
|
||
### 16.3 明确不建议的路径
|
||
|
||
- 不建议中心直接 SSH 管理远端机器
|
||
- 不建议暴露 Docker Remote API 给中心
|
||
- 不建议让每台远端机器都维护一套完整 dashboard 主后台数据库
|
||
|
||
## 17. 最终建议
|
||
|
||
项目应以“中心控制面 + 远端节点代理”为长期结构,宿主机直装作为一等公民,Docker 作为兼容执行后端。
|
||
|
||
实现上优先做三件事:
|
||
|
||
1. 中心端抽象 Provider 层,解除对本机 Docker 和本机文件系统的硬绑定。
|
||
2. 设计并落地 `dashboard-edge`,统一承接远端执行、日志、文件和命令。
|
||
3. 在节点代理侧自动注入 `dashboard` channel 配置,避免用户手工维护远端 `config.json`。
|
||
|
||
这样可以在几乎不改 nanobot 核心设计的前提下,将当前面板平滑演进为多节点 Bot 控制平台。
|