ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GRUB引导故障全解析:grub>与grub rescue>修复实战指南

GRUB引导故障全解析:grub>与grub rescue>修复实战指南 早上一到机房按下服务器电源泡了杯茶回来发现屏幕上不是熟悉的登录界面而是一个孤零零的grub提示符。遇到这个问题的人当时的心里活动一般都是完了系统是不是挂了。其实这个故障在 Linux 运维和日常使用里非常常见可修复性极高。GRUB 引导加载器还活着只是它一时找不到该加载的配置和内核而已。这篇文章就是把我多年来修这类grub和grub rescue故障的完整思路、命令流程和踩坑经验整理出来适合刚接触 Linux 的新手也适合被双系统、磁盘克隆问题折腾过的老手。1. grub与grub rescue到底意味着什么引导链断在哪个环节1.1 两种提示符的级别不一样别上来就乱敲很多人把grub和grub rescue混为一谈其实这是两个截然不同的阶段处理方式也完全不同。grub rescue是 GRUB 的最小救援模式此时 GRUB 连自己的正常模块比如normal.mod都没找到能用的命令屈指可数主要就是ls、set、insmod、unset这几个。通常是因为 MBR 或 ESP 分区里的引导代码加载到的core.img无法定位/boot/grub目录模块加载失败才会落到这种状态。grub则友好得多。它进入的是命令行模式说明 GRUB 正常模块已经加载成功环境变量也基本可用仅仅是因为grub.cfg配置文件没找到、语法出错或者你开机时手动选择了命令行才停在提示符。此时 GRUB 完全有能力直接加载内核只是需要你手动告诉它内核和 initrd 的位置。所以看到grub我通常松一口气因为它离正常启动只差几步手动命令。1.2 完整的GRUB引导链路每一环都可能成为断点要理解故障出在哪至少得知道 GRUB 正常工作时经历了什么。传统 BIOS 启动模式下开机后固件读取硬盘第一个扇区MBR里的引导代码boot.img这部分空间极其有限它只负责把紧随其后的core.img找出来加载。core.img里有基础的文件系统驱动和模块加载器加载完成后它会去读取/boot/grub里的配置和模块最终读grub.cfg并显示菜单然后按要求加载内核vmlinuz-*和内存磁盘initrd.img-*。UEFI 启动模式则是另一条线固件直接读取 EFI 系统分区ESP里的EFI/ubuntu/grubx64.efi这类引导程序文件再由它读取同分区或/boot下的grub.cfg。无论哪条线只要能进入grub说明引导程序本身已经跑起来了断点基本都在找不到/boot/grub读不到grub.cfg磁盘分区信息与记录不一致这三类问题上。所以我修机的第一步永远是确认这几条链路里哪一环断了而不是盲目重装。1.3 我在实际维修中遇到的高频诱因根据这几年经手的情况出现grub或grub rescue的原因无非这么几类故障现象最常见诱因断点位置开机直接进 grub rescue分区被删除/调整、MBR中的core.img与分区偏移对不上core.img 无法定位 /boot/grub开机进 grub但菜单消失grub.cfg 被改坏、磁盘UUID变化、内核升级后未更新配置grub.cfg 读取失败双系统 Windows 更新后进 grub rescueWindows 更新覆盖了 MBR 引导代码boot.img / core.img 连接断裂克隆磁盘或虚拟机迁移后进 grub分区UUID变化grub.cfg写入的还是旧UUIDroot 参数无法匹配实际分区突然断电后进 grub/boot/grub 目录文件部分写入损坏模块或配置加载失败看到grub别急着怀疑是硬盘坏了。绝大多数情况是配置与真实环境不匹配而不是物理损坏。这也是为什么我说这故障看着吓人实际上非常值得自己动手修一下。2. 应急启动第一招在grub命令行里手动把内核拉起来2.1 先摸清当前环境盘点磁盘、分区和GRUB变量在grub提示符下第一件事不是试各种命令而是先搞清楚当前状态。先敲ls查看固件识别到的磁盘和分区输出格式类似(hd0) (hd0,msdos1) (hd0,msdos2)。这个msdos1表示第一块磁盘的第一个 MBR 分区如果是 GPT 分区表你会看到gpt1之类的标识。接着输入set看当前root和prefix两个变量指到哪里。root是 GRUB 认为的当前启动分区prefix是 GRUB 模块和配置文件的查找路径。如果prefix指向的分区不对后面就算敲了insmod normal也会提示找不到模块。我见过很多人卡在这一步其实只要对照ls列出的分区把prefix设置正确问题就解决了一半。2.2 判断/boot目录到底在哪个分区以及内核文件叫什么这一步的关键是弄清楚根分区和/boot分区的关系。如果你的系统是/boot挂在独立分区上那么 GRUB 菜单里的内核路径就是/vmlinuz-xxx如果/boot只是根分区下的一个目录路径就是/boot/vmlinuz-xxx。判断方法很简单用ls (hd0,msdos1)/查看分区内容能看到vmlinuz-*、initrd.img-*文件的分区就是/boot所在分区。为了快速确认我会用search命令直接按文件查找比如search --no-floppy --setroot -f /vmlinuz这个命令会在所有分区里找名为/vmlinuz的文件找到后自动把root变量指过去。不太确定文件名时可以直接输入ls (hd0,msdos1)/v后按 Tab 键GRUB 会试着补全。在grub环境下 Tab 补全非常有用是我排查路径问题最依赖的功能。2.3 手敲完整启动命令set、linux、initrd、boot四步走找到/boot分区和内核文件名后按顺序执行以下四条命令就能把系统拉起来以 Ubuntu/Debian 系为例set root(hd0,msdos1) linux /vmlinuz-5.15.0-91-generic root/dev/sda1 ro quiet splash initrd /initrd.img-5.15.0-91-generic boot逐条解释一下。set root是把当前的/boot分区告诉 GRUB后面加载内核和 initrd 时都基于这个分区。linux行的第一个参数是内核镜像路径后面的root/dev/sda1是 Linux 内核自己用来挂载根文件系统的参数注意这里指的不是/boot分区而是/所在的根分区这是新手最容易搞混的地方。initrd加载内存磁盘镜像里面包含真正挂载根分区所需的驱动和脚本。最后boot才真正启动。如果你不确定根分区是/dev/sda1还是/dev/sda2可以看分区大小和内容。ls (hd0,msdos1)/能看到etc、usr、home这些目录的才是根分区。路径写错了启动时多半会卡在 Kernel Panic提示VFS: Unable to mount root fs。2.4 启动参数里的UUID法则比设备名更稳的写法设备名依赖内核扫描顺序有时候你加了一块新硬盘原来的/dev/sda可能变成/dev/sdbroot/dev/sda1就失效了。所以等你能进入系统后建议用blkid查看根分区的 UUID再把实际启动命令写成rootUUIDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx的形式。在grub下如果忘了 UUID也可以用search --label --setroot 卷标这种按卷标查找的方式定位根分区。成功boot进入系统后第一件事就是执行sudo update-grub让系统重新生成一份与当前磁盘环境匹配的grub.cfg。如果不做这一步下次开机可能又回到老样子。手动引导只是救命手段不是最终修复。3. 进入系统后的三种修复强度更新配置/重装引导/重建rescue环境3.1 最低强度修复update-grub重新生成配置文件如果故障纯粹是grub.cfg内容损坏、内核列表缺失或者分区 UUID 变化导致的进入系统后用update-grub就能搞定。Debian/Ubuntu 系直接执行sudo update-grubRHEL/CentOS/Fedora 系则是sudo grub2-mkconfig -o /boot/grub2/grub.cfg这个过程会执行os-prober扫描当前磁盘上的所有系统重新生成启动菜单。生成完毕后检查一下输出里是否包含了你的 Linux 内核和 Windows Boot Manager如果是双系统确认一切正常再重启。我习惯重启前先看一眼/boot/grub/grub.cfg或/boot/grub2/grub.cfg的时间戳确认确实是刚刚生成的避免出现命令执行了但写错路径的情况。3.2 中等强度修复grub-install重装引导程序到磁盘如果问题出在引导代码本身比如 Windows 更新覆盖了 MBR光更新配置文件是不够的需要把 GRUB 重新安装到磁盘引导区域。传统 BIOS 模式下执行sudo grub-install /dev/sda sudo update-grub这里要特别注意目标是整个磁盘/dev/sda不是分区/dev/sda1。UEFI 模式下则要指定 EFI 分区位置和目标平台sudo grub-install --targetx86_64-efi --efi-directory/boot/efi --bootloader-idubuntu sudo update-grub--efi-directory指向挂载好的 EFI 系统分区--bootloader-id是显示在固件启动菜单里的名字。有些人在 UEFI 机器上习惯性地输入grub-install /dev/sda命令看似执行成功重启却根本没进 GRUB就是因为 UEFI 启动要靠 ESP 里的.efi文件而不是磁盘传统引导扇区。装完之后可以用efibootmgr -v查看固件里的启动项顺序确认引导项存在。3.3 还在rescue模式时先用insmod normal把完整环境拉回来很多人卡在grub rescue阶段进不了系统其实可以先尝试在救援模式下手动加载正常模块把 GRUB 恢复到完整命令行。方法是在救援提示符下执行set prefix(hd0,msdos1)/boot/grub insmod normal normal前提是你能从ls (hd0,msdos1)/里看到grub目录且里面有normal.mod和i386-pc或x86_64-efi这些模块子目录。prefix必须精确指向模块所在目录。执行normal成功后会回到我们熟悉的grub命令行然后再按第 2 章的方法手动引导系统最后进系统用grub-install重新安装。有一个容易忽略的坑prefix里的路径在/boot为独立分区和/boot为根分区子目录时写法不一样。前者是/grub后者是/boot/grub。如果设错了insmod会提示error: file /grub/i386-pc/normal.mod not found之类的信息。这时候别慌重新审视一下prefix的设置即可。3.4 双系统和UEFI环境下的额外注意事项双系统用户修引导时最容易让 Windows 消失。执行update-grub后如果菜单里没有任何 Windows 选项第一反应是查os-prober是否正常工作。Debian/Ubuntu 的/etc/default/grub里默认没有禁用 os-prober但如果之前有人刻意设置了GRUB_DISABLE_OS_PROBERtrueWindows 不会被识别。改成false或注释掉再update-grub一次。UEFI 机器还容易遇到 Secure Boot 开启导致第三方引导程序被拒载的情况。正常安装 Linux 时系统会通过 shim一个已签名的引导加载器来加载 GRUB但如果你手动grub-install --targetx86_64-efi后重启提示安全启动校验失败多半是引导项直接指向了未签名的grubx64.efi此时要么进固件关闭 Secure Boot要么确保使用发行版自带的签名引导链重新安装。4. 连手动引导都进不去时Live USB chroot 才是最终底牌4.1 哪些情况必须动用Live环境别再死磕命令行手动引导也不是万能的。我遇到过几种情况grub下就算敲对了命令也进不去系统根分区是 LVM 逻辑卷GRUB 缺少 lvm 模块根分区是 LUKS 加密分区需要额外解密步骤内核文件或者 initrd 文件确实已经丢失还有更尴尬的你根本不知道内核准确版本号Tab 补全也补不出来。此时最稳妥的做法是放弃在 GRUB 层面死磕改用 Live USB 启动系统直接进到故障系统里修。Live 环境的价值在于它不依赖你硬盘上的引导链可以完整看到挂载点、分区结构、LVM 卷组、加密分区等真实情况还能通过 chroot 进入故障系统执行原本需要该系统才能完成的修复命令。这也是 Linux 系统比 Windows 更抗造的地方——只要硬盘数据没坏透基本都能拉回来。4.2 用Live环境挂载故障系统挂载顺序决定成败启动 Live USB 进入桌面后打开终端先做侦察sudo lsblk -f sudo blkidlsblk -f会清晰列出所有分区、文件系统类型、UUID 和挂载点比fdisk -l直观得多。结合输出判断哪一个是根分区、哪一个如果有是独立/boot、哪一个如果是 UEFI是 EFI 分区。然后按顺序挂载sudo mount /dev/sda2 /mnt sudo mount /dev/sda1 /mnt/boot # 如果有独立boot分区 sudo mount /dev/sda3 /mnt/boot/efi # UEFI机器挂载ESP分区挂载顺序有讲究必须先挂根分区再在根分区下挂载/boot和/boot/efi顺序反了会导致后续 chroot 时路径混乱。接着绑定虚拟文件系统sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo mount --bind /run /mnt/run这些目录是内核和 systemd 与外部打交道的通道不绑定进去chroot 后执行update-grub时可能因为读不到设备信息而生成错误配置。4.3 chroot进入故障系统重建GRUB挂载完成后chroot 进入故障系统sudo chroot /mnt /bin/bash在 chroot 环境里你看到的就是一个可以正常执行命令的故障系统。接下来按发行版执行重装引导的常规操作。Debian/Ubuntu 系grub-install /dev/sda update-grubRHEL/CentOS 系grub2-install /dev/sda grub2-mkconfig -o /boot/grub2/grub.cfgUEFI 机器需要额外指定 EFI 目录grub-install --targetx86_64-efi --efi-directory/boot/efi --bootloader-idubuntu update-grub执行完exit退出 chroot然后sudo umount -R /mnt卸载所有挂载点重启前记得拔出 Live USB。这里有句经验之谈grub-install成功后不要立刻重启先看输出里是否有Installation finished. No error reported.同时update-grub的输出里确认找到了内核文件。我见过有人grub-install报错没注意就直接重启折腾两轮的。4.4 高级场景LVM、LUKS加密和btrfs子卷的处理如果你的系统用了 LVM 逻辑卷Live 环境里挂根分区前要先激活卷组sudo vgchange -ay sudo lvs然后挂载/dev/mapper/卷组名-逻辑卷名到/mnt注意根参数要写成root/dev/mapper/xxx-yyy。LUKS 加密分区则要先解密sudo cryptsetup luksOpen /dev/sda2 cryptroot解密后挂载/dev/mapper/cryptroot。chroot 进去修复时GRUB 需要能识别加密分区所以grub-install时通常还需要确保cryptodisk相关模块可用以及/etc/default/grub里设置了正确的GRUB_ENABLE_CRYPTODISKy。这一套组合拳在服务器和工作站上很常见手动引导几乎不可能完成所以一定要掌握 Live USB 的 chroot 修复法。btrfs 文件系统如果使用子卷作为根目录挂载时要指定子卷例如mount -o subvol /dev/sda2 /mnt否则看到的是一个看起来缺了很多目录的空壳结构。修复完成后还要确保内核启动参数里有对应的rootflagssubvol才能正常挂载。这些细节在常规教程里很少讲但实际生产环境遇到一次就够你头疼的。4.5 没把握时的兜底工具Boot-Repair一键修复大部分引导故障如果你对命令行没有十足把握或者修复多次仍不成功Boot-Repair 这个工具值得一试。它是个图形化工具专门用于修复引导问题。在 Live 环境里安装运行sudo add-apt-repository ppa:yannubuntu/boot-repair sudo apt update sudo apt install boot-repair boot-repair主界面点Recommended repair即可。它会自动分析引导链重建 GRUB甚至修复 Windows 引导。实测下来对非加密、非 LVM 的标准安装成功率很高基本能做到无人值守修复。它处理复杂分区结构时比较慢需要耐心等待日志滚动完。我个人把它当作兜底工具不排斥使用但更推荐大家在理解原理的基础上手动修复因为这样下次遇到类似问题心里才有底。5. 这些故障基本都是哪些原因攒出来的诱因复盘与日常防护5.1 复盘几台典型故障机的共性规律我修过的grub故障里占比最高的不是 Linux 系统自己出问题而是人为操作和环境变化。一台双系统笔记本Windows 大版本更新后开机直接进grub rescue原因是 Windows 更新重写了 MBR覆盖了 GRUB 的引导代码GRUB 的 core.img 和后续模块之间断了此时 Live USB 里grub-install /dev/sda就能救回。还有一台服务器做整盘克隆后新硬盘代号和分区 UUID 全变了旧grub.cfg里写死的 UUID 匹配不上开机进grub重新生成配置后一切正常。另一种典型是手贱型故障。为了省空间删/boot里的旧内核文件删完没执行update-grub或者执行到一半断电grub.cfg指向的内核路径不存在了。这提醒我一件事内核清理要慎重至少保留一个确实能用的版本删完后第一时间重新生成 GRUB 配置。5.2 防止再犯的几条操作习惯想少进几次grub这几个习惯非常有用。第一修改任何 GRUB 相关配置前先复制一份备份。cp /boot/grub/grub.cfg /boot/grub/grub.cfg.bak不过一秒钟关键时刻能省掉一整个晚上的抢救时间。第二磁盘克隆或虚拟机迁移完成后不要直接重启先blkid对比新旧 UUID再执行一次grub-install和update-grub。很多人迁移后发现起不来一半以上都是 UUID 失配。第三把/etc/fstab、/boot和内核相关的变动都当成高危操作处理做完任何改动都顺手验证一遍。比如执行完update-grub后看一眼输出确认内核条目出现。5.3 做一个随身应急U盘把救机命令背下来应急 Live USB 是每个 Linux 用户都该准备的。我更推荐用 Ventoy 做一个多启动 U 盘里面放 Ubuntu Live、SystemRescue 和 GParted Live 几类镜像基本覆盖了引导修复、分区调整、文件救援的全部场景。U 盘容量不要求很大16GB 足够关键是平时就做好别等问题出现再找安装盘。救机时容易脑子短路尤其在你已经重启三次、同事围观的情况下。我的习惯是把本文第 4 章的 chroot 修复命令整理成一个 markdown 文件放进 U 盘根目录出问题时照抄执行。技术这东西关键时候能稳定复现步骤比什么都重要。5.4 遇到grub后的黄金动作清单把整个排查流程压缩成清单贴出来方便你直接存一下输入ls看有无分区输入set看当前 root 和 prefix。用ls (hd0,msdos1)/定位/boot所在分区用 Tab 补全找内核文件名。按set root、linux ... root/dev/xxx、initrd ...、boot顺序手动引导。进入系统后执行sudo update-grub必要时sudo grub-install /dev/sda。如果手动引导失败直接 Live USB 启动挂载后 chroot 重建引导。全部修完重启前检查update-grub输出里是否包含正常内核条目。按这个顺序走绝大多数grub故障都能在半小时内解决。卡住的地方往往是命令单词拼错或分区识别错误所以多花两分钟确认环境比盲目反复尝试高效得多。做了这么多年 Linux 相关的工作我越来越觉得引导故障是最容易让新手放弃 Linux 的一道坎。它看起来像是整台电脑都废了实际上只是引导链里的一小段信息对不上号。只要你理解了 GRUB 加载内核的完整流程知道 chroot 这个终极手段的存在这类问题就再也不会让你慌张。哪怕将来遇到更复杂的分区结构手册里可能找不到一模一样的答案但排查思路永远是一样的先定位断点再沿着链路把它接回去。
返回列表