☰
CentOS 7内核升级后grub rescue修复指南:从根因到实操
2026/10/19 7:52:41 网站建设 项目流程

刚把 CentOS 7.7 的内核从 3.10 升到某个大版本,重启之后直接被扔进grub rescue>这行灰底白字的提示符,整个系统卡在引导阶段起不来。这种体验我太熟悉了,第一次遇到的时候对着屏幕愣了半天,后来弄清楚原理再回头看,其实修复路径并不复杂,但有几个关键点一旦搞错,轻则多折腾几小时,重则把引导彻底弄坏。

这篇文章就把我在实际环境中踩过的坑、验证过的修复步骤、以及“为什么会进 rescue 模式”的底层逻辑完整梳理一遍。不管你是刚入行的运维,还是被生产服务器逼着临时救火的开发,照着下面的思路走,基本都能把系统拉回来。

1. 升级内核后掉进 grub rescue 的根因拆解

先说结论:grub rescue>不是内核本身坏了,而是 GRUB 第二阶段引导程序找不到自己需要的文件,或者找不到/boot分区的位置,所以它退回到一个最小救援环境,等着你手动告诉它“你在哪、该读什么”。内核升级只是触发了这个隐藏问题的导火索。

1.1 引导链路里最脆弱的三个环节

一台 BIOS 引导方式的 CentOS 7 机器,从按下电源到出现登录提示符,完整链路是这样:

  • BIOS 自检,找到启动磁盘,读取 MBR(主引导记录)。
  • MBR 里的 GRUB 第一阶段代码(通常是/boot分区开头的 446 字节)被加载。
  • 第一阶段代码跳转到第二阶段,也就是stage1.5或直接加载/boot/grub2/下的核心模块和配置文件。
  • GRUB 根据grub.cfg里的 menuentry 找到内核文件vmlinuz-xxx和内存盘initramfs-xxx,把它们载入内存,然后交接控制权。

升级内核后掉进 rescue 模式,绝大多数情况出在第三步和第四步之间:

  1. /boot分区空间写满,新内核的vmlinuz和initramfs只写了一半,GRUB 读取失败。
  2. grub.cfg里记录的内核文件名和磁盘上实际存在的文件名对不上,比如旧内核文件被清理,但配置没有重新生成。
  3. 磁盘设备名漂移,比如原来系统装在/dev/sda,因为加了新盘或者 BIOS 枚举顺序变化,启动盘变成了/dev/sdb,GRUB 里的root指令指向了不存在的设备。
  4. 第三方驱动编译安装时动了/boot下的文件,或者手动改过 grub 配置导致语法错误。

我那次生产环境出问题的原因就是第一种,/boot分区是独立的 500M 小分区,内核升级装完新版本后,旧内核没自动清理,分区可用空间只剩 3M,initramfs文件写入不完整。重启后 GRUB 就读到了一个残缺的内核镜像,直接摔进 rescue。

1.2 rescue 模式的提示符到底在说什么

在grub rescue>提示符下,你能用的命令少得可怜:ls、set、unset、insmod。其他的像normal、linux、initrd、boot这些完整引导命令在 rescue 阶段基本不可用,因为核心的normal.mod模块可能还没被加载。

这个环境的设计意图很简单:让你用ls去探查磁盘和分区,找到/boot所在的位置,然后手动set正确的prefix和root变量,让 GRUB 恢复能力,继续走完引导。

所以修复的本质就一句话:让 GRUB 重新找到/boot/grub2和内核文件,然后重建引导配置。下面第三节的整套流程,就是在不同场景下实现这一句话。

2. 修复前必须搞清楚的两个关键判断

进了 rescue 模式别慌,也别急着敲命令。先做两个判断,直接决定你后续用哪条修复路线。判断错了,后面的操作可能越修越坏。

2.1 判断当前引导方式:BIOS 还是 UEFI

CentOS 7.7 存在两种引导方式,修复命令看起来几乎一样,但实际落盘的引导文件位置完全不同:

引导方式GRUB 配置文件位置引导程序安装目标判断方法
BIOS + MBR/boot/grub2/grub.cfg/dev/sda(磁盘 MBR)在 rescue 下ls能看到一个不带gpt分区表的磁盘结构
UEFI + GPT/boot/efi/EFI/centos/grub.cfg/dev/sda1(ESP 分区)ls能看到efi分区,或者机器启动时按快捷键能进 UEFI 设置

我用的环境绝大多数是 BIOS 引导的物理机或虚拟机,默认走/dev/sda的 MBR,但如果你接手的是云主机或者较新的服务器,很可能是 UEFI。判断方法很简单:在 rescue 提示符下执行ls,看到类似(hd0) (hd0,msdos1) (hd0,msdos2)的输出就是 MSDOS 分区表,即 BIOS 模式;看到(hd0,gpt1) (hd0,gpt2)则可能是 GPT 分区表,需要进一步确认是不是 UEFI。

为什么这个判断重要?因为重装引导程序的命令在两种模式下差异极大。BIOS 模式是grub2-install /dev/sda,UEFI 模式是grub2-install --target=x86_64-efi --efi-directory=/boot/efi,而且 UEFI 模式还要确保 ESP 分区挂载正确。如果你在 UEFI 机器上用了 BIOS 的命令,GRUB 的 EFI 引导项不会被更新,重启后照样进不去系统。

2.2 判断是否能直接进入系统

有一种“假 rescue”情况:GRUB 只是暂时找不到配置,但内核文件其实完好无损。这时不需要进救援光盘,直接在grub rescue>下手动引导一次,先进系统,再用系统内的工具重建引导,比在救援环境里折腾省事得多。

手动引导的操作方式如下,假设/boot在(hd0,msdos1):

grub rescue> set root=(hd0,msdos1) grub rescue> set prefix=(hd0,msdos1)/grub2 grub rescue> insmod normal grub rescue> normal

如果这三条命令执行后正常出现 GRUB 菜单,说明引导文件基本完好,只是 GRUB 的root和prefix变量丢了或者指向错误。进了系统之后,重新生成 grub.cfg 并重装引导程序就能根治。

如果执行insmod normal时报错,说找不到normal.mod,那问题就严重了,说明/boot/grub2下的模块文件可能损坏或缺失。这时候别浪费时间,直接上救援光盘或安装 U 盘,走第三节的完整修复流程。

这个判断的价值在于,它能帮你区分“轻症”和“重症”,省掉不必要的救援环境启动步骤。我在虚拟机上验证过多次,set root加normal的手动引导成功率非常高,前提是grub2目录完整。

3. 救援环境完整修复流程(从 U 盘启动到重建引导)

如果手动引导失败,或者你干脆进不去 GRUB 菜单,那就老老实实走救援环境修复。整个过程分五步,每一步都有坑,我逐个说明原理和注意事项。

3.1 使用原版安装盘进入救援模式

准备一个和你系统版本相同或相近的 CentOS 7.x 安装 U 盘(注意:越接近原系统版本越好,不同大版本的 GRUB 模块可能存在兼容差异),从 U 盘启动后,在安装界面选择“Troubleshooting”,然后选“Rescue a CentOS system”。

进入救援模式后,系统会让你选择是否挂载根文件系统,记得选 1,也就是Read-Only挂载。这一步很多人不理解为什么不是Read-Write,原因是在修复引导之前,最好避免系统自动挂载带来的不确定因素,我们自己手动挂载成读写模式会更可控。

接下来需要拿到一个交互式 shell。在救援模式下执行:

chroot /mnt/sysimage

执行之后,你看到的文件系统就是原系统的真实根目录。后续所有命令都在这个 chroot 环境里执行,操作效果等同于你正常开机后在系统里执行命令。这一步是所有修复动作的前提。

提示:chroot 失败最常见的两个原因,一是/mnt/sysimage没有被正确挂载,二是 /boot 分区没挂上。先用mount和lsblk检查,再考虑后续操作。

3.2 审查磁盘布局并挂载缺失分区

在 chroot 之前,先确认分区情况。我用得最多的命令组合是这样:

lsblk -f

这个命令能看清每个分区的文件系统类型、UUID、挂载点。理想情况下,你应该看到一个/boot分区(如果你当初是独立分区装的系统)和一个根分区/。

如果lsblk -f显示/boot没有挂载,手动挂上:

mount /dev/sda1 /mnt/sysimage/boot

如果根分区本身都没挂载,先挂根分区,再挂/boot和/boot/efi(UEFI 模式需要):

mount /dev/sda2 /mnt/sysimage mount /dev/sda1 /mnt/sysimage/boot mount /dev/sda1 /mnt/sysimage/boot/efi # 仅 UEFI 模式

挂载顺序不能乱,必须先根分区再 /boot,因为/mnt/sysimage/boot这个目录存在于根分区文件系统内,根分区没挂载时这个目录本身是空的,后续挂载会失败。

这里我额外强调一点:grub rescue 模式下,/boot分区内的数据是没法通过普通方式读取验证的。但在救援环境的 chroot 后,你可以直接检查文件是否完整:

ls /boot/ ls /boot/grub2/ cat /boot/grub2/grub.cfg | tail -50

重点看三样东西:内核文件vmlinuz-*、内存盘文件initramfs-*、GRUB 模块目录/boot/grub2/i386-pc/(或x86_64-efi/)是否存在且非空。如果是/boot空间写满导致的文件残缺,这时候你已经能看到文件大小异常了,比如initramfs只有几百 KB 而不是正常的十几 MB。

3.3 重建 GRUB 配置并重装引导程序

这是整个修复过程的核心操作。确认分区挂载正确、文件结构完整之后,依次执行以下命令。

第一步,重新生成grub.cfg:

grub2-mkconfig -o /boot/grub2/grub.cfg

执行后你会看到类似Generating grub configuration file ... found linux image: /boot/vmlinuz-3.10.0-1160.xxx.x86_64 ... found initrd image: /boot/initramfs-3.10.0-1160.xxx.x86_64.img ... done的输出。这一步的作用是扫描系统里实际存在的内核文件,生成一个全新的启动菜单配置,把每一个可用的内核都写进grub.cfg。

如果这里输出的是No linux image found,说明你的/boot下根本没有完整的内核文件,需要从安装盘或备份中恢复,这属于另一个层面的数据恢复问题。

第二步,重装引导程序到磁盘:

grub2-install /dev/sda

注意这里是/dev/sda而不是/dev/sda1,因为引导程序要写入磁盘开头的 MBR 区域,不是某个分区内部。如果你用的是 UEFI 模式,执行的是:

grub2-install --target=x86_64-efi --efi-directory=/boot/efi

grub2-install做的事情,是把 GRUB 的 core.img 和模块文件安装到/boot/grub2/下,并把引导入口写入 MBR 或 EFI 启动项。这一步执行成功后,GRUB 就有了完整的自举能力。

第三步,确认grub.cfg里的磁盘路径正确:

grep -E 'set root|search' /boot/grub2/grub.cfg

现在的grub2-mkconfig默认生成的配置用的是 UUID 而非设备名来定位分区,形如search --no-floppy --fs-uuid --set=root xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。UUID 定位的好处是不会受盘符漂移影响,这也是现代 GRUB 配置的标准做法。

如果你的系统盘确实有多个分区且顺序混乱,你需要用blkid查看当前各分区的 UUID,确认grub.cfg里写的 UUID 指向的确实是/boot分区。这个检查只需要一分钟,但能避免重启后再次进入 rescue 模式。

3.4 修复 initramfs 缺少驱动的场景

有一种情况容易被忽略:内核版本升级后,根文件系统所在的磁盘控制器驱动没有被打进新的 initramfs,导致内核能加载但没有驱动去读取根分区,启动卡在dracut阶段,表现也是类似引导失败的症状,但提示文字是dracut:/#或者一动不动。

如果确认是这个原因,在 chroot 环境里重建 initramfs:

dracut -f --regenerate-all

或者指定内核版本:

dracut -f /boot/initramfs-$(uname -r).img $(uname -r)

dracut的作用是根据当前系统的硬件环境重新生成内存盘镜像,把必要的存储驱动包含进去。这里我不展开讲 dracut 的配置细节,但要提醒一件事:如果你用了特殊的 RAID 卡、NVMe 磁盘或者 LVM 卷组,重建 initramfs 时一定要确认对应驱动已经存在于当前内核模块目录中,否则生成的内存盘还是缺驱动。

检查模块是否存在的方法:

find /lib/modules/$(uname -r) -name "*megaraid*" -o -name "*nvme*"

3.5 退出救援环境并重启验证

修复完成后,依次退出 chroot、卸载文件系统、重启:

exit umount /mnt/sysimage/boot umount /mnt/sysimage reboot

拔掉 U 盘,让系统从硬盘启动。正常情况下,你应该看到 GRUB 菜单,选择新内核进入系统。

这里我要特别提醒:重启验证后,别立刻就走。我习惯在进系统后马上执行一次uname -r,确认加载的是新内核;再执行df -h /boot看空间是否健康;最后grub2-mkconfig -o /boot/grub2/grub.cfg再跑一遍,确保启动菜单万无一失。这套“三连”检查做完,才算真正修完。

4. 现场实录:一次从 rescue 到恢复的完整过程

讲完了标准步骤,拿我最近一次真实的服务器故障过程做个对照。这台机器是某数据中心的虚拟化宿主机(代称“模拟项目X”),CentOS 7.7,独立/boot分区,BIOS 引导,系统盘/dev/sda,数据盘/dev/sdb、/dev/sdc。故障起因是例行安全加固要求升级内核版本,从 3.10.0-1160 升到同系列的新小版本。

4.1 故障发生与症状确认

升级命令执行完,uname -r已经显示新内核版本,一切看起来正常。结果一重启,直接掉进grub rescue>,提示符前面带一句error: unknown filesystem。

看到这个报错我心里基本有数了,典型的 GRUB 找不到文件系统。落在(hd0)上去执行ls,输出是(hd0) (hd0,msdos1) (hd0,msdos2),其中(hd0,msdos1)是/boot,(hd0,msdos2)是根分区。理论上分区都在,那问题大概率出在/boot分区内文件或 GRUB 模块上。

我试着手动引导:

grub rescue> set root=(hd0,msdos1) grub rescue> set prefix=(hd0,msdos1)/grub2 grub rescue> insmod normal

结果insmod normal直接报错error: file not found。这就确认了/boot/grub2/i386-pc/normal.mod文件存在性问题,要么文件缺失,要么分区本身就读不了。结合升级内核这个前因,我第一怀疑就是/boot空间写满导致文件写入不完整。

4.2 救援环境下的验证与修复

用同版本的 CentOS 7.7 安装 U 盘启动,进 rescue 模式,chroot 后检查:

df -h /boot # 输出显示 /boot 已用 497M,可用 0B ls -lh /boot/vmlinuz-* /boot/initramfs-*

果然,新内核的initramfs文件只有 1.2M,正常应该 20M 以上,写入过程被空间耗尽打断。而旧内核文件还占着 100 多 M 没清理,新内核文件又是半个残缺品,整个/boot分区一团糟。

先删掉损坏的内核文件腾出空间:

rm -f /boot/vmlinuz-3.10.0-1160.xxx.x86_64 rm -f /boot/initramfs-3.10.0-1160.xxx.x86_64.img

然后重新安装内核包。因为我升级用的方式是直接yum install,rpm 包还在本地缓存里,所以可以重新解包安装:

yum reinstall kernel -y

这一步会重新生成完整的vmlinuz和initramfs。确认文件正常后,按顺序执行grub2-mkconfig和grub2-install:

grub2-mkconfig -o /boot/grub2/grub.cfg grub2-install /dev/sda

重启后系统正常进入 GRUB 菜单,选择新内核启动成功。事后我复盘,根因很清晰:/boot分区切割太小,又缺乏旧内核自动清理机制,一次内核升级直接挤爆了分区。这不是内核或 GRUB 自身的问题,是典型的磁盘空间管理疏漏。

4.3 验证修复效果的实操清单

系统恢复后,我列了一个检查清单,后来成了团队内部处理同类型故障的固定动作:

检查项命令正常指标
当前内核版本uname -r与预期升级版本一致
/boot剩余空间df -h /boot可用空间至少 100M 以上
grub.cfg 是否存在ls -l /boot/grub2/grub.cfg文件存在且大小正常
可用的内核列表grep menuentry /boot/grub2/grub.cfg至少包含新内核和一个保留内核
磁盘 UUID 匹配blkid与grub.cfg对照一致

这套检查做完,心里才踏实。毕竟生产环境重启一次的成本很高,宁可多花三分钟验证,也不要再经历一次大半夜被电话叫醒去机房救火的场景。

5. 常见问题与避坑实录

把这几年的经验集中整理一下,按问题出现频率从高到低排,每个坑我都实际踩过或者排查过,有些甚至修完又复发过。

5.1/boot空间不足引发的一系列连锁问题

这是升级内核后掉进 rescue 模式的头号原因。/boot独立分区如果当初只分了 200M 到 500M,在系统跑了几年后,旧内核不断积累,很容易被两次连续升级写入挤爆。更麻烦的是,yum默认不会自动清理旧内核,需要手动处理。

预防方案有两类:一是定期手动清理旧内核,保留当前版本和上一版本即可:

rpm -qa | grep ^kernel-[0-9] yum remove kernel-旧版本号

二是调整yum的自动清理策略,在/etc/yum.conf里设置keepkernel=2(部分版本支持),或者通过package-cleanup --oldkernels --count=2来控制保留数量,这个命令来自yum-utils包。

如果/boot空间已经告急但还没爆,优先清理旧内核释放空间,再考虑升级操作。千万别在/boot空间不足时执行内核升级,那是给自己埋雷。

5.2 内核升级完成后没有重新生成 grub.cfg

有些升级方式是手动下载 rpm 包然后rpm -ivh,安装过程不会自动触发grub2-mkconfig。结果新内核文件已经在/boot里了,但grub.cfg还停留在旧状态,重启后菜单里根本没有新内核选项,甚至因为配置文件与磁盘状态不一致,GRUB 行为异常直接摔进 rescue。

处理方法也简单,升级完内核务必手动重新生成配置:

grub2-mkconfig -o /boot/grub2/grub.cfg

这个命令在yum install内核后通常会自动执行,但如果你用的是rpm -ivh或者从其他机器拷贝内核文件,手动执行就非常必要。

5.3grub2-install执行成功但重启后仍然进 rescue

这种情况排查方向不在引导安装本身,而在 BIOS 启动顺序。部分机器在硬件变更或 BIOS 重置后,启动顺序会改变,可能导致机器从错误的磁盘尝试引导。在救援环境里执行grub2-install时,要确认你写入 MBR 的磁盘确实是被 BIOS 设置为第一启动项的磁盘。

如果 BIOS 里第一启动项是 U 盘或者另一块空盘,GRUB 装在系统盘上也没用,机器根本没往那块盘上找引导。这时候进 BIOS 检查启动顺序,把目标系统盘调第一,比在系统里反复重装引导程序有效得多。

我处理过一个机房里的案例,服务器重启后莫名进入 rescue,检查后发现是运维同事在 BIOS 里调整了 RAID 卡的启动顺序,导致系统盘从第一启动项变成了第二。这种情况重装十遍引导程序也白搭,归根结底是硬件层面的启动顺序问题。

5.4 双系统或多磁盘环境下的误操作

有些服务器会有多块磁盘,比如系统盘和数据盘各一块。在救援模式 chroot 后执行grub2-install /dev/sda时,如果系统盘实际是/dev/sdb(盘符顺序和平时不一致),你就会把引导装到数据盘上,不仅修不好,还可能让数据盘 MBR 被覆盖。

这个问题的根源,是 Linux 在救援环境下加载磁盘驱动的顺序可能与平时不同,导致盘符漂移。所以执行安装命令前,务必用lsblk -f和blkid确认设备对应关系,不要想当然地认为/dev/sda一定是系统盘。

判断系统盘的另一个技巧是看分区数据内容:挂载后检查有没有/etc、/home、/var等目录结构,有这些的就是系统根分区所在盘,对应的就是系统盘。

5.5 手动引导成功但重启又复现

这种“修好后没几天又挂”的情况,多半是根源没解决。比如/boot空间不足问题没清理,下次再升级内核又会爆;或者根文件系统有文件系统错误,fsck没跑;又或者磁盘本身已经出现坏道,GRUB 模块所在的区域不稳定。

我的处理建议是:只要出现一次 grub rescue,无论多简单修好,都要把硬件健康检查做一遍。用smartctl -a /dev/sda看磁盘健康状况,用dmesg | grep error排查存储相关的内核报错。宁可多花十分钟做全面体检,也不要等第二次救火火烧眉毛。

6. 防患于未然:让系统远离 grub rescue 的三条建议

故障修复再熟练,也不如提前预防来得踏实。结合这些年处理过的引导故障,我给生产环境和重要测试环境定了三条硬性规范,执行到位后,这类问题的发生概率能降低九成。

第一条,/boot分区空间监控必须纳入日常巡检。独立/boot分区的使用率超过 70% 就要告警,超过 85% 必须执行旧内核清理。写个简单的 shell 脚本放 crontab 里,每周跑一次,检查可用空间和处理旧内核,人肉巡检总有一天会忘。

第二条,升级内核前先做引导备份和配置备份。用grub2-mkconfig生成完整配置后,把grub.cfg复制一份到根分区:

cp /boot/grub2/grub.cfg /root/grub.cfg.bak.$(date +%Y%m%d)

同时导出分区表备份:

parted /dev/sda unit s print free > /root/parted_backup.txt

真出问题时,这些备份能帮你快速判断文件是否被改动、配置是否需要回滚。

第三条,升级操作尽量选择非生产时段,并且先做快照或整机备份。虽然虚拟机快照不能替代备份,但在引导故障场景下,快照回滚是恢复系统最快的手段。我处理过的云服务器故障里,有快照的几分钟就能恢复,没快照的往往需要在救援环境里折腾一两个小时。

这三条建议落实起来成本不高,但能避免绝大多数“升级即翻车”的尴尬。尤其是第一条,很多朋友在系统运行几年后才第一次遇到/boot空间告警,那时候再清理已经有些晚了。


最后分享一个我个人的实操习惯:系统恢复后,除了执行前面说的检查清单,我还会顺手做一次“引导链完整性演练”,也就是拔掉所有非系统盘,模拟彻底的硬件环境变更,看系统还能不能正常引导。这个操作在虚拟机上做非常方便,撑死两分钟,但能验证 GRUB 是不是真的完全依赖正确的设备路径,而不是碰巧在默认磁盘顺序下能启动。毕竟,故障恢复的最高境界是“修完之后,再也没在同一个坑里跌倒过”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询