小型网络系列:脚本、Scheduler 和可恢复性

系列导航

  1. 小型网络系列:开篇 - 300-500 Devices 的网络为什么也会复杂
  2. 小型网络系列:RouterOS 和 Switch 的职责边界
  3. 小型网络系列:LAG、VLAN 和 Macvlan 为什么会一起出现
  4. 小型网络系列:PCC 分流逻辑和故障行为
  5. 小型网络系列:WireGuard 为什么是日常路径
  6. 小型网络系列:脚本、Scheduler 和可恢复性

背景

前面几篇讲的是网络形状:RouterOS 和 Switch 怎么分工,LAG / VLAN / Macvlan 怎么承载 Multi-WAN,PCC 怎么分流,WireGuard 怎么承载日常站点路径。

最后一篇讲一个更运维的问题:这些状态不能只靠手工记忆。

小型网络最容易出现的不是“大型系统崩溃”,而是一些小操作慢慢失控:

  • PCC 模式切错几条规则
  • WireGuard Peer 偶发 Down 了没人注意
  • PPPoE 线路长期运行后状态不稳定
  • 黑名单更新靠手工跑
  • RouterOS 上有哪些脚本、哪些 Scheduler,过几个月没人说得清
  • DC-101 RouterOS 版本更老,部署能力和新版本不完全一样

所以我现在更倾向于把 RouterOS 的脚本和 Scheduler 做成 repo-backed state。

Manifest 是 Desired State

RouterOS 这边的核心不是“把脚本复制过去”,而是 Manifest。

每个 host 有自己的 rsc/<host>/manifest.yml,里面描述:

  • 应该存在的 System Scripts
  • 这些脚本对应哪些文件
  • Scheduler 应该怎样运行
  • 哪些旧文件或旧脚本应该删除
  • host 的特殊部署差异

Office-JTOffice-SQDC-101 的状态不是一样的。

Site Manifest 重点
Office-JT PCC 模式脚本、WireGuard Watchdog、WireGuard Trigger、print-per-ip-countsupdate-blackip
Office-SQ WireGuard Watchdog、update-blackip、PPPoE Redial、Watchdog Scheduler
DC-101 老 RouterOS 限制更多,保留更简单的 update-blackip 部署方式

这让“当前应该有哪些脚本”变成 repo 里的可审计事实,而不是 RouterOS 终端历史。

部署路径

RouterOS 维护现在走 routerosctl.py,不是旧的“复制到某台 PVE 再手工导入”。

常用操作大概是:

1
2
3
make -C router/ros audit HOST=<office-jt>
make -C router/ros sync HOST=<office-jt>
make -C router/ros install HOST=<office-jt>

这里文章里继续用内部 host label 表达,不展开真实连接方式、密码环境变量或公网 Endpoint。

audit 用来检查 Live State 和 Manifest 是否一致。sync 上传非 secret runtime files。install 会做更完整的安装流程,并留下 pre/post audit evidence。

这个设计的价值在于:我可以知道一次变更之前和之后 RouterOS 长什么样,而不是只知道“我刚刚好像导入了一个脚本”。

PCC 脚本的可恢复边界

PCC 脚本是 Office-JT 里最容易出错的一类脚本。

它们的可恢复边界来自前一篇讲的命名:

  • pcc-mark-* 是 Bucket Layer
  • pcc-routing-* 是 Routing Layer
  • 模式切换脚本只禁用 ^pcc-mark-
  • 模式切换脚本只启用自己的 ^pcc-mark-N/
  • 不动 pcc-routing-*

这意味着 PCC 模式切换可以反复执行。

如果当前想从 1:1:1 切到 0:1:1,脚本不会假设现在的状态干净,而是先把所有 Bucket Rules 收敛,再启用目标组。出问题时,也可以换回另一组模式,而不是手工逐条找哪几条 Mangle Rule 开着。

这不等于完全自动化,但它比手工点规则可靠得多。

WireGuard Watchdog 的边界

WireGuard 是日常路径,但 Watchdog 不应该做太多事。

Office-JTOffice-SQ 的 Watchdog 思路都很克制:

sequenceDiagram
  participant Netwatch as RouterOS Netwatch
  participant Scheduler as Scheduler
  participant Script as wireguard-watchdog
  participant Peer as WireGuard Peer

  Scheduler->>Script: Run Every 1m
  Script->>Netwatch: Read Peer Status
  alt Peer Down
    Script->>Peer: Disable Peer
    Script->>Peer: Wait 5s
    Script->>Peer: Enable Peer
  else Peer Up
    Script-->>Scheduler: No Change
  end
sequenceDiagram
  participant Netwatch as RouterOS Netwatch
  participant Scheduler as Scheduler
  participant Script as wireguard-watchdog
  participant Peer as WireGuard Peer

  Scheduler->>Script: Run Every 1m
  Script->>Netwatch: Read Peer Status
  alt Peer Down
    Script->>Peer: Disable Peer
    Script->>Peer: Wait 5s
    Script->>Peer: Enable Peer
  else Peer Up
    Script-->>Scheduler: No Change
  end
sequenceDiagram
  participant Netwatch as RouterOS Netwatch
  participant Scheduler as Scheduler
  participant Script as wireguard-watchdog
  participant Peer as WireGuard Peer

  Scheduler->>Script: Run Every 1m
  Script->>Netwatch: Read Peer Status
  alt Peer Down
    Script->>Peer: Disable Peer
    Script->>Peer: Wait 5s
    Script->>Peer: Enable Peer
  else Peer Up
    Script-->>Scheduler: No Change
  end

它只做一件事:Peer Down 时重启 Peer。

它不会重写密钥,不会改 Endpoint,不会改 Route,也不会把办公室日常路径切到 NetBird 或 ZeroTier。

这个边界很重要。自动化越小,误伤范围越小。

Scheduler 是运行约束

Manifest 里除了脚本,还有 Scheduler。

Office-JT 里有几个典型 Scheduler:

  • pppoe1-redial:周期性重启 PPPoE 接口
  • watchdog-wg-peer-office-sq:定时执行 WireGuard Watchdog
  • update-blackip:定时更新黑名单

Office-SQ 也有类似的 Watchdog 和 PPPoE Redial。

这些 Scheduler 不是什么高大上的编排系统,它们只是把“我平时会手工做的维护动作”变成固定节奏。

这样做的好处是:

  • 频率明确
  • 目标脚本明确
  • 是否启用可以在 Manifest 里看到
  • 下次换人或过几个月回来排障,不用猜这件事是不是靠某个终端历史在跑

Office-JT 里还有一个很朴素的脚本:统计绑定 DHCP Lease 的客户端,在连接表里找连接数超过阈值的地址。

它不是监控系统,也不负责自动限速。

但它在排障时有用:

  • 某台机器连接数异常高,会影响 PCC 体感
  • 下载器、同步工具、浏览器异常 Tab 都可能把连接表撑大
  • 先看到高连接客户端,再决定要不要调 PCC 或做策略

这也符合这套网络的风格:不追求一次性上完整企业监控和准入治理,但把常见排障动作固化成可以重复执行的小工具。

DC-101 为什么特殊

DC-101 是 RouterOS-based L3 Switching,但它的 RouterOS 版本和能力边界更老。

在部署流程里,它和 Office-JT / Office-SQ 不完全一样:

  • 不支持同样的 import dry-run 流程
  • 不接受较新的 repo-style remote scripts/ directory 方式
  • Manifest 里需要用更简单的 remote file 形态表达

这类差异要写在稳定文档里,而不是靠人记。

否则自动化最容易在“看起来都是 RouterOS”的地方踩坑。版本不同、设备类型不同,部署能力就可能不同。

最后的结论

这个小型网络不是靠一个巨大的自动化系统维护的。

它更像几层简单机制叠起来:

  • Manifest 描述 RouterOS Desired State
  • routerosctl.py 负责 Audit / Sync / Install
  • PCC 脚本只切 Bucket Layer
  • WireGuard Watchdog 只重启 Peer
  • Scheduler 固化周期性维护动作
  • 小脚本辅助排障,不假装自己是完整监控平台

这套做法很朴素,但适合当前规模。

它的目标不是把网络变成无人值守系统,而是让每次变更和每个自动动作都有边界、有证据、有回退方向。对 300-500 Devices 的小型网络来说,这比堆一套复杂控制平台更现实。