在CentOS系统运维中,当内核发生panic或oops崩溃时,kdump是你必须配置的核心机制。它通过kexec在当前内核崩溃时加载一个备用内核,然后将崩溃时的内存状态捕获为vmcore转储文件,保存在/var/crash/目录下。这份转储文件是后续用crash工具分析内核崩溃根因的唯一依据。不配置kdump,内核崩溃后你只能看到屏幕上一堆报错信息,重启后什么痕迹都没有,排查问题将变得极其困难。下面我从安装、配置、验证到分析,完整讲透整个流程。

一、kdump的工作原理和为什么必须开

kdump基于kexec系统调用实现。kexec允许从当前运行的内核直接启动另一个内核,跳过BIOS自检和硬件初始化阶段。当系统内核发生致命错误时,kdump机制会自动触发kexec,加载一个预置的小型捕获内核(capture kernel),这个捕获内核会把崩溃时刻的物理内存镜像写入磁盘。整个过程不需要人工干预,也不依赖崩溃内核本身是否还能正常工作。

在生产环境中,内核崩溃可能由硬件故障、驱动bug、内存损坏等多种原因引起。没有kdump转储,运维人员只能靠经验猜测,或者反复复现问题。有了vmcore文件,你可以用crash工具精确定位到崩溃时的函数调用栈、寄存器状态、内存布局,甚至具体是哪个模块出了问题。这是Linux内核故障排查的标准流程,也是企业级运维的基本功。

二、CentOS 7和CentOS 8/Stream上安装kdump

CentOS 7和CentOS 8/Stream的安装方式略有不同,但都很简单。首先安装kdump相关软件包:

# CentOS 7
yum install kexec-tools kdump -y

# CentOS 8 / Stream
dnf install kexec-tools kdump -y

安装完成后,需要启用并启动kdump服务:

systemctl enable kdump
systemctl start kdump

启动kdump服务后,系统会自动生成一个捕获内核镜像,通常位于/boot/目录下,文件名类似vmlinuz-0-rescue-xxxx。你可以用ls /boot/vmlinuz-*来确认是否生成。

三、配置kdump核心参数

kdump的主配置文件是/etc/kdump.conf,这个文件控制着捕获内核的内存预留、转储文件存放路径、压缩方式等关键参数。下面逐一讲解核心配置项。

1. 预留捕获内核内存(path /proc/vmcore)

捕获内核需要在系统启动时就预留一块内存,否则崩溃时没有空间来运行捕获内核。默认情况下系统会自动计算,但在大内存机器上建议手动指定。编辑/etc/kdump.conf:

path /var/crash
core_collector makedumpfile -l --message-level 1 -d 31

这里core_collector使用makedumpfile工具,它比默认的dd方式更高效,支持过滤无用页面(如全零页、用户态页面),-l表示使用lzop压缩,-d 31表示过滤掉所有用户态页面和空闲页,只保留内核相关的关键内存数据。这在大内存服务器上能大幅减小转储文件体积。

2. 指定转储路径

默认转储保存在/var/crash/目录下。如果这个分区空间不够,可以改到其他挂载点:

path /data/crash

确保目标目录存在且有足够空间。一台64GB内存的服务器,完整转储可能需要30-60GB磁盘空间,用makedumpfile过滤后可以控制在10-20GB。

3. 捕获内核命令行参数

在/etc/kdump.conf中可以通过kdump_commandline指定捕获内核启动参数,例如:

kdump_commandline --append "irqpoll maxcpus=1 nr_cpus=1"

这在某些硬件环境下很有用,比如捕获内核启动时遇到中断风暴,irqpoll可以避免中断丢失。一般情况下不需要修改,保持默认即可。

4. 网络转储(可选)

如果本地磁盘空间紧张,可以配置网络转储,把vmcore通过NFS或SSH传到远程服务器:

net nfs my.nfs.server:/remote/crash
net_timeout 60

使用网络转储时要注意,网络本身在崩溃时可能不可用,所以这种方式适合做备份而非唯一手段。

四、预留内存的手动计算方法

对于内存超过16GB的服务器,自动计算可能不准确,建议手动设置。在/etc/kdump.conf中添加:

kdump_args --mem-max 4G

或者直接在grub中通过crashkernel参数指定。编辑/etc/default/grub,找到GRUB_CMDLINE_LINUX行,添加:

GRUB_CMDLINE_LINUX="crashkernel=auto"

如果auto不生效,可以手动指定,比如64GB内存的机器:

GRUB_CMDLINE_LINUX="crashkernel=256M"

修改后需要重新生成grub配置:

# CentOS 7
grub2-mkconfig -o /boot/grub2/grub.cfg

# CentOS 8 / Stream
grub2-mkconfig -o /boot/grub2/grub.cfg

然后重启系统使参数生效。重启后用以下命令确认预留是否成功:

cat /proc/cmdline

输出中应该包含crashkernel=xxxM的字样。

五、验证kdump是否正常工作

配置完成后必须验证,否则真到崩溃时才发现没配置好就晚了。CentOS提供了一个安全的测试方法,通过sysrq触发模拟崩溃:

echo c > /proc/sysrq-trigger

这会触发一个内核panic,kdump应该自动启动捕获内核并生成vmcore文件。整个过程机器会重启,不会对数据造成破坏(因为只是模拟)。执行后检查/var/crash/目录下是否生成了新的转储目录,里面应该有vmcore文件。

如果没有生成,按以下步骤排查:

第一,检查kdump服务状态:systemctl status kdump,确认是active (running)。

第二,检查捕获内核是否存在:ls /boot/vmlinuz-*rescue*。

第三,检查crashkernel参数是否生效:dmesg | grep -i crash。

第四,检查SELinux是否阻止:如果是enforcing模式,查看/var/log/messages中是否有avc denied相关日志,必要时设为permissive测试。

六、用crash工具分析vmcore转储文件

拿到vmcore文件后,需要用crash工具进行分析。首先安装:

yum install crash kernel-debuginfo -y

kernel-debuginfo包包含带调试符号的内核镜像,没有它crash无法解析符号。然后启动crash:

crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/127.0.0.1-2024-xx-xx-xx:xx/vmcore

进入crash交互界面后,常用命令如下:

bt        # 查看崩溃时的回溯调用栈
ps        # 查看崩溃时的进程列表
log       # 查看内核日志缓冲区
files     # 查看崩溃时打开的文件
mod -S    # 列出已加载的内核模块
mod <模块名>  # 查看特定模块信息

bt命令是最核心的,它会显示崩溃时内核执行到哪个函数、调用链是什么。结合模块信息,你就能定位到具体是哪个驱动或子系统出了问题。比如看到调用栈底部是某个网卡驱动的函数,基本就能确认是网卡驱动bug导致的panic。

七、生产环境的最佳实践建议

第一,不要把/var/crash放在根分区。根分区满了会导致kdump无法写入,转储失败。建议单独挂载一个足够大的分区,或者用LVM预留空间。

第二,定期测试kdump。每个季度或内核升级后都应该做一次sysrq触发测试,确保机制正常。内核大版本升级后,捕获内核可能需要重新生成。

第三,保留多份转储。/var/crash/目录下每次崩溃会生成带时间戳的子目录,不要随意删除。可以设置定期归档策略,把旧转储压缩后移到冷存储。

第四,配合监控告警。可以写一个简单的crontab脚本,定期检查/var/crash/下是否有新生成的目录,有则发送告警通知,这样即使你不在现场也能第一时间知道系统发生了内核崩溃。

第五,对于使用UEFI启动的新机器,确认kexec-tools版本支持UEFI环境下的kdump,CentOS 7.6以上和CentOS 8都已经支持,但老版本可能有兼容性问题。

八、常见问题和踩坑总结

问题一:kdump启动失败提示内存不足。这通常是crashkernel预留太小,或者系统总内存很大但自动计算不准确。手动加大crashkernel值即可解决。

问题二:vmcore文件生成了但crash打不开。90%的情况是缺少对应版本的kernel-debuginfo包,或者vmlinux路径不对。确保安装的debuginfo和当前运行内核版本完全一致。

问题三:触发sysrq测试后机器没有重启。可能是sysrq被禁用了,检查/proc/sys/kernel/sysrq的值,设为1即可:echo 1 > /proc/sys/kernel/sysrq。

问题四:使用makedumpfile时转储文件损坏。检查makedumpfile版本是否支持当前内核,老版本在新内核上可能有兼容性问题,升级makedumpfile到最新版。

总的来说,kdump配置并不复杂,但细节决定成败。从预留内存到转储路径,从压缩策略到调试符号,每一步都需要确认到位。把kdump当成生产服务器的标配来部署,而不是出了问题才临时配置,这才是成熟运维的做法。