1. 先搞清楚手动装 GRUB 到底在装什么
GRUB 手动安装这件事,很多人第一次遇到都是在系统已经起不来的情况下,对着一个grub rescue>或者黑屏发呆。这时候如果脑子里只有"照着教程敲一遍grub-install",大概率会在第三步就卡住,因为你根本不知道那条命令到底往磁盘里写了什么东西、写到了哪个位置、依赖哪些前置条件。我自己最早踩这个坑,是在把系统从一块老硬盘整体换到新盘之后,克隆工具把分区数据搬过去了,引导却没搬过去,机器开机直接掉进固件设置界面。折腾了大半天才反应过来:数据是全的,缺的是那块磁盘上"让固件能读懂的第一段代码"。GRUB 手动安装的核心价值就在这里——它是你在系统跑不起来、或者目标系统根本不在当前运行环境里的时候,仍然能把引导链条重新接上的手段。这篇内容适合三类人看:正在做系统盘迁移或扩容的运维、装双系统被引导覆盖过的普通用户、以及需要在离线环境里做可启动介质的开发者。零基础也能跟着走,但我会把每一步"为什么这么做"讲透,因为真正能救命的不是命令本身,是命令背后的那套机制。
1.1 从按下电源到内核接管,GRUB 站在第二环
开机这条链路上,GRUB 的位置非常明确。固件(UEFI 或者传统 BIOS)完成自检和硬件初始化后,它的唯一任务就是找到并执行下一段代码;GRUB 就是这段代码,它接手之后要干三件事:把文件系统驱动起来(是的,GRUB 自带一套精简的文件系统读取能力)、找到内核和 initramfs 所在的分区、把内核加载进内存并把控制权交出去。内核起来之后挂载真正的根文件系统,再拉起 init 进程,后面才是我们熟悉的系统。
理解这个顺序很重要,因为它解释了为什么 GRUB 装错了会导致"系统明明完好却进不去"。磁盘上的文件一个都没少,只是第一段代码没放对地方,或者放对了但找不到自己的配置文件,链条在第二环断了。这时候你用任何系统修复工具都显得无从下手,因为问题不在文件系统层面,而在"固件如何读取这块磁盘"的层面。
还有一个容易混淆的点:GRUB 是分两段加载的。第一段极小,小到能塞进固件固定寻找的那几个字节或那个固定路径里;第二段才是完整的引导程序,包含文件系统驱动、菜单界面、命令行等。手动安装的时候,这两个部分要分别落到不同的物理位置上,缺一不可。
1.2grub-install和grub-mkconfig是两件完全不同的事
这是新手最容易搞混的地方,也是我见过最多的"装完还是起不来"的原因。grub-install干的是把引导程序本体按固件的读取方式摆到正确的物理位置;grub-mkconfig干的是扫描当前系统、生成菜单配置文件。前者决定"能不能启动到 GRUB",后者决定"GRUB 起来之后菜单里有没有东西、默认进哪个"。
只跑前者不跑后者,你会看到一个空的或者只有一行grub>提示符的界面;只跑后者不跑前者,配置文件生成了但磁盘上没有能加载它的引导程序,等于白写。两件事必须都做,而且顺序是先装本体、再生成配置,因为配置文件默认要写到/boot/grub/grub.cfg,而这个路径下的模块目录是grub-install铺过去的。
在 UEFI 模式下,grub-install具体做的是:把一个符合 PE 格式的grubx64.efi写进 EFI 系统分区的EFI/<ID>/目录,同时在主板的 NVRAM 里注册一条引导项(BootXXXX),指向这个文件。注意后半句——它不只是写文件,还改了主板里的变量。所以 UEFI 下装 GRUB 有时候会"看起来成功了但重启没变化",原因就是 NVRAM 那一步没成功,比如分区没挂对、或者固件写保护。
在传统 BIOS 模式下,grub-install做的是:把第一段引导代码写进磁盘最前面那段保留区域(MBR 的前 446 字节),把第二段核心镜像写到磁盘上"第一个分区开始之前"的空隙里。这个空隙在 MBR 分区表下通常是 31KB 左右,在 GPT 分区表下不存在,必须单独划一个 BIOS Boot 分区来放。这也是为什么 GPT + Legacy 组合下你必须要有个 1MiB 左右的小分区,不是可有可无的装饰。
1.3 手动装的三种典型触发场景,判断标准不一样
不是所有引导问题都需要手动装,先分清属于哪一类,能省掉大量无用功。
| 场景 | 现象 | 处理方向 |
|---|---|---|
| 系统盘迁移或扩容 | 新盘数据完整,开机找不到系统 | 在新盘上重新执行完整安装流程 |
| 引导被其他系统覆盖 | 装了另一个系统后原系统从菜单消失 | 通常只需重新生成配置并注册引导项 |
| 引导文件损坏或误删 | 开机直接进grub rescue> | 从应急环境进入,重装本体加重建配置 |
| 从零制作可启动盘 | 目标盘没有任何系统 | 需要先部署系统文件,再装引导 |
| 固件模式切换 | 从 Legacy 改 UEFI 后无法启动 | 按新模式重新安装,两种模式互不兼容 |
判断的关键动作只有一个:确认固件当前工作在哪种模式。在已运行的系统里跑一条[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS就能知道。这条判断必须做在当前要安装的目标机器上,不能凭经验猜。我见过太多案例是照着 UEFI 教程在 Legacy 机器上敲,敲完一堆报错,最后发现方向从一开始就错了。
2. 动手前的信息采集与设备规划
手动安装 GRUB 最忌讳的就是"命令敲得快、信息看得少"。这个阶段多花十分钟,能避免后面两小时的反复。信息采集的重点是三块:固件模式与分区表类型、目标磁盘的设备名与分区布局、以及各个分区的 UUID 和文件系统类型。这三块信息决定了后面每一条命令的参数长什么样。
采集这些东西不需要装任何额外工具,应急环境(安装介质启动出来的 live 环境)里自带的命令就够用。我一般的习惯是先把lsblk -f的输出完整看一遍,再对照blkid确认 UUID,最后用分区工具看一眼分区表类型。三个来源交叉验证,避免设备名认错——这是最致命也最常见的失误,/dev/sda和/dev/sdb搞反,把引导装到了数据盘上,白忙一场还算轻的。
2.1 固件模式、分区表类型与磁盘编号的确认方法
先看固件模式。在应急环境里同样适用前面那条判断:/sys/firmware/efi目录存在就是 UEFI 模式启动的。这个判断还有个隐含意义——如果这台机器本身支持 UEFI,但你用 Legacy 方式启动的安装介质,那么你在这个环境里做出来的引导也是 Legacy 的。所以进入应急环境时,启动菜单里选对条目很关键。
再看分区表类型。parted -l或者fdisk -l的输出里,会明确标注Partition Table: gpt或者dos。GPT 和 MBR 的区别不只是容量上限,更直接影响到"第二段引导代码往哪放":MBR 分区表有天然的空隙可用,GPT 分区表必须有个专门的 BIOS Boot 分区,类型码要设成21686148-6449-6E6F-744E-656564454649(这个 GUID 就是 "Hah!IdontNeedEFI" 的十六进制,属于业内一个流传很久的梗,看到不用奇怪)。
最后确认磁盘编号。现在服务器和不少笔记本用的是 NVMe 盘,设备名是/dev/nvme0n1这种形式,分区则是/dev/nvme0n1p1;传统 SATA/SAS 盘是/dev/sda加/dev/sda1。注意 NVMe 的分区名多一个p,这个细节在写命令时漏掉就会报"设备不存在"。另外多盘环境下设备名可能随插拔顺序漂移,所以整个操作过程中建议先拔掉无关的移动存储,或者用/dev/disk/by-id/下的稳定链接来指代磁盘。
2.2 分区布局与容量的取舍逻辑
分区怎么划,直接决定了 GRUB 能不能装得下、装完之后稳不稳。几个关键分区的容量不是拍脑袋定的,背后有明确的计算依据。
EFI 系统分区(ESP)给多大?通行做法是 512MiB 起步。算一笔账:一个内核镜像加对应的 initramfs,在常见发行版上大概占 50 到 120MiB,取决于驱动打包的多少。如果你保留两个旧内核做回滚,就是 240MiB 左右;再算上 GRUB 自己的模块文件(x86_64-efi目录大概 10 到 20MiB)、可能的固件更新文件、以及双系统共存时另一个系统也要往这里写东西,512MiB 的余量其实不算宽裕。我的习惯是直接给 1GiB,多出来的几百兆在整块盘面前几乎可以忽略,但能避免以后内核版本堆积导致的"空间不足装不上新内核"。
BIOS Boot 分区在 GPT + Legacy 组合下是必需品,1MiB 就够,因为第二段核心镜像一般 30 到 50KB,1MiB 有充裕余量。这个分区不需要格式化,也不会有文件系统,它就是一个"裸的存储区域"。注意它的分区类型必须正确设置,设错了grub-install会报找不到嵌入区域。
/boot是否要独立分区?如果你打算用 LVM、软件 RAID 或者全盘加密作为根文件系统,答案是必须要。原因很直接:GRUB 自带的文件系统读取能力有限,它能读 LVM 逻辑卷,但对某些复杂组合(比如 LVM 之上再套加密)就无能为力了,尤其是加密格式较新的版本。这种时候把内核和 initramfs 放在一个独立的、普通 ext4 格式的/boot分区里,GRUB 只需要读这一个简单分区,剩下的解密工作交给 initramfs 里的工具去做,链条就顺了。/boot给 1GiB 是比较稳妥的,同样是为了容纳多个内核版本。
| 分区 | 建议容量 | 文件系统 | 用途说明 |
|---|---|---|---|
| ESP | 512MiB ~ 1GiB | FAT32 | UEFI 模式下的引导文件存放区 |
| BIOS Boot | 1MiB ~ 2MiB | 无 | GPT + Legacy 模式下的核心镜像嵌入区 |
| /boot | 1GiB | ext4 | 独立存放内核与引导配置,兼容复杂存储栈 |
| 根分区 | 剩余空间 | 按需 | 系统主体 |
提示:ESP 的 FAT32 簇大小建议保持默认(通常是 512 字节或 4KiB)。有些工具为了"优化"把簇设得很大,会导致小文件占用大量空间,ESP 这种全是小文件的场景反而吃亏。
2.3 UUID 与挂载点的交叉核对
设备名会漂移,UUID 不会。所以从这一步开始,所有涉及"指代某个分区"的地方,尽量用 UUID 而不是/dev/sdX。查 UUID 用blkid,输出里UUID=后面那串就是。在应急环境里核对的时候,重点看三样:根分区的 UUID、ESP 或/boot的 UUID、以及文件系统类型(TYPE=字段)。
核对的方式是手工验证,不能只看一眼。举例来说,应急环境里把根分区挂到/mnt,把 ESP 挂到/mnt/boot/efi,挂完之后用findmnt或者lsblk再看一遍挂载树,确认每个分区都挂在了它该在的位置。这一步出错,后面grub-install会把引导文件写到一个错误的位置,表面上命令执行成功,重启就是没反应。
还有一个细节:如果目标系统里/etc/fstab用的是 UUID 挂载,那你得确认这些 UUID 和磁盘上实际的一致。系统盘克隆的场景下,克隆工具有时会重新生成 UUID,导致fstab里的条目全部失效,系统起来之后会掉进紧急模式。这种情况在装 GRUB 之前就该修好,否则引导装对了也用不了。
3. 分步实操:把 GRUB 装到目标盘上
前面铺垫的信息采集做完,实操部分其实就是一条有严格顺序的流水线。我把它拆成六步:挂载根分区、绑定虚拟文件系统、切换根环境、安装引导本体、生成配置文件、清理卸载并验证。顺序不能乱,尤其是绑定虚拟文件系统这一步,很多人跳过它直接切根,然后遇到一堆莫名其妙的报错。
3.1 挂载目标系统的分区
应急环境下,所有操作都在内存里跑,目标系统的分区需要手动挂上来。假设我们已经确认根分区是/dev/nvme0n1p2,ESP 是/dev/nvme0n1p1:
mkdir -p /mnt mount /dev/nvme0n1p2 /mnt # 如果有独立的 /boot mount /dev/nvme0n1p3 /mnt/boot # UEFI 模式下挂载 ESP mkdir -p /mnt/boot/efi mount /dev/nvme0n1p1 /mnt/boot/efi挂载顺序有讲究:先挂根,再挂子目录,否则子目录会被根分区的内容覆盖掉。挂完之后用findmnt -R /mnt看一眼完整的挂载树,确认层级正确。
这里有个容易忽略的点:ESP 的挂载路径应该是目标系统里/etc/fstab中记录的那个路径,常见的是/boot/efi,但也有些配置放在/efi或者/boot。如果路径对不上,grub-install会把引导文件写到一个目标系统启动后"看不见"的位置,虽然固件可能还是能加载,但以后的更新和维护会非常混乱。核对方法就是看目标系统的fstab:
grep -i efi /mnt/etc/fstab3.2 绑定虚拟文件系统,这一步不能省
grub-install在运行过程中需要读大量系统信息:它要看/sys/firmware/efi判断当前是哪种模式,要访问/dev下的设备节点去探测磁盘,要从/proc拿挂载信息,还可能要通过/run和一些服务通信。在正常系统里这些都在,但切到目标系统环境之后,这些目录是空的,命令就会各种失败。
for d in dev dev/pts proc sys run; do mount --bind /$d /mnt/$d done/dev/pts单独列出来是因为它是个独立的挂载点,只绑/dev不能覆盖它。如果你用的是 systemd 环境,/run也必须绑,否则某些命令会报 "Failed to connect to bus" 之类的错。这五条挂载做完,再用mount | grep /mnt确认一遍,应该能看到五个 bind 挂载。
注意:绑定
/dev的时候用的是--bind,不是重新挂载一个新的 devtmpfs。这样做的目的是让目标环境看到和当前环境完全相同的设备节点集合,避免设备编号不一致。
3.3 切换根环境并做落点检查
chroot /mnt /bin/bash进去之后第一件事不是急着敲安装命令,而是做三项检查。第一,确认固件模式判断和预期一致:ls /sys/firmware/efi有内容说明是 UEFI 模式。第二,确认引导相关目录存在:ls /boot/grub或者ls /boot/grub2,目录名在不同发行版家族里不一样,Debian 系通常是grub,RHEL 系通常是grub2。第三,确认包管理器里 GRUB 相关的包是装好的,因为grub-install这个命令本身来自这些包。
# Debian 系 dpkg -l | grep grub # RHEL 系 rpm -qa | grep grub2如果发现目标系统里根本没装 GRUB 相关的包(比如是从零手工部署的系统),那得先装包再安装引导。这时候要注意,装包的时候可能因为网络不通而失败,可以先把安装介质里的包源挂上,或者用离线包。这一步不做,后面grub-install会直接报"命令不存在"。
3.4grub-install的参数拆解与执行
这是整个流程里最关键的一条命令,参数随模式不同而变化。先看 UEFI 模式:
grub-install \ --target=x86_64-efi \ --efi-directory=/boot/efi \ --bootloader-id=GRUB \ --recheck逐个解释这些参数的意义,因为很多人是照抄的,出了问题不知道改哪个。
--target指定目标平台。UEFI 下 64 位是x86_64-efi,如果是 ARM 架构的机器则是arm64-efi,这个必须和实际架构对上。传统 BIOS 模式下是i386-pc,注意哪怕是 64 位系统,Legacy 模式的引导平台名仍然是i386-pc,这个是历史遗留命名,不要以为是装错了。
--efi-directory指向 ESP 的挂载点。这个路径必须是"在当前 chroot 环境里能看到 ESP"的路径,也就是说必须是相对 chroot 根目录的路径。如果你在外面挂的是/mnt/boot/efi,进来之后写/boot/efi才对,写成/mnt/boot/efi就错了。
--bootloader-id是 ESP 里的目录名,同时也决定了 NVRAM 里引导项显示的名字。默认值通常是发行版名,我一般改成明确的标识,比如GRUB或者带系统代号的名字,方便多系统共存时区分。这个名字只能包含字母数字和少数字符,不要用中文或空格。
--recheck表示重新探测设备,不管缓存里有什么。这个参数建议每次都带上,尤其在磁盘布局刚刚变动过的情况下,能避免使用过期的设备信息。
如果目标是一块要拿去做移动介质的盘(USB 硬盘、移动固态),加上--removable。这个参数的作用是:把引导文件写到 ESP 的固定回退路径EFI/BOOT/BOOTX64.EFI,这样即使目标机器不读 NVRAM 里的自定义引导项,固件也会按标准回退路径去找。做可启动盘的时候这个是必须的,否则换一台机器可能就启动不了。
再看传统 BIOS 模式,命令形式完全不同:
grub-install --target=i386-pc --recheck /dev/nvme0n1注意这里给的是整块磁盘的设备名,不是分区名。因为 Legacy 模式下引导代码要写到磁盘最前面的保留区域,这个位置不属于任何分区,所以必须指向整盘。写成/dev/nvme0n1p1会报错。这是两种模式在命令形式上最直观的区别,也是新手最容易搞错的地方。
还有一个隐含前提:Legacy 模式下如果磁盘是 GPT 分区表,那个 BIOS Boot 分区必须存在且类型正确。如果不存在,grub-install会报 "embedding is not possible",这时候要么补建分区,要么改用 UEFI 模式——我倾向于后者,因为 UEFI 已经是主流,没必要在 GPT 上硬套 Legacy。
3.5 生成配置文件并检查内容
引导本体装好之后,生成菜单配置:
grub-mkconfig -o /boot/grub/grub.cfgRHEL 系的路径是/boot/grub2/grub.cfg,如果系统用了grub2-mkconfig,命令名也带 2。不确定的话用command -v grub-mkconfig grub2-mkconfig看一眼哪个存在。
这条命令会扫描当前环境里的内核(/boot下所有vmlinuz-*文件)并生成对应的菜单项。如果想让它同时探测其他操作系统(双系统场景),需要确认/etc/default/grub里这一行存在且值正确:
GRUB_DISABLE_OS_PROBER=false较新版本的 GRUB 默认把这个功能关掉了,因为它要在系统里执行外部探测程序,有安全和性能方面的考虑。但双系统用户没有它,菜单里就只有当前系统一项。改完这个变量再跑一次生成命令。
生成之后一定要打开看一眼,不能生成完就重启。重点检查三处:菜单项数量对不对、每个菜单项的root=或者搜索条件指向的 UUID 是不是目标分区、linux那行的内核路径是否真实存在。
grep -E "menuentry|linux |search" /boot/grub/grub.cfg | head -30如果发现search --no-floppy --fs-uuid --set=root后面的 UUID 跟实际不符,说明生成配置的时候探测到了错误的磁盘信息,这时候要回头检查挂载是否正确。
3.6 退出、卸载与首次重启验证
配置生成完,按相反顺序退出和卸载:
exit for d in run sys proc dev/pts dev; do umount /mnt/$d done umount /mnt/boot/efi umount /mnt/boot umount /mnt syncsync这一步不要省,它把内存里还没落盘的写操作强制刷到磁盘,避免拔盘或者立刻重启导致文件不完整。
重启之前在 UEFI 模式下还有个检查动作:efibootmgr -v看一眼引导项列表,确认新装的那条在里面,并且顺序合理。如果新项不在,或者排在很后面,可以用efibootmgr -o调整顺序,或者在固件设置界面里手动调。这一步能提前发现问题,比重启之后抓瞎强得多。
4. 特殊场景的差异化处理
标准流程走完,大部分情况就解决了。但实际工作里遇到的多半不是标准情况,得按场景做调整。下面这四类是我处理得最多的,每一类的处理思路都有明显差异。
4.1 UEFI 与 Legacy 的关键差异对照
把两种模式的差异集中列出来,比分散在流程里讲更清楚。
| 对比项 | UEFI 模式 | Legacy BIOS 模式 |
|---|---|---|
| 目标平台参数 | x86_64-efi | i386-pc |
| 引导文件位置 | ESP 的 FAT32 分区内 | 磁盘最前部保留区加分区空隙 |
| 是否指定整盘 | 不需要,只指定 ESP | 必须指定整块磁盘 |
| NVRAM 引导项 | 需要写入 | 不需要 |
| 必需的小分区 | ESP,FAT32 | GPT 下需 BIOS Boot 分区 |
| 固件查找方式 | 按 NVRAM 项或固定回退路径 | 按磁盘固定扇区 |
| Secure Boot 影响 | 有,可能拒绝加载 | 无 |
表格里最后一行值得单独说。开启了 Secure Boot 的机器,会校验引导程序的签名,未签名的grubx64.efi会被拒绝执行。这种时候标准的grub-install生成的是未签名版本,需要额外的签名流程或者使用发行版提供的已签名组件。判断方法是在固件设置里看 Secure Boot 状态,或者在运行的系统里跑mokutil --sb-state。这个不属于 GRUB 安装本身的问题,但它是"装完没反应"的一个常见原因,排查的时候要想到。
4.2 系统盘迁移后的引导重建顺序
整盘迁移是最常见也最容易出岔子的场景。克隆工具搬的是分区内的数据,复制的是分区表,但引导代码所在的那几个特殊位置——MBR 保留区、分区前的空隙、NVRAM 变量——往往不在克隆范围内,或者克隆了但指向的是旧盘的 UUID。
正确顺序是这样:先完成数据克隆,然后在应急环境里挂上新盘,先把fstab和引导配置里的 UUID 全部改成新盘的实际值,再执行 GRUB 安装,最后生成配置。顺序颠倒的话,安装时探测到的是旧信息,生成的配置里写着旧 UUID,新盘上永远找不到这些分区。
改 UUID 引用的位置有几处,别漏:/etc/fstab、/etc/default/grub里的GRUB_CMDLINE_LINUX(如果有root=UUID=...)、以及加密或 LVM 相关的配置文件。改完统一用blkid核对一遍新盘上每个分区的实际 UUID。
还有一点:如果新旧两块盘同时接在机器上,设备名会更乱。建议的做法是克隆完成之后,把旧盘物理断开或者用echo 1 > /sys/block/sdX/device/delete从系统里移除,只留新盘,再执行安装。这样能彻底避免"装到了旧盘上"这种低级但致命的错误。
4.3 多系统共存时的菜单编排与标识冲突
双系统或者多系统环境下,最典型的问题是"装了新系统,老系统的引导项消失"。原因通常不是老系统坏了,而是后装的那个系统把自己的引导写到了 ESP 的默认路径,把原来的引导文件覆盖了,或者 NVRAM 里的引导项被改成了指向新的。
处理思路是先确认老系统的引导文件还在不在。ESP 里不同系统的引导文件放在不同目录下,EFI/下面每个子目录对应一个系统标识。查看方法:
ls -R /boot/efi/EFI如果老系统的目录还在,文件也在,那只需要在 NVRAM 里加回一条引导项,指向它原来的文件,或者靠在当前系统的 GRUB 配置里加上探测条目。加 NVRAM 引导项用efibootmgr -c,但更稳妥的做法是让每个系统的引导项都独立存在,然后在固件的启动菜单里选择,而不是依赖一层 GRUB 去跳另一层。
如果两个系统的--bootloader-id设成了一样的名字,后装的会直接覆盖先装的同目录文件。这是实打实的冲突,必须改名。多系统环境下我习惯给每个系统一个明确的标识,比如用系统代号加版本号区分,这样在efibootmgr的输出里一目了然。
菜单默认项和等待时间在/etc/default/grub里调:
GRUB_DEFAULT=0 GRUB_TIMEOUT=5 GRUB_TIMEOUT_STYLE=menuGRUB_TIMEOUT_STYLE设成menu才会显示菜单,设成hidden的话要按键才出来,很多人以为菜单没生成,其实是这个变量在作怪。改完这些变量必须重新跑一次生成命令才生效。
4.4 LVM、软件 RAID 与加密根下的特殊处理
这三种存储栈都会给 GRUB 安装增加额外步骤,核心原因只有一个:进入 chroot 之后,这些虚拟设备层需要先被激活,否则 GRUB 看不到里面的分区。
软件 RAID 的情况,chroot 之前要先组装阵列:
mdadm --assemble --scan cat /proc/mdstat如果阵列成员盘状态异常,先处理阵列本身,别急着装引导。装的时候注意 Legacy 模式下要往阵列的每块成员盘上都写一遍引导代码,因为阵列的引导能力取决于每块盘上的引导代码是否完整,缺一块就有单点故障。
LVM 的情况,chroot 之前要激活卷组:
vgchange -ay lvs装 GRUB 的时候,如果根分区在逻辑卷上,Legacy 模式可能报"嵌入区域不可用",这时候必须有独立的/boot分区。UEFI 模式下如果/boot是普通分区、只有根在逻辑卷里,通常没问题,因为引导只需要读/boot。
加密根的情况最麻烦。GRUB 对加密的支持有限,而且较新版本的加密格式(LUKS2)在部分版本的 GRUB 里支持不完整。稳妥的方案是:/boot独立且不加密,加密的只有根分区。这样 GRUB 读明文/boot拿到内核和 initramfs,内核起来之后由 initramfs 里的工具做解密挂载,链条清晰可控。如果坚持全盘加密,得确认 GRUB 版本和加密格式的兼容性,实测下来是这里翻车最多的地方。
注意:涉及加密和 LVM 时,
grub.cfg里的root=参数经常会被写成逻辑卷路径或者加密映射名而不是 UUID。这种写法在设备名漂移之后会失效,建议手工核对一遍,必要时改成root=/dev/mapper/xxx的稳定路径。
5. 常见问题与排查实录
排查引导问题有个基本原则:先确定断在哪一环,再决定修什么。GRUB 自己的命令行其实就是最好的诊断工具,它能把磁盘上的分区一个个列出来、能试着读文件系统、能手动指定内核启动。很多人一看黑屏就想着重装系统,其实九成以上的情况在 GRUB 命令行里敲几条就能救回来。
5.1 卡在grub rescue>提示符的抢救方法
这个提示符出现,说明第一段引导代码(或者固件加载的那个文件)成功运行了,但它找不到能读取完整功能模块的路径,所以只能提供一个极简的命令行。这时候还能用的命令很少:ls、set、insmod、normal。
第一步,看磁盘和分区:
grub rescue> ls (hd0) (hd0,gpt1) (hd0,gpt2) (hd0,gpt3)第二步,逐个试探哪个分区是/boot所在的位置。试探的语法是ls (hd0,gpt2)/,能列出目录内容的就是 GRUB 认得文件系统的分区。如果报unknown filesystem,说明这个分区的文件系统类型 GRUB 当前加载的模块不支持,得靠加载额外模块。
第三步,找到有grub目录的那个分区之后,设置根和前缀:
grub rescue> set root=(hd0,gpt2) grub rescue> set prefix=(hd0,gpt2)/boot/grub grub rescue> insmod normal grub rescue> normalset prefix这一句是最关键的,它告诉 GRUB 去哪里找模块目录。路径要对——如果/boot是独立分区,前缀通常是(hd0,gptX)/grub;如果/boot在根分区下,前缀是(hd0,gptX)/boot/grub。搞错了会报"file not found"。
insmod normal加载正常模式模块,normal进入完整界面。进到菜单之后系统就能起来了,但这只是临时救急,重启之后还会回到 rescue。要彻底解决,必须进系统之后重新跑一遍grub-install和生成配置的命令,把引导本体重新写一遍。
5.2error: unknown filesystem的排查路径
这个报错出现的位置很多,可能是ls的时候,也可能是加载配置的时候。核心含义是:GRUB 尝试读这个分区的文件系统,但它带的那套驱动不认识。
主要原因有三类。第一类是文件系统特性太新,比如某些发行版默认开启了较新的元数据校验特性,而 GRUB 里的驱动版本较老,读不了。第二类是文件系统类型本身不在支持列表里,比如某些压缩文件系统或者特殊配置的写时复制文件系统。第三类是分区实际上被加密或者被 LVM 包了一层,裸分区上没有可读的文件系统。
对应的处理方式:如果/boot能独立出来用最普通的 ext4 并且关掉新特性,问题基本消失;如果不行,就在 rescue 环境下手动insmod ext2试试能不能加载(ext2 驱动在 GRUB 里同时兼容 ext3 和 ext4 的常见情况);再不行就得从应急环境进 chroot,升级 GRUB 到较新版本之后重新安装。这条排查路径我走过很多次,结论很明确:给/boot用简单、保守的文件系统配置,能避免掉大部分这类问题,代价只是损失一点新特性,完全值得。
5.3 装完重启直接进固件设置或者黑屏
这种"看起来装成功了但完全没反应"的情况,在 UEFI 模式下最常见的原因是 NVRAM 引导项没写进去。grub-install输出的日志里如果有 "EFI variables are not supported on this system" 之类的提示,就说明它只写了文件、没写变量。这种情况下固件按自己的顺序找不到引导项,就只能进设置界面。
补救方法是手工加引导项:
efibootmgr -c -d /dev/nvme0n1 -p 1 \ -L "GRUB" \ -l '\EFI\GRUB\grubx64.efi'参数含义:-d磁盘、-p分区号、-L显示名称、-l引导文件在 ESP 内的路径(注意用反斜杠,这是固件路径的写法)。加完之后再跑efibootmgr -v确认。
另一个原因是 Secure Boot 拒绝了未签名的引导文件,现象是黑屏或者直接跳到下一个引导项。判断方式是临时关掉 Secure Boot 再试,如果能起来就确认是这个原因。长期的解决办法是用签名过的引导组件,或者走发行版提供的签名流程。
还有一种情况是--bootloader-id和已有项冲突,导致固件里出现两条同名但指向不同文件的项,固件选了错的那条。这种情况用efibootmgr把多余的项删掉(-b XXXX -B),只留正确的一条。
5.4 高频问题速查表
把上面这些整理成一张表,出问题的时候按现象对号入座,能省掉大量试错时间。
| 现象 | 最可能原因 | 快速验证 | 处理方向 |
|---|---|---|---|
grub rescue> | 前缀路径失效或模块目录丢失 | 用ls逐分区试探 | 设 root 和 prefix,insmod normal |
error: unknown filesystem | 文件系统特性不兼容 | 换分区试探是否正常 | 独立/boot用保守 ext4 |
error: no such device | UUID 指向的分区不存在 | blkid核对实际 UUID | 修正配置里的 UUID 引用 |
| 重启直接进固件设置 | NVRAM 引导项缺失 | efibootmgr -v看列表 | 手工添加引导项 |
| 黑屏无输出 | Secure Boot 拒绝或引导文件损坏 | 关闭 Secure Boot 再试 | 使用签名组件或重新安装 |
| 菜单里只有一项 | 系统探测功能被关闭 | 查/etc/default/grub | 打开探测选项重新生成 |
| 装完命令成功但无变化 | 装到了错误的磁盘 | lsblk核对设备和挂载 | 卸载后重新指定正确磁盘 |
embedding is not possible | GPT 下缺 BIOS Boot 分区 | parted -l看分区表 | 补建分区或改用 UEFI 模式 |
这张表里我最想强调的还是最后一条——"命令成功但无变化"。这个现象特别有欺骗性,因为终端里全是正常输出,没有任何报错,人会本能地认为已经装好了。实际上grub-install只对"它被告知的那块磁盘"负责,如果你在 chroot 环境里没有正确挂载,或者设备名认错了,它照样会认真地把引导装到一个错误的地方然后返回 0。所以每次执行完,我都会用findmnt和lsblk双重确认一遍挂载关系和设备对应关系,这个习惯救过我很多次。
5.5 几个只有踩过才知道的细节
第一个细节:grub-install的执行日志一定要看完,不要只看最后一行有没有报错。它中间会输出探测到的平台、写入的路径、跳过的步骤,这些信息在出问题时是唯一的线索。我一般的做法是把输出重定向到文件里存一份,grub-install ... 2>&1 | tee /tmp/grub-install.log,出了问题回头看。
第二个细节:卸载顺序错了会留下残留。如果先卸载/mnt再卸载/mnt/boot/efi,后者会因为父挂载点已经消失而报"target is busy"。正确的做法永远是从最深层的挂载点开始往上卸。实在卸不掉的时候用umount -l做惰性卸载,但那只适合马上要重启的场景,不适合还要继续操作的情况。
第三个细节:生成的grub.cfg权限要检查。这个文件里可能包含加密相关的参数或者敏感的设备信息,权限过宽不合适。正常的权限是 600 或者 644 且属主是 root,如果发现是其他值,顺手改回来。
第四个细节:UEFI 模式下,ESP 里那个EFI/BOOT/BOOTX64.EFI回退文件和EFI/<ID>/grubx64.efi是两回事。前者是固件找不到 NVRAM 项时的兜底,后者是正常路径。做移动介质必须保证前者存在且正确;装本机系统则主要靠后者。两个都维护好,兼容性最好。
第五个细节:如果目标系统用的是较新的内核和较老的 GRUB 组合,可能出现在 GRUB 阶段读不出内核的情况。这时候不要怀疑磁盘,先看看 GRUB 版本和内核版本的匹配关系,必要时升级 GRUB 到较新版本再重新安装一遍。
我自己在这些年里处理引导问题的体会是,绝大多数"装不上"其实都不是 GRUB 本身的问题,而是前置条件没满足——挂载不对、设备认错、模式判断错、分区没准备好。真正需要钻研 GRUB 内部机制的场合非常少。所以与其把时间花在背命令参数上,不如把信息采集那一步做扎实:固件模式、分区表类型、设备名、UUID、挂载关系,这五样东西确认清楚,后面的命令基本就是照抄,出错的概率会低很多。另外建议养成一个习惯,每次动引导之前先把efibootmgr -v和lsblk -f的输出截图或者存一份,万一搞砸了,至少知道原来的状态长什么样,恢复的时候有据可依。