
如果你也试过在 CentOS 7.7 上升级内核重启后没有看到熟悉的登录提示而是黑底白字的grub rescue那这篇内容就是给你准备的。我前几天就在一台生产环境的宿主机上踩了这个坑升级内核本来只是为了修复一个驱动兼容问题结果引导直接丢了连系统都进不去。折腾了几个小时总算把引导链恢复回来系统原封不动。这里把整个过程、背后的原因以及可以提前做好的防护一并整理出来希望对你有实际帮助。1. 为什么会掉进grub rescue先搞清楚引导链路1.1 从BIOS到内核引导过程到底发生了什么机器上电后BIOS或UEFI根据启动顺序把控制权交给磁盘上的引导程序。CentOS 7.7默认使用GRUB2它在传统BIOSMBR磁盘上分两部分安装第一部分叫boot.img写在MBR区域它本身不识别文件系统唯一的任务就是找到同一磁盘剩余空间里的core.img第二部分core.img一般是/boot/grub2/i386-pc/core.img它包含基本的文件系统驱动能读取/boot分区并加载normal模块进而读取/boot/grub2/grub.cfg。grub.cfg里定义了菜单项告诉GRUB要加载哪个vmlinuz和initramfs。一旦升级内核后新的vmlinuz和initramfs文件会被写入/boot同时grub2-mkconfig某些情况下由内核安装脚本触发会生成新的grub.cfg把默认启动项指向新内核。这个链路看起来不复杂但任何一个环节出问题GRUB都无法继续只能丢给你一个rescue提示符。换句话说grub rescue不是系统坏了而是GRUB第二阶段或者grub.cfg没能被正确加载。理解这一点后续的排障思路就会清晰很多你要做的不是去“修内核”而是把GRUB和内核文件之间的路径关系重新理顺。1.2 升级内核后最常见的几个翻车点我在实际处理中把升级内核后进入grub rescue的情形归纳成四类第一新内核文件本身没装完整。比如下载中断、磁盘空间不足导致initramfs没生成或者/boot分区被写满。grub.cfg指向了一个不存在的文件GRUB加载不了内核就会退回rescue。第二grub.cfg没有更新。升级内核后如果没有触发grub2-mkconfig或者配置生成过程出错菜单里还是旧版内核的路径但实际内核文件已经被替换或清理同样起不来。这种情况在通过源码编译内核时特别常见因为make install并不会每次都自动帮你重写grub.cfg。第三分区表或UUID变化。一些清理工具或者手工操作可能会改变分区的UUID而grub.cfg里的rootUUIDxxx是旧的找不到对应分区就卡住。哪怕你只是用第三方分区工具调整了分区大小也可能造成这种问题。第四GRUB核心文件损坏或位置不对。比如安装内核过程中意外断电core.img写一半又比如前一阵子调整过分区大小导致MBR里的boot.img与core.img之间的扇区映射失效。这类问题最隐蔽grub rescue里set了root也经常报错。升级内核这个动作本身不会直接损坏GRUB但会触发一系列与引导有关的文件写入、配置重新生成任何一个环节有偏差都会把你带到rescue界面。换句话说升级内核后的第一个动作不应该是重启而是先检查grub.cfg是否已经正确生成。2. 救援模式下的自救手把手从grub rescue返回正常系统2.1 第一步先别慌确认当前状态看到grub rescue提示符第一时间要做的不是乱敲命令而是判断当前机器是什么引导方式磁盘是什么布局。你可以先敲一个ls不带参数。它会列出GRUB能识别到的所有磁盘和分区形式大概是这样grub rescue ls (hd0) (hd0,msdos1) (hd0,msdos2)如果输出里没有任何分区说明GRUB的磁盘驱动都没法识别硬盘那多半是硬件或固件问题这种后面单独说。如果能看到分区恭喜大部分情况下还有救。接下来用ls加分区路径查看分区内容例如grub rescue ls (hd0,msdos1)它会显示这个分区上的文件系统类型如xfs/ext4以及可见的目录。这一步的目的是确定哪个分区是你的/boot分区。注意GRUB在rescue模式下对分区命名用的是(hd0,msdos1)这种形式hd后面的数字从0开始msdos后面从1开始。对不上没关系挨个试总有一个是正确的。2.2 使用ls命令摸清磁盘分区布局判断/boot分区的核心方法很简单用ls逐一查看每个分区找里面有grub2目录或vmlinuz文件的分区。如果你的系统/boot是独立分区那这个分区的顶层应该就能看到grub2、vmlinuz-xxx、initramfs-xxx如果/boot只是根分区下的一个目录那你需要找到根分区然后在根分区里找boot/grub2。我遇到的一台机器是500G硬盘分区布局为sda1是1G的/boot独立分区sda2是LVM的根卷。在grub rescue里执行ls显示有(hd0,msdos1)和(hd0,msdos2)。ls (hd0,msdos1)之后很快列出了grub2、vmlinuz-3.10.0-1160.el7.x86_64等文件基本可以确认这就是/boot。如果看到的是一个已经挂载的LVM卷往往需要先用insmod lvm加载LVM模块然后通过(hd0,msdos2)访问。例如grub rescue insmod lvm grub rescue ls (hd0,msdos2)处理LVM、RAID、加密盘等复杂存储时先加载对应模块是关键不然看不到里面的内容。这一步做扎实后面的修复基本就是复制粘贴的事。2.3 手动设置root和prefix引导旧内核确定/boot分区后手动设置GRUB的root和prefix变量。以我的机器为例/boot是独立分区且位于第一块盘的第一个分区执行grub rescue set root(hd0,msdos1) grub rescue set prefix(hd0,msdos1)/grub2如果是/boot没有独立分区的情况prefix通常是(hd0,msdos1)/boot/grub2。prefix指向GRUB模块所在目录也就是你看到的grub2目录的位置。设置完prefix后需要加载normal模块才能进入正常的菜单界面grub rescue insmod normal grub rescue normal正常情况下会跳出GRUB菜单这时你就能看到系统里安装过的所有内核列表。如果菜单里只有旧内核可以选择旧内核启动如果菜单里包含新内核但启动仍然失败也不要紧张先选一个能用的旧内核进系统后面再修。如果连normal模块都加载不了或者加载后菜单空白那就只能纯手工引导内核了。这需要你在之前的分区里找到具体的vmlinuz和initramfs文件名然后设置root后手工执行grub rescue set root(hd0,msdos1) grub rescue linux /vmlinuz-3.10.0-1160.el7.x86_64 root/dev/mapper/centos-root grub rescue initrd /initramfs-3.10.0-1160.el7.x86_64.img grub rescue boot这里root参数要写成内核真正要挂载的根设备路径LVM卷、UUID都可以。手工引导的成功率取决于你对系统存储布局的熟悉程度所以前面用ls摸清布局的步骤格外重要。如果你记不住LVM卷组名可以多试几次GRUB不会因为你敲错命令而把磁盘搞坏。2.4 进入系统后立即重建grub配置只要成功进入系统修复就完成一大半了。接下来在shell里重建GRUB配置和核心引导文件。先确认GRUB2的配置文件路径cat /etc/default/grub然后重新生成grub.cfggrub2-mkconfig -o /boot/grub2/grub.cfg如果是UEFI引导路径是/boot/efi/EFI/centos/grub.cfg命令稍有不同grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg之后需要重新把GRUB安装回启动设备。传统BIOS模式下执行grub2-install /dev/sdaUEFI模式下一般不用重复执行grub2-install但如果efibootmgr里没有引导项可能还是要处理一下。做完这两步再检查一下/boot目录里内核文件是否完整然后重启验证。重启前最好把当前正在使用的内核版本记下来万一重启后又进不去至少能清楚自己改了什么。3. 为什么升级内核会导致grub配置失效原理层面的复盘3.1 grub.cfg与内核文件的关系从表面看grub rescue是GRUB找不到路径但深一层的原因是升级内核后grub.cfg里的信息与磁盘实际内容不一致。grub.cfg本质上是一堆GRUB指令的集合里面每一段menuentry都包含几个关键指令load_video加载视频驱动、set root设定根设备、linux指定内核文件路径和内核参数、initrd指定initramfs路径。这些路径和参数是在内核安装时由grub2-mkconfig调用脚本扫描/boot目录后自动生成的。扫描依据是/boot下面实际存在的文件以及系统当前的根设备信息。如果升级内核后新内核的vmlinuz和initramfs文件都齐全grub2-mkconfig一般能正常生成包含新内核的菜单项。但很多自动化脚本在生成菜单时会依赖一个叫blscfg的模块Boot Loader SpecificationCentOS 7.7虽然还不是默认但也可能受影响。一旦脚本异常退出就会留下一个旧的grub.cfg指向已经被覆盖掉的内核文件自然就起不来。我在那台故障机器上看到的正是这种情况新内核文件躺在/boot里但grub.cfg的时间戳还是升级前的菜单内容完全没有新内核的痕迹。这说明升级过程可能只拷贝了内核文件却没有触发grub2-mkconfig或者触发后失败了却没有报错。这类“静默失败”最容易害人因为从文件层面看一切正常但引导配置根本没有更新。3.2 新版内核与旧grub的兼容性问题CentOS 7.7自带的GRUB版本是2.02整体比较老。如果你升级到较新的主线内核比如从ELRepo安装kernel-ml版本直接到4.x甚至5.x新版initramfs里可能会使用一些新格式的压缩或文件特性老版本GRUB识别起来可能会有问题。尤其是当你用了某些第三方工具把内核压缩成zstd格式新内核默认可能是zstd压缩的initramfs而GRUB 2.02在编译时没有启用zstd支持它就读不出来表现为加载initramfs时直接失败或回到rescue。这种情况在社区里讨论过不少。不过要说清楚这不是内核本身的问题而是GRUB与initramfs压缩格式之间的兼容性。解决思路很简单要么升级GRUB用新的bootloader包要么让内核不用zstd压缩initramfs要么就保持在/boot里同时保留一个旧内核并正确配置默认启动项。对于生产环境我始终建议“新旧双内核”策略新内核验证稳定之前绝对不删旧内核。3.3 磁盘分区变化与UUID的影响升级内核过程中某些第三方脚本可能会重做initramfs或者在生成配置时把根设备写成设备节点名如/dev/sda2而不是UUID。如果你机器上有多个相同类型的磁盘重启后设备名可能会变导致内核找不到根。问题就发生在GRUB加载了内核但内核自己挂载根分区时失败表现可能是panic而不是grub rescue两者要区分。另外如果你之前手动改过分区比如用growpart扩容根分区但是没有同步更新/etc/fstab或者grub.cfg里的UUIDGRUB在读取阶段就有可能会失败。在这些场景下grub rescue只是个表象根因是UUID记录已经和磁盘实际信息不一致了。所以排障时手里的fdisk -l和blkid输出非常管用。尤其是blkid它能告诉你每个分区的真实UUID对照着grub.cfg里的内容就能快速找出问题。4. 实操记录一次完整的grub rescue修复过程模拟案例4.1 故障现象描述为了把过程说得更具体我直接还原一次我处理过的真实故障细节做了脱敏但操作路径一样。某台CentOS 7.7服务器两块500G硬盘BIOS引导主板是某品牌服务器。/boot是独立分区sda1ext4根分区在sda2LVM卷组。为了支持新的网卡驱动使用ELRepo仓库安装了kernel-ml-5.4.xxx。安装过程没有报错但重启后直接进入了grub rescue。屏幕上没有任何菜单只有一行提示符。当时看到这个界面我先确认了机器上的数据是否有备份。因为手头有最新的系统备份所以心里稍微稳一点接下来的操作都是只读排查不会破坏现有数据。如果你没有备份也不要慌下面的步骤一样安全但一定要避免在rescue状态乱执行write或install命令。4.2 修复操作全流程先敲ls输出(hd0) (hd0,msdos1) (hd0,msdos2)继续ls (hd0,msdos1)看到了grub2、vmlinuz-3.10.0-1160.el7.x86_64、initramfs-3.10.0-1160.el7.x86_64.img还看到了vmlinuz-5.4.xxx和对应的initramfs。说明/boot分区确认无误而且新旧内核文件都在。问题很可能出在grub.cfg或GRUB核心模块上。执行set root(hd0,msdos1)set prefix(hd0,msdos1)/grub2然后insmod normalnormal结果成功弹出了GRUB菜单。菜单里看到有两个内核选项选中旧内核3.10.0启动。进入系统后第一时间查看/var/log/messages和grub相关日志。使用dmesg | grep -i grub没有明显信息但注意到/boot/grub2/grub.cfg还是旧的时间戳说明内核安装后没有重新生成grub.cfg。也就是说新内核的vmlinuz虽然有但菜单配置压根没更新GRUB在尝试加载默认配置时又因为某种原因失败于是回到了rescue。修复操作很明确grub2-mkconfig -o /boot/grub2/grub.cfg grub2-install /dev/sda执行完后查看grub.cfg里是否包含5.4内核的menuentry确认无误后reboot。这次启动直接进入了GRUB菜单选择5.4内核正常进入了系统。之后又顺手更新了/etc/default/grub把GRUB_DEFAULTsaved加上为后面的多内核切换做准备。4.3 修复后的验证与加固修复不是能开机就结束了。为了确认系统稳定我做了三件事第一检查当前内核版本uname -r第二验证grub.cfg里默认启动项和实际使用的一致grub2-editenv list第三写了一个备份grub.cfg的脚本放到cron里每天凌晨自动把当前grub.cfg复制到/root/backup/。另外我建议在升级内核前先手动执行grub2-mkconfig生成一次基线配置升级后如果新内核有问题还能通过旧内核进场。这里还要多说一句很多人修好grub rescue之后就忘记检查/etc/fstab里是否有UUID引用问题。如果你的根分区也发生了变化即使GRUB能引导内核内核也可能因为找不到根设备而启动失败。所以修复完成后最好执行一遍blkid对照/etc/fstab确保所有挂载项都能对上。5. 常见问题与排查技巧速查表5.1 找不到/boot/grub2/grub.cfg怎么办当你设置好prefix并执行normal后如果GRUB提示找不到grub.cfg通常说明prefix路径设置错了。先再执行ls查看当前分区是否有boot目录。如果/boot不是独立分区但你设成了(hdX,msdosY)/grub2它自然找不到。这时重新set prefix(hdX,msdosY)/boot/grub2即可。还有一种情况分区里有grub2目录但它是空的或者模块文件缺失。这种情况多为之前有人清理过/boot或者GRUB程序包损坏。需要进入系统后用yum reinstall grub2重新安装再grub2-install。如果rescue状态下实在找不到任何grub2目录可以考虑用系统安装光盘启动进入rescue模式那样操作起来更舒服工具也更齐全。5.2 set root后仍然报错no such partition在grub rescue里执行set root(hd0,msdos1)然后ls (hd0,msdos1)也正常但执行normal时却报no such partition这通常是GRUB的core.img无法正常读取分区。原因可能是分区偏移发生变化或者GRUB安装时的扇区位置与当前不符。解决方式是在rescue下重新执行grub2-install不行因为rescue模式下没有grub2-install命令只有进入系统后才能执行。如果暂时进不去系统可以尝试用安装光盘的rescue模式修复。进入rescue模式后chroot到原系统根目录然后执行grub2-install和grub2-mkconfig。很多生产环境恢复都是这样做的。需要注意chroot前要把/boot、/proc、/sys、/dev等目录绑定挂载好具体步骤文档里都有这里不展开。出这种问题时最好也检查一下硬盘SMART信息防止是磁盘坏道导致GRUB核心区域损坏。5.3 修复过程中容易踩的几个坑我在处理这类故障时踩过几个典型的坑列出来给大家参考。第一root和prefix中的磁盘编号写错。比如你有两个硬盘GRUB中的hd0可能不是你认为的第一块物理盘。一定要以ls的输出为准不要凭经验猜。第二把/boot分区当成根分区去设置root。导致后续加载initramfs时linux命令指定的vmlinuz路径不对。这里建议多用ls (hdX,msdosY)/boot/这种形式去确认结构再写路径。第三在rescue模式乱用write命令覆盖MBR。没有十足把握不要执行任何写入型grub命令。第四UEFI机器上修复了grub.cfg却忘了修复EFI引导项重启后还是进不去。UEFI和BIOS的修复方式差异很大一定要先确认引导模式。我见过最惨的例子是有人把grub2-install写到了第二块盘上结果第一块盘还是坏的重启还是起不来。这种低级错误完全可以避免——在运行grub2-install之前先确认当前系统是从哪块盘启动的用lsblk看一下挂载点再做决定。5.4 如何在升级内核前做好备份前面的修复是事后补救但更重要的其实是事前防护。升级内核前我建议至少做三件事。一是把当前grub.cfg复制一份cp /boot/grub2/grub.cfg /root/grub.cfg.bak。二是确认/boot分区有足够空间df -h /boot至少保留200M以上余量。三是在升级时尽量使用官方仓库或成熟第三方仓库对于通过源码编译升级内核的朋友更要在make install之前检查/boot空间并且先备份好旧内核文件。如果升级后新内核有问题需要回退旧内核直接在GRUB菜单里选择旧内核即可。但要注意有些升级脚本会把新内核设为默认同时把旧内核的vmlinuz保留在/boot。只要文件还在旧内核就能用。所以别急着清理旧内核等所有新内核验证稳定了再删除不迟。我个人的习惯是保留最近两个版本的内核既保证能回退也不会占用太多/boot空间。那次grub rescue修复之后我最大的体会是升级内核本身不难难的是升级之后引导链是否完整。现在我在任何服务器上动内核都会先看一眼grub.cfg、确认/boot空间再准备一份光盘或U盘里的rescue环境。这套排查方法后来我给同事讲过很多次照着走基本都能救回来。希望这篇记录能让你在遇到黑屏白字的grub rescue时少走弯路快速找回系统。