Files
MoShiro/docs/fleet/overview.md
T
justme 2e146d4da7
ci/woodpecker/push/main-amd64-build Pipeline was successful
refactor!: rename the project from Monitor to MoShiro [CI]
Namespaces, assemblies, solution, binaries, images, systemd units, config paths, environment variables, protocol methods and the Linux user are all renamed. Breaking: existing databases, node identities and installed units must be recreated.
2026-10-07 02:03:25 +08:00

8.3 KiB
Raw Blame History

Fleet:通用节点框架

实现状态:Fleet.Update、Fleet.Server.Releases、fleet-updater、fleet-release 还只是设计;容器节点的更新目前由宿主机上的 moshiro-update 脚本和 MoShiro 的 ReleaseService 完成(见 deployment.md)。其余组件已实现。

名称暂定。Fleet 与业务无关,MoShiro 是它的第一个使用者。

1. 定位

凡是“很多节点连到一个面板”的产品,都要解决同一批问题:节点怎么接入、怎么证明身份、怎么保持连接、怎么可靠上报、怎么接收配置、怎么更新自己。Fleet 把这些做成通用库和工具,产品只需要写业务。

┌──────────────────────────── 产品层(各产品自己写) ─────────────────────────────┐
│ MoShiro:  Protocol(Kind/任务) · Measurement(积木) · Agent · Probe · Backend     │
│ 其他产品:  YourApp.Node · YourApp.Server                                        │
└──────────────────────────────────┬─────────────────────────────────────────────┘
                                   │ 只依赖 Fleet;Fleet 不认识任何产品
┌───────────────────────────────── Fleet ───────────────────────────────────────┐
│ 节点侧(只依赖 BCL,支持 AOT)             服务端侧(ASP.NET Core)              │
│ Fleet.Core        Result/退避/有界队列    Fleet.Server.Enrollment  注册与审批    │
│ Fleet.Identity    密钥/签名/证书/存储      Fleet.Server.Link        wss 网关/在线表 │
│ Fleet.Rpc         JSON-RPC/路由/二进制帧   Fleet.Server.Releases    通道与灰度(可选)│
│ Fleet.Link        会话/认证/重连/能力/     Fleet.Server.Sqlite      存储实现(可选)│
│                   发件箱/状态同步/点对点    IFleetStore              存储抽象        │
│ Fleet.Hosting     模块宿主/配置/日志/服务外壳/健康信标                             │
│ Fleet.Update      清单/验签/安装/切换/回滚                                        │
│ 工具:fleet-enroll(注册)  fleet-updater(更新)  fleet-release(CI 签名)        │
└──────────────────────────────────────────────────────────────────────────────┘

2. 设计原则

  1. 与业务无关:Fleet 中不出现任何产品概念。产品通过扩展点接入:元数据类型、RPC 方法、发件箱消息类型、期望状态文档类型。scripts/check-deps 强制规定 backend/fleet/** 不能引用 MoShiro.*。
  2. 安全默认值:
    • Fleet 永远不提供 exec、shell、文件读写、远程下发代码这类方法;
    • 节点只响应本地注册过的方法,本地策略 allow_methods 还可以进一步收窄;
    • 更新必须通过离线密钥签名验证,面板即使被攻破也推不出恶意二进制。
  3. 权限分离:注册(fleet-enroll,一次性运行)、常驻业务进程、更新(fleet-updater)是三个独立的进程,使用不同的系统用户,各自只拥有最小权限。
  4. NativeAOT 优先:节点侧只依赖 BCL;泛型扩展点通过产品传入的 JsonTypeInfo<T> 实现序列化,不使用反射。
  5. 只抽取真正用到的:每项能力都必须同时被 MoShiro 和 samples/EchoNode 使用,防止过度设计。

3. 组件

组件 侧 职责 详细
Fleet.Core 两侧 Result<T>、错误码基类、退避、有界队列、ULID/UUIDv7 —
Fleet.Identity 两侧 ECDSA P-256 身份密钥、自签名证书、SPKI 指纹、带用途前缀的签名串、KeyStore(文件权限 0600) link.md §2
Fleet.Rpc 两侧 JSON-RPC 2.0 信封、方法路由、请求与通知、二进制帧、错误映射;与传输方式无关 link.md §4
Fleet.Link 节点 连接服务端(wss)或其他节点(TLS);认证、心跳、重连、能力协商、可靠发件箱、期望状态同步 link.md
Fleet.Enrollment.Client 节点 加入令牌注册流程(供 fleet-enroll 使用) link.md §3
Fleet.Hosting 节点 模块宿主、配置(源生成 JSON)、logfmt 日志、服务外壳(systemd/procd/Windows)、健康信标 link.md §8
Fleet.Update 节点 清单格式、验签、下载校验、多版本目录与原子切换、服务适配器、健康确认、回滚 update.md
Fleet.Server.Enrollment 服务端 加入令牌、注册端点、审批与接管 link.md §3
Fleet.Server.Link 服务端 wss 端点、签名认证、连接注册表、在线事件、状态下发、收件箱 ACK link.md
Fleet.Server.Releases 服务端(可选) 托管清单、管理通道、灰度发布、汇总各节点版本 update.md §6
Fleet.Server.Sqlite 服务端(可选) IFleetStore 的 SQLite 实现(节点、令牌、公钥、状态版本) —
fleet-enroll 工具 节点注册:生成密钥、调用注册端点、写入配置 link.md §3
fleet-updater 工具 节点更新守护进程,可以同时管理多个产品 update.md
fleet-release 工具 在 CI 或离线环境中生成并签名发布清单 update.md §3

4. 目录结构

fleet/                              以后可以原样拆成独立仓库并发布 NuGet 包
├─ Directory.Build.props            导入仓库根目录的 props
├─ src/
│  ├─ Fleet.Core/  Fleet.Identity/  Fleet.Rpc/  Fleet.Link/  Fleet.Hosting/  Fleet.Update/
│  ├─ Fleet.Enrollment.Client/
│  └─ Fleet.Server.Enrollment/  Fleet.Server.Link/  Fleet.Server.Releases/  Fleet.Server.Sqlite/
├─ tools/  fleet-enroll/  fleet-updater/  fleet-release/
├─ samples/  EchoNode/  EchoServer/   最小示例:不依赖 MoShiro 的第二个使用者
├─ tests/
└─ docs → 仓库 docs/fleet/

5. 演进策略

  • 现阶段(已确认,暂不独立):放在 MoShiro 仓库的 backend/fleet/ 目录中,通过项目引用使用,一处修改两边同时编译。
  • 拆分条件:公开 API 连续两个里程碑没有破坏性变更,并且 samples 能覆盖全部能力。满足后拆成独立仓库,按 semver 发布 NuGet 包,MoShiro 改为包引用。
  • 公开 API 审查:backend/fleet/src/* 的 public 类型使用 PublicAPI.Shipped.txt / PublicAPI.Unshipped.txt 跟踪(使用 Microsoft.CodeAnalysis.PublicApiAnalyzers,只在构建期生效),任何变更都会在 PR 中显示出来。

6. 产品接入一览

节点侧:

var identity = NodeIdentity.Load(config.IdentityDir);                // 由 fleet-enroll 生成
var link = FleetLink.ToServer(config.Server, identity, MyRpcContext.Default)
    .WithCapabilities(["myapp.v1"])
    .WithState<MyDesired>(MyRpcContext.Default.MyDesired, reconciler) // 期望状态同步(可选)
    .WithOutbox<MyReport>(MyReportCodec.Instance, maxBytes: 16 << 20) // 可靠上报(可选)
    .On<DoThingParams, DoThingResult>("myapp.do_thing", HandleAsync); // 业务方法
var host = new ModuleHost(log).Add(link).Add(myModules);
await ServiceShell.RunAsync(host, HealthBeacon.From(config));         // 同时提供更新所需的健康确认

服务端:

builder.Services.AddFleetServer(o => o.UseStore<SqliteFleetStore>())
    .AddState<MyDesired>(desiredProvider)          // 为每个节点计算期望状态
    .AddInbox<MyReport>(reportHandler)             // 持久化之后再 ACK
    .OnNodeEvent(presenceHandler);                 // 上线、下线、版本变化
app.MapFleetEnrollment("/fleet/enroll");
app.MapFleetLink("/fleet/rpc");
app.MapFleetReleases("/fleet/releases");           // 可选