dashboard-nanobot/design/remote-node-management.md

572 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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 控制平台。