3、内核恐慌:Kernel Panic 场景下的日志抓取与 vmcore 配置
Kernel Panic,说白了就是 Linux 内核遇到了它无法处理的致命错误。这时候系统会直接「罢工」,屏幕上刷出一堆调用栈信息,然后要么挂死,要么自动重启。
我遇到过不少运维新手,一看到 Panic 就慌了,赶紧重启机器。结果呢?现场被破坏了,想查根因都无从下手。其实,Panic 本身并不可怕,可怕的是你没留下证据。
这一章,我们就来聊聊:当内核恐慌发生时,怎么把现场「拍下来」。
3.1 理解 Kernel Panic 的触发机制
先搞清楚一件事:Panic 不是随机发生的。它通常由以下几种原因触发:
- 硬件故障:比如内存 ECC 报错、CPU 缓存一致性错误、PCIe 链路异常。
- 内核 BUG:驱动模块有缺陷、文件系统代码有逻辑漏洞、内存管理模块踩了空指针。
- 关键进程崩溃:init 进程或内核线程意外退出,内核认为系统无法继续运行。
- 资源耗尽:极端情况下,内存或进程表被耗尽,内核无法分配关键资源。
内核在 Panic 时,会调用 panic() 函数。这个函数会做几件事:
- 打印当前 CPU 的寄存器状态和调用栈。
- 打印所有 CPU 的 backtrace(如果启用了多核支持)。
- 尝试刷新日志缓冲区到控制台。
- 根据
panic_timeout参数决定是否自动重启。
关键点:Panic 发生后,内核日志(dmesg)中最后几行信息,就是破案的关键线索。但默认情况下,这些日志只存在内存里,一旦重启就丢了。
3.2 日志抓取:抢救 dmesg 的最后机会
如果你的系统 Panic 后没有自动重启,或者你通过 IPMI/iLO 等带外管理卡还能看到控制台输出,那就有机会手动抓取日志。
我个人习惯在 Panic 发生后,第一时间做两件事:
- 拍照:用手机拍下屏幕上的调用栈。虽然原始,但最可靠。
- 串口记录:如果配置了串口控制台,终端模拟器里会保留完整的 Panic 输出。
但说实话,手动抓取太被动了。更专业的做法是——让系统在 Panic 时自动把内存转储下来。这就是 vmcore。
3.3 vmcore 是什么?为什么需要它?
vmcore 是内核 Panic 时,将整个内存内容(或部分内存)导出到磁盘的一个文件。你可以把它理解成「内核的尸检报告」。
有了 vmcore,你可以用 crash 工具或 gdb 来分析:
- Panic 发生时,CPU 正在执行哪条指令?
- 各个进程的堆栈是什么状态?
- 内存中哪些数据结构被破坏了?
- 是哪个内核模块导致的崩溃?
我在项目中遇到过好几次,光看 dmesg 根本看不出问题,但一分析 vmcore,立刻定位到是某个第三方驱动在特定条件下触发了空指针解引用。
小提示:vmcore 文件通常很大(等于物理内存大小),所以需要预留足够的磁盘空间。建议单独划分一个分区,比如 /var/crash。
3.4 配置 kdump:让系统自动生成 vmcore
kdump 是 Linux 上最常用的 vmcore 捕获机制。它的原理很简单:
- 系统正常运行时,保留一小部分内存给一个「捕获内核」(capture kernel)。
- 当主内核 Panic 时,自动切换到捕获内核。
- 捕获内核启动后,将主内核的内存内容保存到磁盘。
下面是我常用的配置步骤:
3.4.1 安装 kdump 工具
# RHEL/CentOS
yum install kexec-tools crash
# Ubuntu/Debian
apt install kdump-tools crash
3.4.2 预留内存
在 GRUB 内核启动参数中,添加 crashkernel=auto 或手动指定大小:
# 编辑 /etc/default/grub
GRUB_CMDLINE_LINUX="... crashkernel=256M"
# 更新 GRUB 配置
grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL/CentOS
update-grub # Ubuntu/Debian
注意:crashkernel=auto 在某些旧内核上可能不生效。我建议手动指定,比如 256M 或 512M,具体取决于你的内存总量。内存小于 2G 的机器,可以设 128M。
3.4.3 配置 kdump 服务
# 编辑 /etc/kdump.conf
# 指定 vmcore 保存路径
path /var/crash
# 指定核心收集器(压缩格式)
core_collector makedumpfile -c -d 31
# 可选:指定转储级别(0-31,31 表示全部转储)
# -d 31 表示排除所有可排除的页,减小文件体积
3.4.4 启动并测试
# 启动 kdump 服务
systemctl enable kdump
systemctl start kdump
# 手动触发 Panic 测试(仅限测试环境!)
echo c > /proc/sysrq-trigger
执行 echo c > /proc/sysrq-trigger 后,系统会立即 Panic。重启后,检查 /var/crash 目录下是否生成了 vmcore 文件。
重要:千万不要在生产环境上执行这个测试命令!我见过有人手滑在线上机器敲了这条命令,结果整个团队被叫去复盘。测试请用虚拟机或专门的测试机。
3.5 核心流程:从 Panic 到 vmcore 的完整链路
下面这张图,展示了 kdump 的工作流程:
3.6 避坑指南:我曾经踩过的坑
配置 kdump 看起来简单,但实际落地时有不少细节。我把自己踩过的坑列出来,你遇到了可以少走弯路:
| 问题场景 | 原因 | 解决方案 |
|---|---|---|
| Panic 后没有生成 vmcore | 捕获内核没有预留成功 | 检查 /proc/cmdline 是否包含 crashkernel 参数 |
| vmcore 文件大小为 0 | 磁盘空间不足或路径权限错误 | 确保 /var/crash 有足够空间,且 kdump 用户有写权限 |
| 捕获内核启动失败 | 预留内存太小或内核版本不匹配 | 增大 crashkernel 值,或更新 kexec-tools 版本 |
| vmcore 无法被 crash 工具解析 | 缺少对应的 debuginfo 包 | 安装 kernel-debuginfo 包,版本必须与运行内核一致 |
特别提醒:我曾经在一台 64G 内存的机器上,忘了预留磁盘空间。结果 Panic 后,捕获内核尝试写入 64G 的 vmcore,直接把根分区写满了,系统彻底起不来。所以,一定要单独划分一个分区给 vmcore,比如 /var/crash 挂载一个 100G 的独立分区。
3.7 验证配置是否生效
配置完成后,别急着收工。我建议做一次完整的验证:
- 检查 kdump 服务状态:
systemctl status kdump - 检查预留内存:
cat /proc/iomem | grep Crash - 在测试环境触发 Panic,确认 vmcore 生成成功
- 用
crash工具打开 vmcore,确认可读
只有验证通过,你才能放心地把机器交还给业务方。否则,真出了事,你连个「尸检报告」都拿不到。
我的习惯:每次内核升级后,我都会重新验证一遍 kdump 配置。因为新内核可能改了某些接口,导致 kdump 失效。别等到 Panic 了才发现——那时候就晚了。