跳转至

主机重启恢复设计

目标

任意单节点重启不得使其余节点永久离线;主节点恢复后,Headscale、Tailnet、Nomad、系统云盘和控制台应自动恢复,无需人工改 hosts、临时反代或手工启动容器。

根因

原路径让 MM 的 mesh.yohan.fun 经 Tailnet 回源主节点 100.64.0.1:39200。主节点重启时 Tailnet 地址尚未恢复,MM 无法回源 Headscale;其他节点又必须访问 MM 上的 mesh.yohan.fun 才能恢复 Tailnet,构成控制面循环依赖。MM 的 BaoTa Nginx 也未作为独立 systemd 单元启用,重启后可能不启动。

选型

方案 可维护性 部署复杂度 性能 学习成本 扩展性 结论
仅给现有服务增加 Tailnet 等待 无影响 不能打破回源循环,不采用
新建第二套 Headscale 增加同步与故障面 会产生控制面状态分叉,不采用
MM 直连主节点 bootstrap 加 Tailnet 就绪加载器 仅启动期一条控制面回源 采用
失败后无限重启 Nginx、Nomad 或容器 增加无效重试和日志噪声 不采用

运行契约

  1. MM 是唯一公网入口,BaoTa Nginx 使用独立 systemd 单元自启动。
  2. MM 对 mesh.yohan.fun 在启动期经主节点公网 bootstrap 回源;该 bootstrap 仅允许 MM 公网 IP,只代理 Headscale 协议和经 A-Auth 管理员校验的 Headplane /admin,不暴露 Nomad、Docker 或业务端口。
  3. 主节点 BaoTa Nginx 先运行 Tailnet listener 清理器、再做配置校验并启动 bootstrap;100.64.0.1 缺失时必须移除私有 39200 配置,不能让残留监听器阻断公网 bootstrap。
  4. 主节点若已保存的 Tailnet 状态明确为 NeedsLoginNoState,才由 root-only 恢复服务向本机 Headscale 申请不可复用、5 分钟有效的一次性注册键;恢复服务每次启动都强制执行 tailscale set --accept-dns=false --accept-routes=false,注册显式保留既有 Exit Node 宣告并使用 --accept-dns=false,系统级应用、主机默认路由和主机 DNS 不得由 Tailnet 接管。密钥仅存在进程内存,不写入项目、日志或长期配置。其他状态不得自动重注册,保留给故障调查。
  5. Tailnet 地址 100.64.0.1 出现后,加载私有 39200 回源配置并 reload,然后启动 Nomad 和 Runtime。Runtime 恢复时必须检查 Docker 专用网络附着;若此前因 Tailnet 端口绑定失败而丢失网络端点,重新附着固定私网地址后再验证 loopback 健康端点。主节点与 101/103 的 Nomad 均只等待 Tailnet IPv4 出现后启动;不等待已退役的数据库、文件系统或预拉取镜像。Cloudreve 位于 dd,按其自身容器健康恢复,不作为 Worker 启动前置条件。

验收

受控重启时每台机器逐台执行,确认 Tailnet 注册、SSH、Docker 健康、Nomad、mesh.yohan.fun、Console、系统云盘和告警恢复;不得同时重启多个节点。主节点演练还必须覆盖“Tailnet listener 配置残留但地址未出现”的 bootstrap 降级路径、NeedsLogin/NoState 的一次性恢复路径,以及重注册后 accept-dns=falseaccept-routes=false、宿主公网默认路由和宿主公网 DNS 仍有效。

已知恢复入口

节点的 root SSH 公钥仍限制为主节点 Tailnet 来源。该限制不应因演练而绕过;若某个 Worker 已启动但 Tailnet 尚未恢复,需在该 Worker 的本机终端执行 systemctl restart tailscaled,然后由主节点继续验收。不得为了这类单机故障而放开密码登录或移除来源限制。