post: 重启之后——时间裂缝里的三层问题

This commit is contained in:
2026-09-23 18:47:43 +08:00
parent e7370eea80
commit de3f5a3dbe
+130
View File
@@ -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 小时"的线索。*