Files
MoShiro/docs/fleet/overview.md
T
justme 83e5120377 refactor!: rename the project from Monitor to MoShiro
Namespaces, assemblies, projects and directories, the solution, binaries,
images, systemd units, config paths, environment variables, protocol method
names, the media type and the raw chunk magic all move to MoShiro/moshiro.
Existing data and deployments are not compatible and must be recreated.
Also fix the architecture tests after the solution layout change and make
the update tests independent of their order.
2026-10-07 01:49:04 +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");           // 可选