跳转至

阶段二十一:网络可达性 UDP 探测与 Globalping 配额整改

阶段状态:进行中

计划状态:已完成

当前工作包:P21-10 阶段归档与 P22 启动准备(等待用户指令)

📌 结论摘要

网络态势里的“代理出口可用性”已改为“节点网络 UDP 直连可达性”。R4 订阅组不再承担 AgentMeshOS 生产代理,常规监测不再读取订阅、不再建立 Hysteria2 会话,而由 101、102 分别对在线节点做 Tailnet 路径探测:任一来源拿到直连就判绿色,两个来源都不是直连才判红色,详情逐源显示直连、Peer Relay、DERP 及实际中继节点。

Globalping 保持自动运行,但把单轮探针降到 5,Edge 改为 10 分钟、五台节点改为每小时全量检查,并把自动、手动接口、主机与入口刷新统一记入额度台账。360T7 的直连列表原先并未包含五台节点公网 IP,本轮已补齐并核验运行时集合命中与真实流量计数。

P21 另挂一个并行子计划:节点网络路径视图与双节点诊断计划。它把 Edge、DERP、Peer Relay、公网 IP、TCP、UDP、Tailnet 隧道和两节点诊断整理成可读的路径视图。用户已于 2026-11-01 确认执行,PV-0 至 PV-7 已完成代码、发布、生产回读、按节点汇总与控制面韧性评估。

🗂️ 目录

🧾 计划状态

项目 状态 说明
阶段状态 进行中 P21-0 至 P21-9 全部闭环;24 小时双源观察与 360T7 整机重启复验均已完成,仅剩阶段归档
计划状态 已完成 网络态势、双源探针、每小时 Globalping 全量、告警链、生产回读与重启复验全部完成
当前工作包 P21-10 阶段归档与 P22 启动准备(等待用户指令) P21 实施工作已全部结束;阶段滚动需用户确认 P22 启动
与 P20 的关系 P20 已临时收口 OfficeSummer 离线复验保留为可重启项

🎯 目标、成果与验收契约

编号 验收要求 本轮结果
A1 101、102 独立输出每个节点的直连或非直连结果与实际路线 已达成,两份快照各覆盖 9 个在线节点
A2 任一来源直连则绿色,全部非直连才红色 已达成,API 汇总逻辑与单测覆盖
A3 页面不以内部编号作为主文案,DERP 显示实际节点名称 已达成,详情显示“DERP,经 MM”等
A4 新探针不读 R4 订阅、不建代理会话 已达成,代码路径不含订阅与代理调用
A5 双源探测有明确资源与并发上限 已达成,单来源并发 2、每 5 分钟一轮、锁文件互斥
A6 自动与手动 Globalping 调用全部进入统一台账 已达成,单次实测写入 1 条 5 tests 记录
A7 正常基线不超过约 40 tests/小时 已达到设计口径:常规 8 tests/次、Edge 3 tests/次
A8 五台节点 IP 在保存配置与运行时直连集合一致 已达成,持久文件与运行时集合双向核验
A9 R4 退出自动监测后仍保留手动诊断 手动入口保留,自动 timer 停用留待用户确认
A10 文档与代码门禁全部通过 本轮执行并在收尾复核

🧱 技术栈与架构选型

层 选型 理由
探测面 101、102 上的 systemd timer + tailscale ping 复用现有 Tailnet 数据面,零新增依赖
数据面 原子写 JSON 快照 + 既有节点通道发布到 RR 与现有快照消费方式一致,便于回读与回退
汇总面 API Gateway 只读投影 逐源保留原始结果,避免“合并来源”丢失证据
展示面 Console 现有网络态势模块 保持页面结构与交互习惯,减少改造面
配额面 Globalping 调用统一 JSONL 台账 自动与手动同账,可按用途拆分核对

不引入 Nomad 新 Job、数据库或独立调度服务;探测只读节点登记与 Tailscale 状态。

🧩 分布式底座接入声明

约束 落实方式
单用户、无审批前置 探针由 timer 直接运行,无批准单或租约
节点登记权威 目标节点来自 /usr/local/lib/agentmeshos/node-registry.json
控制面边界 RR 仍是唯一汇总与展示上游,101、102 只产出本机快照
凭据边界 探针不读取订阅、不接触代理凭据
失败关闭 快照缺失或过期时页面不沿用旧绿色结论

📊 执行记录与证据

2026-11-02 d02/DD 公网 IP 更新与回测

用户提供并确认 d02、DD 更换公网 IPv4 后,本次先通过公网 SSH 回读两台主机的 hostname、Tailnet 地址、物理网卡地址和默认路由,确认新地址确实落在对应 VPS;随后更新 AliDNS 权威 A 记录、101/RR 的公网 SSH 入口和 DD 异机副本脚本默认地址。DNS 计划 dry-run 只包含两条 A 记录更新,apply 后权威 DNS dns17.hichina.com、dns18.hichina.com 和公共递归解析均返回新地址。

节点 新地址归属 Globalping ICMP Globalping TCP 443 HTTPS 健康 公网 SSH 101 Tailnet UDP 102 Tailnet UDP
d02 主机名 d02-dedirock,物理网卡已回读新地址 17/20 成功,15% 丢包 12/12 成功 https://d02.yohan.fun/__edge/health 返回 200 返回 d02-dedirock 与正确 Tailnet 地址 直连,约 177 ms 直连,约 184 ms
DD 主机名 dedirock-171060537,物理网卡已回读新地址 23/25 成功,8% 丢包 14/15 成功 https://dd.yohan.fun/__edge/health 返回 200 返回 dedirock-171060537 与正确 Tailnet 地址 直连,约 212 ms 直连,约 211 ms

d02 首次回测时发现 Nginx 因启动阶段无法解析 cloud-origin.yohan.fun 而处于 failed;权威 DNS 和 d02 本机解析恢复后,执行 nginx -t、受控重启并确认 443 监听,最终 HTTPS 健康回读通过。该故障不是新 IP 归属错误,而是地址切换时暴露的 Nginx 启动依赖问题;未写入 /etc/hosts,没有用硬编码 IP 绕过 DNS。

2026-11-02 网络态势节点红色聚合根因

d02、DD 新 IP 回测后,网络态势实时分布图仍将节点标红。回读 RR 的同一轮拓扑采集证据显示:两台节点的 Tailnet 直连、公网 SSH 和各自 Edge 健康链路均为 healthy,但 DERP region 901/902 检查为 derp_connection_failed;拓扑采集器原先把 DERP 检查结果加入节点总状态,因此可选的 DERP 故障污染了节点主状态。DD 另外存在独立的 public-cloud 业务链路失败,但该链路不应改变 DD 主机状态。

修复口径:节点主状态只聚合核心管理路径(Tailnet 与必要公网 SSH);DERP、Peer Relay 和业务网站继续作为独立检查/链路显示。这样不会硬编码绿色,也不会丢失 DERP 或 Cloudreve 的真实故障,只避免“单项能力失败 = 整台主机失败”的错误聚合。该修复补充了 operational_node_status 回归测试;后续发布后必须回读 d02、DD、dog 的节点颜色、独立 DERP/业务链路状态和实时检查时间。

2026-11-02 RR 中国方向公网 TCP 多端口复核

历史记录显示,2026-11-01 曾从中国方向观测到 RR 公网 TCP 443、47522、80、8888、32118、39120 同时失败;但 Memory 也保留了 2026-10-30 同一路径 443 与 47522 均 6/6 open 的反例。因此该问题应定义为“按时间和观测来源变化的选择性/间歇性公网 TCP 故障”,不能把历史窗口固化成 RR 永久 TCP 封禁。

本次从 Globalping 中国方向对 RR 当前公网地址做了多端口实测:

TCP 端口 用途 结果
80 公网 HTTP/重定向入口 9/9 成功
443 公网 HTTPS 入口 8/9 成功,约 11% 丢包
47522 RR 真实 SSH 运维入口 9/9 成功

结论:当前 RR 的公网 TCP 通路已恢复可用,但 443 存在轻微丢包;这不能推翻历史故障,只说明历史故障不是永久状态。后续公网入口判断必须同时记录观测来源、端口、时间和测量 ID,不再用单次 443 结果代表“所有 TCP 正常”或“所有 TCP 都被封”。

2026-11-02 23:15 多轮复核(消除单轮噪声)

对同一地址连续复测,确认上一轮 11% 属于单次探针噪声,不是持续性故障:

轮次 端口 结果 丢包 观测时间
第 1 轮 443 4/4 成功 0% 2026-11-02 23:15 CST
第 2 轮 443 4/4 成功 0% 2026-11-02 23:15 CST
第 3 轮 443 4/4 成功 0% 2026-11-02 23:15 CST
交叉验证 80 4/4 成功 0% 2026-11-02 23:15 CST
交叉验证 47522(SSH) 4/4 成功 0% 2026-11-02 23:15 CST

结论:RR 公网 443 当前连续三轮全通;历史窗口内的故障仍按“时间与来源相关的间歇性阻断”记录,不用本次结果覆盖历史,也不用历史结果否定当前。

2026-11-02 Cloudreve 公网链路超时根因与修复

public-cloud 长时间显示超时,但 DD 本机 Cloudreve 容器正常、端口 5212 返回 200。根因不在 Cloudreve,而在 MM 的 Edge Nginx 回源写法:

层 证据 说明
配置 proxy_pass http://cloud-origin.yohan.fun:5212; 直接写域名 Nginx 只在加载配置时解析一次,之后固定使用旧地址
进程 回源 Nginx 主进程启动于 2026-10-27 06:44 DD 换 IP 后进程未重载,仍连接旧地址
DNS MM 当前解析 cloud-origin.yohan.fun 已指向 DD 新地址 名称解析本身正确
直连 MM 直连 DD 新地址 5212 返回 200,耗时 56 ms 网络与业务均正常
现象 MM 本机访问 cloud.yohan.fun 15 秒 0 字节 与“旧 upstream 握手无响应”一致

修复:Edge Nginx 模板改为 resolver + 变量写法,域名在每次建连时重新解析,TTL 15 秒,仅 IPv4。契约测试新增负向回归,禁止再生成静态域名 proxy_pass。部署到 MM 后的实测:

检查项 结果
MM 本机 https://cloud.yohan.fun/status.php 200,0.22 秒
公网 https://cloud.yohan.fun/status.php 200,4.4 秒
公网 https://www.threedogs.vip/ 200(修复前 504)
拓扑快照 public-cloud 链路 healthy

该问题与 dog 历史故障同源:域名回源被静态解析后,换 IP 不会自动生效。后续所有 Edge 候选机上线、换 IP 或重建站点后,必须确认回源使用动态解析,不能靠重启 Nginx 或写 hosts 绕过。

2026-11-02 DERP 901 恢复确认

DERP 901 的失败不是 derper 进程故障,而是资格控制器要求“连续两次健康观测”才重新准入。补做一次 DD 的正式探测后,recovery_count 由 1 升到 2,控制器自动把 region 901 写回 DERP Map 并重启 Headscale;RR 与 101 两端 tailscale debug derp 901 均成功建立 DERP 连接,902 同样正常。整个过程没有手改 Map 文件。

环节 实测结果
101 探针 9 个在线节点:6 直连、3 DERP、0 无响应
102 探针 9 个在线节点:6 直连、3 DERP、0 无响应
双源一致项 RR、dog、Home、NAS、Summer 均为直连
双源差异项 MM、d02、DD 两个来源都只能走 DERP
快照落地 RR 同时存在 tailnet-udp-v1.json 与 tailnet-udp-102-v1.json
Globalping 台账 单次自动 Edge 检查写入 1 条请求、5 tests,坏行 0
360T7 持久配置 direct_ip 21 条、格式异常 0,五台节点 IP 均在列
360T7 运行时 五台 IP 在 inet passwall psw_white_static 全部命中
直连真实流量 直连返回规则已有累计包计数,说明分流规则实际生效
退役探针告警 旧 SearXNG stale-check 告警已由正式恢复事件关闭;当前告警中心未处理数量为 0
告警中心历史展示 后端按告警数据库全量统计未读/处置状态,页面区分当前待处理与历史未读,保留最近 100 条展示
Tailnet unit 101、102 探针服务均以 ConditionFileIsExecutable=/usr/bin/tailscale 重新部署,unit verify 与真实运行通过

360T7 直连规则返工与复验

这次返工包含两个错误,必须一起纠正:一是把错误的配置对象当成“直连列表”,二是第一次追加时原文件末尾没有换行,导致两条 IP 粘连、nft 规则语法错误、PassWall 重载失败。第二点已当场回滚重写,下面是重做后的四层证据。

层次 证据 结论
LuCI 源码 client/rule_list.lua 用 /usr/share/passwall/rules/ 拼路径,direct_list 页读写 direct_ip 文件 “直连列表”就是该文件,不是 UCI 对象
持久文件 direct_ip 共 21 条,五台节点公网 IP 逐条命中,位于 overlay/ubifs 持久分区 规则来源可持久化
运行时集合 重启 PassWall 重建后,五台 IP 在 inet passwall psw_white_static 逐条命中 文件内容进入运行时
真实流量 对 MM 执行 3 次 tailscale ping,直连返回规则计数合计 +14 包 节点流量确实走直连而不是 PassWall

曾用过的错误对象:

曾用对象 实际含义 为什么不能用
psw_vps PassWall 自身的节点或负载均衡集合 与用户维护的直连列表无关
passwall.Direct.ip_list 分流模式(shunt)的分流规则 不是 LuCI“直连列表”页保存的对象
inet fw4 里的 psw_white_static 表名查错 真实集合在 inet passwall 表

🔍 根因与防护

本轮最主要的方法性错误不是命令本身,而是取证对象没有先建立映射:先把 psw_vps 当直连列表,再把 passwall.Direct.ip_list 当直连列表,还用 inet fw4 去查只存在于 inet passwall 的集合,于是连续得出“未命中”的错误结论。

防护不变量:

  1. 判断任何集合成员前,先确认界面名称对应的持久对象与运行时对象。
  2. 区间集合禁止用字符串包含代替语义判断。
  3. 任何“未命中/不存在”结论至少需要保存配置、运行时状态和一次反例检查。
  4. 用户指出结论反常时,旧结论立即降级为未验证,必须改变取证路径。
  5. 面向用户先给业务含义和影响,内部字段与编号只作为二级证据。

🛠️ 工作包状态

工作包 状态 说明
P21-0 规则与备份 完成 全局规则更新、Memory 回读、两条防复发机制入库
P21-1 探测契约 完成 快照结构、路线枚举、二态规则与单测
P21-2 双源探测 完成 101、102 均产出可复现快照
P21-3 API 与 Console 完成 逐源分行、DERP 名称、台账展示
P21-4 Globalping 配额与台账 完成 5 probes、10 分钟 Edge、五台节点每小时全量、统一台账;设计预测约 80–100 tests/小时
P21-5 360T7 直连闭环 完成 用户于 2026-11-02 重启路由器。重启后只读回读:/usr/share/passwall/rules/direct_ip 21 条,运行时 inet passwall psw_white_static 五台节点 IP 用 nft get element 逐条判定全部命中(该集合 flags interval,不能用字符串 grep 判断成员)
P21-6 影子观察 完成 2026-11-01 11:34 至 2026-11-02 11:34 连续运行;101/102 timer active,快照持续更新,无 stale、服务失败或资源堆积。11:45 101 视角 dog 瞬时超时,11:48 Tailnet 即时复核恢复
P21-7 R4 退役 完成 101、102 的 R4 探针 timer 与 RR 的计划器、告警 timer 已停用并撤销开机自启;手动诊断入口保留
P21-8 文档与发布 完成 文档、代码、退役探针告警修复、Tailnet unit 条件修复、提交推送、生产回读和运行态复验完成
P21-9 告警中心历史展示治理 完成 告警统计改为数据库全量,页面明确区分当前待处理与历史未读;生产容器已运行提交 7e040d20

🔁 回退方案

层 回退动作
探测 停用 agentmeshos-tailnet-udp-probe*.timer,恢复 R4 timer
展示 回退 Console 与 API Gateway 上一完整镜像
配额 恢复上一版 collector 单元与参数
360T7 用 temp/p21-360t7/direct_ip.bak-* 覆盖并重启 PassWall

任何回退都保留 last-known-good 快照,不用旧绿色结果冒充当前可用。

⚠️ 未决项

未决项 建议 状态
R4 自动探针停用 已完成停用与开机自启撤销,页面不依赖 R4 结果 完成
24 小时影子观察 已完成:2026-11-01 11:34 至 2026-11-02 11:34 连续运行;101/102 timer active,快照持续更新,无 stale、服务失败或资源堆积 已关闭;短时路径抖动按节点网络动态变化记录,不作为探针停摆
360T7 整机重启复验 用户已重启;重启后持久文件 21 条、运行时区间集合五台 IP 全部命中 完成