监测单元和预案重写成"分层"版(来源改为本地整份文件)

== 为什么重写 ==

certbot 签证书时加了 http -> https 的 301,而监测单元原来判断
"curl 拿到 200 才算健康"、且 curl **默认不跟跳转** -> 拿到 301
-> 判成"网站挂了" -> 又要启动预案 -> 重启中转 -> 再查还是 301。
这是**第二次**踩同一类坑了(上一次是改监听地址忘了改探测地址)。

共同教训:**改了入口的行为,必须回头看所有探测入口的地方。**

== 新设计:分两层探测 ==

    PRIMARY   https://yk.xxmxxs.top/v1/health     用户实际走的路
    FALLBACK  http://127.0.0.1:13245/v1/health    中转本身

两个都查才能分清哪一层坏了,进而选对抢救动作:

    PRIMARY 挂 + FALLBACK 好  -> edge 层(CF / DNS / nginx)
   两个都挂                  -> core 层(中转服务本身)

预案据此走不同的阶梯:

    edge: 重载 nginx -> 重启 nginx -> 查 443 与证书
    core: 重启中转 -> 强杀重拉 -> 中转+nginx 都重启

不区分层次的话只能瞎重启,而 edge 层的问题重启中转一万次也没用。

== 做法上的改进:不再远端打补丁 ==

前几轮一直是"SSH 过去用嵌套 heredoc 现场改 monitor.sh",
连续踩三次:PowerShell 在本机求值 \、引号被吃、
脚本里的 %{http_code} 和 Python 的 %% 格式化打架。

现在改成:relay/monitor-lightsail.sh 和 relay/rescue-lightsail.sh
是**唯一事实来源**,本地编辑 -> 整份上传 -> 重装,
改了什么一目了然,也能进 git。

== 顺带 ==

因为 Lightsail 防火墙还没放行 443,PRIMARY 一直是 000,
监测会把 fails 一直加上去、白生成抢救报告。
所以暂时把 monitor.timer 停掉,等 443 开了再启用
(脚本 _build/pause_monitor.py,恢复是一条 systemctl start)。
This commit is contained in:
xmz7891
2026-10-08 22:53:44 +08:00
parent e63b5f08d7
commit 47e08af151
6 changed files with 780 additions and 106 deletions
+100
View File
@@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
r'''暂停监测单元,等 443 端口开好再启用。
== 为什么要暂停 ==
新架构:用户 -> Cloudflare -> nginx(443) -> 127.0.0.1:13245
证书签好了、nginx 也配了 443,但 **Lightsail 防火墙还没放行 443**,
所以外部访问 https://yk.xxmxxs.top 是 522。
监测查的是"用户实际走的路",于是一直判失败、fails 一直涨。
涨到 3 就启动紧急预案 —— 而预案能做的都解决不了"防火墙没开",
结果只会白折腾服务 + 每 10 分钟塞一份没用的报告进后台,
把以后真正出事的现场淹掉。
所以:**系统还没部署完,先别开监测**。443 通了再启用。
== 暂停不是关掉 ==
只 stop,配置和脚本都留着,一条命令就能恢复:
sudo systemctl start ykxmz-monitor.timer
== 写这个文件的原因 ==
之前用 `python -c @"..."@` 写过一次,里面 `\$(...)` 转义错了,
bash 报 "syntax error near unexpected token `('"。
教训一致:**远端命令超过一行就写文件**,别在 -c 里跟转义缠斗。
'''
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "_build"))
from lssh import run # noqa: E402
RELAY_DIR = "/opt/ykxmz-relay"
def main() -> int:
print("=" * 62)
print(" 暂停监测单元(等 443 开好再启用)")
print("=" * 62)
print()
print(" ── 1. 停掉监测定时器 ──")
# 分几条简单命令跑,不做复杂嵌套 —— 免得又踩转义
run("sudo systemctl stop ykxmz-monitor.timer", timeout=120, quiet=True)
out = run("systemctl is-active ykxmz-monitor.timer", timeout=60,
quiet=True)
print(" monitor.timer = " + out[1].strip())
print()
print(" ── 2. 失败计数清零 ──")
run("printf 'fails=0\\nlast_rescue=0\\nlast_code=000\\n"
"local_code=200\\nlayer=edge\\n' > %s/monitor_state.txt"
% RELAY_DIR, timeout=60, quiet=True)
out = run("cat %s/monitor_state.txt" % RELAY_DIR, timeout=60, quiet=True)
for ln in out[1].strip().splitlines():
print(" " + ln)
print()
print(" ── 3. 清掉演练产生的报告 ──")
before = run("ls -1 %s/rescue_reports 2>/dev/null | wc -l" % RELAY_DIR,
timeout=60, quiet=True)
print(" 清之前: %s 份" % before[1].strip())
run("rm -f %s/rescue_reports/*.txt" % RELAY_DIR, timeout=60, quiet=True)
after = run("ls -1 %s/rescue_reports 2>/dev/null | wc -l" % RELAY_DIR,
timeout=60, quiet=True)
print(" 清之后: %s 份" % after[1].strip())
print()
print(" ── 4. 当前状态 ──")
st = run("systemctl is-active ykxmz-relay nginx ykxmz-monitor.timer "
"certbot.timer", timeout=60, quiet=True)
names = ["ykxmz-relay", "nginx", "ykxmz-monitor.timer", "certbot.timer"]
for i, ln in enumerate(st[1].strip().splitlines()):
if i < len(names):
print(" %-24s %s" % (names[i], ln))
print()
code1 = run("curl -s -o /dev/null -w '%{http_code}' "
"http://127.0.0.1:13245/v1/health", timeout=60, quiet=True)
print(" %-24s %s" % ("中转本机", code1[1].strip()))
code2 = run("curl -sk -o /dev/null -w '%{http_code}' --resolve "
"yk.xxmxxs.top:443:127.0.0.1 "
"https://yk.xxmxxs.top/v1/health", timeout=60, quiet=True)
print(" %-24s %s" % ("nginx 443 本机", code2[1].strip()))
print()
print(" 443 开好之后恢复监测:")
print(" sudo systemctl start ykxmz-monitor.timer")
print(" (或者告诉我,我来开 + 全链路验证)")
return 0
if __name__ == "__main__":
sys.exit(main())