feat: probe host stats, node cards with a separate lines panel grouped by carrier, Windows host sampling, manual carrier override [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful

This commit is contained in:
justme committed 2026-10-08 21:56:19 +08:00
1 parent bac1c27e72
commit 88b1a0a9bb
36 files changed
+750 -185

No files matched your search

+3 -3
View File
@@ -91,14 +91,14 @@
| 端点 | 内容 |
| --- | --- |
| `GET /api/public/hosts` | 每个对外可见的 Agent 的最新快照:`{agent_id, name, online, stale, last_seen_at, host}`;超过 15 s 没有更新 `stale` 为真(离线,或者 Agent 关了上报) |
| `GET /api/public/agents/{agent_id}/host?range=1h` | 历史曲线(列式,按步长取平均;`range` 从 1 小时到 30 天):`cpu`、`mem`、`disk`(百分比)、`rx_bps`、`tx_bps` |
| `GET /api/public/hosts` | 每个对外可见的 Agent 和没被吊销的 Probe 的最新快照:`{id, kind, name, online, stale, last_seen_at, host}`(`kind` 是 `agent` 或 `probe`);超过 15 s 没有更新 `stale` 为真(离线,或者节点关了上报) |
| `GET /api/public/hosts/{node_id}?range=1h` | Agent 或 Probe 的历史曲线(列式,按步长取平均;`range` 从 1 小时到 30 天):`cpu`、`mem`、`disk`(百分比)、`rx_bps`、`tx_bps` |
`host` 只有汇总的数字:CPU 占用、内存与根分区的已用和总量、网卡累计收发字节与瞬时网速、系统运行时长。**没有 CPU 型号、主机名、网卡名,也没有任何 IP**——Agent 不采集这些,公开接口当然也不会返回;有测试断言响应里不出现这类字段。实时更新走 SSE 的 `hosts` 主题,历史每个 Agent 每分钟存一个样本(`retention.host_days`,默认 7 天)。
### 2.3.2 节点的展示信息
`GET /api/public/nodes`:看得见的 Agent 和没被吊销的 Probe 的展示信息,`{id, kind, os, os_name, arch, country, isp_key, isp_name}`——系统(`linux` / `windows` / `macos`)、「Debian 12」这样的系统名、架构(`x64` / `arm64`…)、国家代码(`CN`)、运营商类别(`mobile` / `telecom` / `unicom` / `broadnet` / `other`)和名字。**没有 IP 地址、城市、ASN、经纬度**,有测试保证:公开接口的整个响应里不出现 IP 形状的字符串,也没有 `ip`、`city`、`asn` 这些字段。管理员在设置里打开 `site.show_build` 之后,每项还有 `version` 和 `tag`(节点自己上报的程序版本和 tag);关着时这两个字段是 `null`。
`GET /api/public/nodes`:看得见的 Agent 和没被吊销的 Probe 的展示信息,`{id, kind, os, os_name, arch, country, isp_key, isp_name, isp_manual}`——系统(`linux` / `windows` / `macos`)、「Debian 12」这样的系统名、架构(`x64` / `arm64`…)、国家代码(`CN`)、运营商类别(`mobile` / `telecom` / `unicom` / `broadnet` / `other`)和名字。**没有 IP 地址、城市、ASN、经纬度**,有测试保证:公开接口的整个响应里不出现 IP 形状的字符串,也没有 `ip`、`city`、`asn` 这些字段。管理员在设置里打开 `site.show_build` 之后,每项还有 `version` 和 `tag`(节点自己上报的程序版本和 tag);关着时这两个字段是 `null`。
`GET /api/public/about`:`{show_build, backend}`。`show_build` 关着时 `backend` 是 `null`;打开后 `backend` 是 `{version, tag, built_at}`(后端自己的版本、tag、构建时间,不含提交号)。
+2 -2
View File
@@ -6,7 +6,7 @@
- 在**若干 Probe**(家宽等需要观测的出口,可以有多个)与**多台海外 VPS Agent**(10 几台)之间,采集**最原始的逐包、逐事件数据**;哪些 Probe 连哪些 Agent 由面板决定(自动全连,也可以手动选择);
- 由 Backend 的分析层推算:**如果在某条线路上部署 REALITY 类、Hysteria2 类或 Minecraft 服务,体验会怎样**,并对多条线路排序和对比;
- **主机层信息只上报只读的汇总数字**(2026-10 起,由用户确认放开):Agent 读 `/proc` 得到 CPU 占用、内存、根分区、网卡累计流量与瞬时网速、运行时长,不采集 CPU 型号、主机名、网卡名和任何 IP,不采集进程;Probe 不上报主机资源。节点只在连接面板时自报粗粒度的系统、架构和构建信息(版本、tag、提交、构建时间),用于展示和更新;国家和运营商由 Backend 用节点的来源地址查询,节点自己不访问任何外部服务。展示页看不到任何 IP。Agent 和 Probe 仍然是**纯采集器**,不具备 SSH、远程执行、终端、文件读写、自更新等能力:更新由节点宿主机上的更新器完成,节点进程只往数据目录放面板转来的发布清单和更新请求。
- **主机层信息只上报只读的汇总数字**(2026-10 起,由用户确认放开):Agent 和 Probe 读 `/proc` 得到 CPU 占用、内存、根分区、网卡累计流量与瞬时网速、运行时长,不采集 CPU 型号、主机名、网卡名和任何 IP,不采集进程;Probe 的上报可以在 `probe.json` 里关掉(`reporting.host_stats: false`)。展示页用卡片画出每个 Agent 和 Probe 的主机状态,线路单独放在卡片下面的面板里。节点只在连接面板时自报粗粒度的系统、架构和构建信息(版本、tag、提交、构建时间),用于展示和更新;国家和运营商由 Backend 用节点的来源地址查询,节点自己不访问任何外部服务。展示页看不到任何 IP。Agent 和 Probe 仍然是**纯采集器**,不具备 SSH、远程执行、终端、文件读写、自更新等能力:更新由节点宿主机上的更新器完成,节点进程只往数据目录放面板转来的发布清单和更新请求。
## 2. 拓扑
@@ -113,7 +113,7 @@ Agent / Probe 能做的 执行编译在二进制中的 Kind;监听和访问
- **最小权限运行**:非 root 用户;只在需要时授予 `CAP_NET_RAW`(ICMP);默认端口都高于 1024,不需要 `CAP_NET_BIND_SERVICE`,只有在 Agent 本地显式开启 443 时才授予。
- **身份**:节点使用本地生成的 ECDSA P-256 密钥对签名认证(Agent 和 Probe 都自己生成;Probe 有两把独立的密钥,一把连面板、一把连 Agent),Backend 只存公钥,数据库泄露也无法冒充节点。
- **防放大**:未认证的包静默丢弃;回复长度与请求相等;每个流按声明速率限速;使用重放窗口。
- **容器里的主机指标**:容器里的 Agent 通过只读挂载宿主机的 `/proc`、`/sys`、根目录和 `/etc/os-release`(环境变量 `HOST_PROC`、`HOST_SYS`、`HOST_ROOT`)读取宿主机的资源占用和系统名;读不到的项返回空值,不会退回去读容器自己的数据。Probe 只需要挂载 `/etc/os-release`。
- **容器里的主机指标**:容器里的 Agent 通过只读挂载宿主机的 `/proc`、`/sys`、根目录和 `/etc/os-release`(环境变量 `HOST_PROC`、`HOST_SYS`、`HOST_ROOT`)读取宿主机的资源占用和系统名;读不到的项返回空值,不会退回去读容器自己的数据。Probe 的 compose 也一样挂载这几项。
- **自身状态**:节点上报进程内的计数(会话数、包速率、队列、丢弃数);Agent 另外每隔几秒用 `moshiro.host` 上报一份主机资源占用的汇总数字(可以在 `agent.json` 里用 `reporting.host_stats = false` 整个关掉),最新值实时推给展示页,Backend 每分钟存一个样本(默认保留 7 天,`retention.host_days`)。
## 6. 可扩展性目标
+1 -1
View File
@@ -33,7 +33,7 @@ MoShiro 的两条控制链路都建立在 Fleet 之上:
| `moshiro.test.cancel` | B→A | 请求 | `test_id` |
| `moshiro.test.status` | A→B | 通知 | `test_id`、`status`(`running`、`phase_done`、`succeeded`、`failed`、`aborted`)、`phase?`、`error_code?` |
| `moshiro.event` | A→B | 通知 | `kind`(`probe_connected`(`detail` 是 `probe_id`,`probe` 里带版本、远端地址和连接时间)、`probe_disconnected`、`endpoint_changed`、`session_rejected`、`clock_step`、`gap`、`cpu_saturated`(节点进程 CPU 饱和,可能影响测量,由 Probe 或 Agent 上报))、`at_utc`、`detail` |
| `moshiro.host` | A→B | 通知 | `HostSnapshot`:主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP),每 `host_interval_s` 秒一次;`host_stats` 为 false 时不发,见 [enrollment.md](../security/enrollment.md) |
| `moshiro.host` | A、P→B | 通知 | `HostSnapshot`:主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP),每 `host_interval_s` 秒一次;`host_stats` 为 false 时不发,见 [enrollment.md](../security/enrollment.md) |
心跳的附加字段里有 `probes[]`:Agent 当前连着的每个 Probe(`id`、`version`、`remote`、`since_utc_ms`),每次都是完整快照,Backend 靠它纠正错过的连接事件。点对点握手的认证消息里可以带 Probe 的 `version`(只用于展示)。块头里的 `probe_id` 以 Agent 认证过的会话为准,Probe 自报的值会被覆盖。
+1 -1
View File
@@ -302,7 +302,7 @@ Agent 的 Compose 模板已经包含以下只读挂载和环境变量,systemd
磁盘指标是根文件系统容量,不是所有硬盘合计,也不采集磁盘 I/O。链路速率是参与流量统计的接口速率合计,单位 Mbit/s,不是互联网测速结果;任一接口不支持读取速率时显示空值。接口仍按名称排除回环、容器、网桥和部分隧道,复杂 bonding/VLAN 配置可能存在重复计数。主机名、硬件型号、MAC/IP 不作为资源指标上报。
Probe 保持现有功能,只上报系统、架构与节点状态,不上报 CPU、内存、磁盘或网卡指标。因此 Probe 的 Compose 模板只需要配置目录和 `/etc/os-release` 挂载;从 Agent systemd 示例改为 Probe 时,去掉 `/proc`、`/sys`、`/` 挂载及 `HOST_*` 环境变量。
Probe 也上报同样的汇总数字(`probe.json` 的 `reporting.host_stats` 默认开,设为 `false` 就一个字也不上报,同时可以去掉 `/proc`、`/sys`、`/` 这三个挂载),所以 Probe 的 compose 和 Agent 一样挂载它们并设置 `HOST_*` 环境变量。Docker Desktop(macOS、Windows)上读到的是 Docker 的虚拟机,不是宿主系统本身;Windows 上直接运行的 Probe 和 Agent 用系统调用读 CPU、内存和物理网卡的流量(不读网卡名和地址);macOS 目前只有磁盘和运行时长。
## 容器节点的更新(Agent、Probe)
+2 -2
View File
@@ -100,10 +100,10 @@ Probe 启动
## Agent 的本地配置:主机状态上报
`agent.json` 的 `reporting` 段(面板无法修改):
`agent.json` 和 `probe.json` 的 `reporting` 段(面板无法修改):
```json
{ "reporting": { "host_stats": true, "host_interval_s": 2 } }
```
`host_stats` 为 true(默认)时,Agent 每隔 `host_interval_s` 秒用 `moshiro.host` 上报一份主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP);设为 false 就一个字也不上报。
`host_stats` 为 true(默认)时,Agent 和 Probe 每隔 `host_interval_s` 秒用 `moshiro.host` 上报一份主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP);设为 false 就一个字也不上报。