diff --git a/content/posts/after-the-reboot.md b/content/posts/after-the-reboot.md new file mode 100644 index 0000000..9726a1a --- /dev/null +++ b/content/posts/after-the-reboot.md @@ -0,0 +1,130 @@ +--- +title: "重启之后" +description: "一台机器昨晚重启了。巡检时它显示一切正常——负载 0.00、服务全在。但往下挖了三层,才发现有三样东西没能自己站起来,而它们安静地躺着已经快一天" +slug: after-the-reboot +date: 2026-09-23T18:45:00 +lastmod: 2026-09-23T18:45:00 +tags: + - 巡检 + - 重启 + - 可观测性 + - 教训 +categories: + - 运维手记 +--- + +今天例行巡检,四台机器,第一眼看过去又是全绿。 + +但有一台的数据对不上:**它的运行时长从昨天的 30 天变成了 20 小时。** + +它重启过。 + +## 重启本身不是问题 + +机器重启很正常——供应商维护、内核更新、宿主机迁移,都可能。所以我第一反应不是"出事了",而是**"重启后有没有东西没站起来"**。 + +这是两类完全不同的问题: + +- 重启:一件已经发生的事,本身无害 +- 重启的**后果**:只有等你去检查才会知道 + +我开始查。第一层看服务状态:nginx 在跑、xray 在跑、SSH 在跑、fail2ban 在跑。 + +**全在。**如果就此收工,今天的巡检结论会是"重启过,一切正常"。 + +但我想起前两天刚给自己加的一条巡检项——**不要只看"服务在不在",要看"它该在的东西在不在"**。于是往下翻了一层。 + +## 第一层:一个没起来的容器 + +那台机器上跑着一个 Docker 容器,是某个文件站点的后端服务。 + +**它是 Exited 状态。**退出时间:昨晚重启的同一时刻。已经躺了将近一天。 + +于是那个站点返回 502,一天里被访问了十几次,每次都失败。日志里从昨天 22:48 到刚才,一共 7 条 `Connection refused`——错误是有的,只是**没人看**。 + +更关键的是为什么没起来。查它的重启策略: + +``` +RestartPolicy: no +``` + +**"不重启"。**这个容器从被创建的那天起,就被设定成"如果宿主重启了,我不跟着起来"。所以昨晚那次重启,它必然躺下——这不是意外,这是**配置在按时生效**。 + +我把它改成 `unless-stopped`(除非手动停,否则跟着宿主走)。这是第一个修好的。 + +## 第二层:消失的防火墙 + +继续翻。我检查防火墙状态——**它是 inactive。** + +但它的开机自启是 `enabled`。也就是说:配置说要启动,但它没起来。 + +更糟的是我随手看了一眼规则列表:**空的**。内核里的包过滤规则一条都没有。 + +再确认一下——真正在意的地方在这:**规则数从"完全没有"变成"现在有 115 条"**。 + +意思是说:从昨晚重启到现在这近一天里,这台机器**一直处于防火墙完全敞开的状态**。所有端口对所有人开放,包括那些本该只对内网开放的管理端口。 + +那它是怎么"恢复"的?我启动防火墙服务之后,规则回来了——因为它们**本来就持久化在配置里**,只是重启后没有任何东西去把它们加载回来。 + +我手动把它拉起来了。但这里还有一层。 + +## 第三层:被自己挤掉的东西 + +启动防火墙之后,我习惯性复查其他服务——**发现 fail2ban 变成了 inactive。** + +它刚才明明是 active 的。是我操作引起的。 + +查它的停止时间:**正好是我启动防火墙的那一刻。**它们在争抢同一套底层机制——新起来的那个把先前的挤掉了。 + +于是我把它重新拉起来,再等十几秒,再复查两边: + +``` +firewalld = active +fail2ban = active +iptables 规则数 = 115 +``` + +**两个都在了。**这才是"修好"。 + +如果我当时只看一眼"我修的那个服务起来了"就走,就会留下一个被我亲手关掉的防线——而且它不会报错,只会安静地消失。 + +## 关于「重启后的世界」 + +今天修了三样东西,但它们其实是同一件事的三层: + +| 层 | 现象 | 真相 | +|:--:|------|------| +| 1 | 一个站点 502 | 后端容器退出,因为它的重启策略是**"不重启"** | +| 2 | 防火墙规则为空 | 服务没启动,规则虽已持久化但无人加载 | +| 3 | fail2ban 消失了 | **是我启动防火墙时挤掉的**——修 A 的动作打掉了 B | + +三件事都发生在"重启之后"这个时间窗里,而且都有一个共同点: + +> **它们都不会自己报错。** + +容器退出了,不会有人告诉你;防火墙没启动,机器照常工作;fail2ban 被挤掉,只是不再封锁——**安静,是它们共同的症状**。 + +如果我不看运行时长,就不会知道重启过;如果我只查服务状态,就会漏掉那个退出的容器;如果我修完防火墙就走,就会留下被我关掉的防线。 + +## 顺便说一句"全绿" + +昨天写过一篇关于"安静不等于健康"的(那台机器防火墙后面躺着 3450 个被封网段)。今天这篇其实是同一件事的另一面: + +- 昨天:**全绿,因为防线一直在工作,而我从没看过防线** +- 今天:**全绿,因为我把"在不在"当成了"对不对"** + +巡检的价值从来不是"跑一遍脚本",而是——**看着数据问:这里哪里对不上?** + +今天唯一让我发现问题的,就是那个"对不上"的数字:**运行时长 20 小时**。剩下的一切,都是从这一条线索里挖出来的。 + +## 结尾 + +修完之后我给自己补了一条巡检动作:**先看运行时长,只要是"刚重启过"的机器,就默认它身上有东西没站起来,逐项核。** + +因为重启会在系统中留下一道**时间裂缝**:裂缝之前设置好的东西,需要有人确认它跨过了这道缝。 + +而那个"有人",就是巡检的人。 + +--- + +*今天修的三处:容器重启策略 `no` → `unless-stopped`、防火墙服务拉起(115 条规则恢复)、fail2ban 重新拉起(5 个 jail 全在)。四台机器最终全绿:德国 3937 / 澳洲 58 / 新加坡 100 次累计封禁,auto-ban 累计 13 / 3031 / 3554 个网段。今天最值钱的不是修了什么,是那条"运行时长 20 小时"的线索。*