4. GRUB2引导加载器:配置文件结构、内核参数传递、签名验证、常见故障场景
好,咱们今天聊聊GRUB2。说实话,在可信启动这条链上,GRUB2是个承上启下的关键角色。它得验证自己,还得验证内核,任何一个环节出问题,机器就起不来。我这些年排查过的启动故障,至少有三成跟GRUB2有关。所以这块内容,你得吃透。
4.1 GRUB2配置文件结构
GRUB2的配置文件,核心就是 /boot/grub2/grub.cfg。但你要注意,这个文件通常不是手写的,而是由 grub2-mkconfig 工具自动生成的。我个人习惯,从来不直接改 grub.cfg,而是改 /etc/default/grub 和 /etc/grub.d/ 目录下的脚本。
为什么?因为 grub.cfg 一更新就会被覆盖,你手动改的东西全没了。我在项目中遇到过有人直接改了 grub.cfg 加内核参数,结果下次内核更新后,参数丢了,系统启动异常。嗯,这是个很典型的坑。
配置文件的结构大致如下:
# /etc/default/grub 核心配置
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
这里我重点说几个:
- GRUB_TIMEOUT:菜单等待时间,单位秒。设为0就直接启动,设为-1就无限等待。我建议调试阶段设成5秒以上,免得手忙脚乱。
- GRUB_CMDLINE_LINUX:这是传给内核的参数,后面会细讲。
- GRUB_ENABLE_BLSCFG:Boot Loader Specification 配置,新版本RHEL/CentOS 8+ 默认开启。如果你发现改了
/etc/default/grub但启动菜单没变,八成是这个在作怪。
而 /etc/grub.d/ 目录下的脚本,执行顺序是按文件名数字来的:
| 脚本 | 作用 |
|---|---|
| 00_header | 加载GRUB环境变量,设置默认配置 |
| 10_linux | 查找当前系统内核,生成启动项 |
| 30_os-prober | 探测其他操作系统(如Windows) |
| 40_custom | 用户自定义启动项,推荐在这里加 |
改完配置后,记得执行 grub2-mkconfig -o /boot/grub2/grub.cfg 重新生成。我曾经见过有人忘了这步,重启后配置没生效,急得团团转。
4.2 内核参数传递
内核参数,说白了就是告诉Linux内核在启动时该怎么干活。你想想看,内核刚启动时啥也不知道,得靠这些参数来配置内存、设备、安全策略等。
参数通过 GRUB_CMDLINE_LINUX 传递,常见的有:
- rhgb quiet:Red Hat 图形化启动,隐藏详细日志。排查问题时建议去掉,能看到完整的启动信息。
- crashkernel=auto:预留内存给kdump用。我遇到过预留太大导致系统内存不足的情况,后来改成手动指定大小。
- console=tty0 console=ttyS0,115200:同时输出到本地终端和串口。服务器调试时特别有用。
- selinux=0 enforcing=0:关闭SELinux。注意,这只是临时调试用,生产环境千万别这么干。
- systemd.unit=emergency.target:直接进入紧急模式,适合修复系统。
这里有个小技巧:你可以在GRUB启动菜单界面按 e 键,临时编辑当前启动项的内核参数。改完后按 Ctrl+x 启动,这次生效,下次重启就没了。非常适合临时调试。
4.3 签名验证
可信启动的核心,就是验证。GRUB2的签名验证分两层:
- GRUB自身验证:由前一级(如shim)验证GRUB的二进制文件和配置文件。
- 内核验证:GRUB验证内核、initramfs的签名。
签名验证的配置在 /etc/grub.d/ 里,但更关键的是BIOS/UEFI里的安全启动设置。如果安全启动开启,但GRUB或内核没签名,系统会直接拒绝启动。
我曾经遇到一个案例:客户说服务器更新内核后起不来了。我过去一看,安全启动是开启的,但新内核没签名。嗯,这就是典型的「更新了内核但忘了签名」的坑。
验证签名的命令是:
# 验证内核签名
mokutil --list-enrolled
# 查看当前内核是否签名
pesign -S -i /boot/vmlinuz-$(uname -r)
# 手动签名内核
pesign -s -i /boot/vmlinuz-xxx -o /boot/vmlinuz-xxx.signed -c /etc/pki/xxx/cert.pem
注意,签名用的证书必须提前注册到MOK(Machine Owner Key)列表中。注册方法是在启动时进入MOK管理界面,或者用 mokutil --import 导入。
4.4 常见故障场景
好了,理论说完了,咱们看看实际中会遇到哪些问题。我按频率排个序:
| 故障现象 | 可能原因 | 排查方法 |
|---|---|---|
| 启动菜单不显示 | GRUB_TIMEOUT=0 或配置文件损坏 | 启动时按住 Shift 键(BIOS)或 Esc 键(UEFI)强制显示菜单 |
| 「File not found」错误 | 内核或initramfs路径不对 | 进入GRUB命令行,用 ls 命令查看分区内容,确认文件存在 |
| 「Verification failed」 | 安全启动开启,但内核未签名 | 检查MOK列表,重新签名内核或关闭安全启动 |
| 「No suitable video mode」 | GRUB图形模式不兼容 | 在配置中设置 GRUB_TERMINAL=console 强制文本模式 |
| 内核panic | 内核参数错误或不兼容 | 在GRUB菜单按 e 编辑,去掉 rhgb quiet 查看详细错误 |
这里我重点说一个我踩过的坑:「/boot 分区空间不足」。内核更新时,旧内核不会自动删除,时间长了 /boot 分区就满了。然后你执行 grub2-mkconfig 时,它写不进去新的配置文件,但也不报错。下次重启,GRUB读的还是旧配置,新内核根本找不到。
排查方法很简单:
# 查看 /boot 分区使用情况
df -h /boot
# 清理旧内核(保留最近2个)
package-cleanup --oldkernels --count=2
另一个常见问题是 GRUB 配置文件语法错误。比如你手写了一个自定义菜单项,但少了个花括号,GRUB解析时会直接跳过整个文件。结果就是启动菜单只剩一个「恢复模式」选项。
怎么避免?我个人习惯是:每次改完配置,先用 grub2-script-check /boot/grub2/grub.cfg 检查语法。这个命令不会生成新配置,只是检查语法是否正确。
核心思路: 遇到GRUB启动故障,先别慌。按这个顺序排查:
- 确认安全启动状态(BIOS/UEFI设置)
- 检查 /boot 分区空间
- 用临时编辑方式查看内核参数
- 检查签名状态
- 查看GRUB配置文件语法
80%的问题都能在这五步里找到答案。
最后,送你一个我常用的GRUB命令行救命技巧:如果系统完全起不来,在GRUB菜单按 c 进入命令行,然后手动引导:
# 查看分区
ls
# 设置根分区(假设是 (hd0,msdos1))
set root=(hd0,msdos1)
# 加载内核
linux /vmlinuz-xxx root=/dev/sda1
# 加载initramfs
initrd /initramfs-xxx.img
# 启动
boot
这个办法能绕过所有配置问题,直接启动系统。等系统起来了,再回头修配置文件。嗯,这招我救过不少次场。