服务器重启故障排查

70 阅读8分钟

前言

针对服务器异常重启且服务未自动恢复的情况,排查思路需要分为 操作系统 /硬件层面”“K8s/容器层面” 两个方向。

一、 排查操作系统为何重启

首先需要弄清楚是掉电/硬件故障,还是系统崩溃,或者是内存不足(OOM)导致的重启。

  1. 确认重启准确时间

last reboot
# 或者
uptime -s

这将帮助你在日志中锁定具体的时间段。

uptime -s
2026-01-04 21:07:45
#可确定具体重启时间
接下来去哪里查“是谁重启的”?

既然确定是“被重启”的,你需要找出指令来源:

  1. 检查谁登录过 查看在 21:06 左右谁在线:
last | head -n 20

看是否有用户(如 root, oper)在 21:00 ~ 21:06 之间登录并在且仍然在线(或者显示 down)。

  1. 检查操作历史 如果是人为操作,查看 root 或其他用户的命令历史:
history | grep reboot
# 或者查看特定用户的历史
cat /home/user/.bash_history | tail -n 20
  1. 检查审计日志 如果开启了 auditd,可以查到具体的命令调用:
grep "reboot" /var/log/audit/audit.log
grep "shutdown" /var/log/audit/audit.log
  1. 云平台监控 如果是阿里云/华为云/腾讯云等云平台,去控制台查看“操作日志” 。
  • 如果控制台显示“用户重启实例”,那就是有人点的。
  • 如果显示“系统维护重启”,那就是云厂商的问题。
总结

确定服务器是否为“异常” 重启 ,还是被“命令”重启的。 这是影响排查方向的 。

  1. 检查系统日志(核心步骤)

由于服务器已经重启,当前的 dmesg 可能看不到之前的信息。你需要查看上一次启动期间的日志。

  • 使用 systemd 日志 (推荐):
# 查看上一次启动周期的日志(即崩溃前的那次)
journalctl -b -1 -e
# 如果日志太多,可以只看最后几百行,寻找 error, panic, critical 等关键字
journalctl -b -1 -n 500
  • 如果输出提示 "Data from the specified boot is not available",说明日志没有持久化配置,只能查 /var/log 下的文件。
  • 查看传统 日志文件 : 检查 /var/log/messages/var/log/syslog(取决于你的linux版本):
grep -i "error" /var/log/messages | tail -n 50
# 或者是
grep -i "error" /var/log/syslog | tail -n 50
  1. 检查是否因内存不足 (OOM) 被强杀

集群在负载高时容易耗尽内存,导致 Linux 内核触发 OOM Killer,这通常会导致系统卡死重启或关键进程被杀。

# 搜索内存溢出记录
grep -i "Out of memory" /var/log/kern.log
# 或者
grep -i "Kill process" /var/log/syslog
# 或者
journalctl -k | grep -i "OOM"

如果你看到服务或相关容器进程被 Kill,说明你需要升级配置或限制容器资源。

二、排查集群故障根因

在排除“人为 SSH 登录重启”的可能性后,那么,是谁触发了重启?这至关重要。

可能性一:自动化的监控脚本

考虑到 21:00:01 监控开始报错。

  • 场景: 服务器上可能运行着一个脚本(crontab 或后台服务)。它检测到某个业务连续报错或端口不通,于是执行了某个脚本命令试图自动修复。或者这个脚本占用了大量资源导致节点资源耗尽。

  • 验证方法:

    •   检查计划任务日志:
    • grep CRON /var/log/cron | grep "21:0"# 或者
      grep CRON /var/log/syslog | grep "21:0"
      

可能性二:K3s/K8s 节点的资源耗尽

当k8s节点的资源耗尽时,节点会进入不可用状态(节点被标记为 NotReady),服务进入卡顿或者不可用状态。通常分为 K8s 层面(Kubelet 的反应)操作系统 层面(Linux 内核的反应) 两个阶段。

  1. 内存耗尽

这是最容易导致服务崩溃的原因。

  • K8s 层面的反应 ( Pod 驱逐):

    • 现象: 当节点内存低于阈值(默认 memory.available < 100Mi),Kubelet 会触发 MemoryPressure 状态。

    • 后果: Kubelet 开始驱逐 Pod。它会根据 QoS 等级(服务质量)来杀 Pod:

      • 先杀 BestEffort(没设置 limit/request 的 Pod)。
      • 再杀 Burstable(使用了超过 request 内存的 Pod)。
      • 最后才杀 Guaranteed(关键业务)。
    • 日志: kubectl get node 显示 MemoryPressure,Pod 状态变为 Evicted

  • 操作系统 层面的反应:

    • 现象: 如果内存增长太快,Kubelet 来不及反应,Linux 内核会介入。
    • 后果: 触发 OOM Killer。内核会根据评分(oom_score)强制杀死占用内存最高的进程(通常是 Java 进程、数据库或 K3s Server 本身)。
    • 日志: /var/log/messagesdmesg 出现大量 Out of memory: Kill process ...
    • 对系统的影响: 如果杀掉的是业务进程,业务挂掉;如果杀掉的是 SSHD 或 Systemd,服务器可能会死机或 重启
  1. CPU 耗尽 (CPU Pressure) —— 变慢、假死

CPU 即使跑满 100%,通常也不会直接导致进程被杀,但会引发连锁反应。

  • 现象: Load Average 飙升,系统响应极慢,SSH 登录卡顿或超时。

  • K8s 的连锁反应:

    • 探针失败: 业务处理请求变慢,导致 K8s 的 Liveness Probe(存活探针) 超时。Kubelet 认为容器死锁了,于是重启 容器
    • Readiness 失败: 业务无法及时响应,Readiness Probe 失败,Service 切断流量,导致业务不可访问。
    • HPA 扩容: 如果配置了自动扩容,Pod 数量会增加,反而进一步消耗资源(如果节点资源不足)。
  1. 磁盘空间耗尽 (Disk Pressure) —— 写入失败、服务崩溃

K3s/K8s 极其依赖 /var/lib/rancher/k3s/var/lib/docker(或 containerd)。

  • 现象:

    • ImageFS Pressure: 容器镜像占满了磁盘。Kubelet 会开始删除未使用的镜像和停止的容器。
    • NodeFS Pressure: 整个文件系统满了。
  • 后果:

    • Pod 无法启动: 无法拉取新镜像 (ErrImagePull)。
    • 日志丢失: /var/log 满了,你看不到报错日志。
    • 业务崩溃: 数据库(MySQL/Redis)或应用无法写入临时文件或日志,直接报错退出。
    • K3s 崩溃: etcd(K3s 自带数据库)如果无法写入磁盘,整个集群会挂掉,kubectl 命令失效。
  1. PID 耗尽 (PID Pressure) —— 无法创建新线程

这种情况常发生在高并发的 Java 应用或遭遇“Fork 炸弹”时。

  • 现象: 内存还有空余,但无法启动新进程或线程。
  • 报错: Resource temporarily unavailableCannot allocate memory (尽管内存够)。
  • 后果: Kubelet 报 PIDPressure,开始驱逐 Pod。SSH 甚至可能都登不上去,因为 SSH 登录需要 Fork 一个新进程。

可能性三:K3s/K8s 的某些激进策略 (较少见)

虽然 K8s 通常只会重启 Pod,但在极少数配置下(如节点自愈脚本),如果节点判定自身状态极差,可能会触发节点重启。但概率低于前两者。

可能性四:云平台控制台操作

日志里出现了虚拟机和宿主机(云平台)通信的组件。由于来自云平台控制台重启不会被识别为服务器用户,所有这也是排查方向。

  • 场景: 操作人员在云平台的控制台上,点击或者误操作了“重启实例”。
  • 原理: 云平台通过Agent或ACPI信号通知操作系统关机。这种操作不会last 中留下登录记录,但会触发你在日志里看到的 systemd 正常关机流程。
  • 验证方法: 必须去云服务商的网页控制台,查看 “操作日志” (Operation Logs)“事件监控” 。查看 1月4日 21:06 分左右是否有“重启实例”的记录。

三、 排查集群为何未自动恢复

正常情况下,服务器重启后,systemd 应该自动启动集群,集群会自动拉起容器。如果存在未自动恢复的情况需要排查。

  1. 检查集群服务是否开机自启

如果服务器重启后集群没起来,可能是没有 enable 服务。

#kubelet 自动启动 = 集群自动恢复  如果是k3s请使用k3s替换kubelet查询
systemctl is-enabled kubelet
# 如果显示 disabled,请执行:
systemctl enable kubelet
  1. 查看集群服务启动日志

检查 K3s 自身是否有报错:

systemctl status kubelet
# 查看 K3s 服务的详细日志
journalctl -u kubelet -e --no-pager
  1. 检查 Containerd日志

K3s 默认使用 containerd。如果 K3s 起来了但容器没起,可能是运行时的问题。

# 通常日志在 /var/lib/rancher/k3s/agent/containerd/containerd.log# 或者直接看 journal
#k3s-agent
journalctl -u containerd

三、 常见原因总结与对策

根据经验,异常重启通常由以下几个原因导致:

  1. 资源耗尽 ( OOM ):

    1. 现象: 日志里有 "Out of memory: Kill process"。
    2. 对策: 给 Pod 设置 resources limits(资源限制),或者增加服务器 Swap/内存。
  2. 云服务商/硬件维护:

    1. 现象: 系统日志里突然中断,没有任何报错,再次启动通过 last reboot 能看到时间。
    2. 对策: 去阿里云/腾讯云/AWS 的控制台查看“站内信”或“事件监控”,看是否有物理机迁移或维护重启。
  3. 磁盘写满:

    1. 现象: /var/lib/rancher/k3s 所在分区满了,导致组件崩溃。
    2. 排查: df -h 查看磁盘使用率。
  4. 定时任务或者脚本

    1. 现象: 某个脚本命令试图自动修复或者占用了大量资源导致节点资源耗尽。
    2. 排查: crontab -l查看定时任务或者相关脚本

建议后续操作

为了防止下次重启后服务无法访问,请确保执行以下操作:

  1. 设置开机自启: systemctl enable kubelet
  2. 检查 重启 策略: 确保你的 Deployment/StatefulSet 的 restartPolicyAlways
  3. 持久化日志: 确保 /var/log/journal 目录存在,以便 journalctl 能保存重启前的日志。