Red Hat系Linux内核启动参数管理:grubby工具实战指南
干运维这么多年我见过太多人在grub.cfg上手改内核启动参数重启之后发现配置全丢一脸懵。其实在 Red Hat 系RHEL、CentOS、Rocky、AlmaLinux、Fedora上改引导这件事有专用工具就是标题里说的grubby。它属于系统管理员的基本功专门用来查引导条目、改内核启动参数、调启动顺序、增删引导项最关键的在于它是永久生效、落盘到配置文件的不会因为重启或者重新生成 GRUB 配置就消失。这篇文章不讲花哨的东西就把grubby从查、改、调、增、删这几个核心操作全部捋一遍每个操作都配上实际场景和验证方法顺带把我在生产环境里踩过的坑一起写出来。不管是刚接触 Linux 的新人还是经常维护服务器的人照着做基本不会出岔子。1. grubby 到底是什么先搞清楚你在用的引导工具1.1 Red Hat 系下的引导管理家族grubby不是唯一跟引导有关的工具但它是最适合日常操作的那一层。一般来说Red Hat 系的引导管理分为三层底层是 GRUB2 本体负责真正加载内核配置文件在/boot/grub2/grub.cfgBIOS 机器或者/boot/efi/EFI/redhat/grub.cfgUEFI 机器。中间是grub2-mkconfig它的作用是根据/etc/default/grub和/etc/grub.d/下的脚本重新生成grub.cfg。上层就是grubby它的人设是“引导条目的统一管理入口”直接读当前生效的grub.cfg或者 BLS 配置然后做增删改查。如果你不需要重新生成整套 GRUB 配置只是改某个内核的启动参数、改默认启动项、加一个自定义引导入口那grubby就是最正确的选择。它在底层会自动判断你的机器是 BIOS 还是 UEFI会去找对应的配置文件写入不用你操心路径问题。1.2 为什么不用 vim 直接改 grub.cfg很多人习惯直接 vim 打开grub.cfg改启动参数我专门解释一下为什么这是踩坑行为。grub.cfg是生成出来的文件不是“源文件”。你手动改完天空一声巨响下次内核更新、装机工具触发重新生成 GRUB 配置、或者你手动执行grub2-mkconfig -o /boot/grub2/grub.cfg所有手工改动全部被覆盖相当于白改。还有一个更隐蔽的问题手动改grub.cfg不会同步更新/etc/default/grub里的GRUB_CMDLINE_LINUX变量。于是你会遇到一种很魔幻的情况——grub.cfg里看着参数加上了但系统里“默认内核参数”的源头没变下次生成配置时旧参数又回来了。grubby解决的正是这个问题。它既跟当前的grub.cfg同步也会把改动写入它自己的持久化配置比如/etc/kernel/cmdline或者 BLS 目录下的.conf文件保证前后一致。2. 查清楚再动手查看现有引导条目与内核参数2.1 查看当前默认内核与索引我接手任何一台新服务器第一件事永远是搞清楚当前默认启动的是哪个内核命令只有三个grubby --default-kernel grubby --default-index grubby --default-title--default-kernel返回的是默认内核文件的完整路径比如/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64--default-index返回的是它在引导菜单里的数字编号--default-title返回的是菜单标题也就是启动时界面上显示出来的名字。这三个命令组合起来基本就能确定当前引导菜单的最上层是什么。如果是新安装的系统默认内核通常就是唯一的内核编号为 0。但生产环境往往有多内核并存的情况特别是内核更新后旧内核还留着这时候必须确认默认项到底指向哪个。2.2 查看某个内核条目的详细参数查看所有引导条目的信息用grubby --infoALL输出内容类似这样index0 kernel/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64 argscrashkernel1G-4G:192M,4G-64G:256M,64G-:512M rhgb quiet root/dev/mapper/rl-root initrd/boot/initramfs-5.14.0-362.8.1.el9_3.x86_64.img titleRocky Linux (5.14.0-362.8.1.el9_3.x86_64) 9.3如果只想看默认条目的详情把ALL换成DEFAULT。想知道某个具体内核文件的启动参数也可以直接把内核路径传进去grubby --info/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64拿到这些信息之后你才能判断“当前参数是不是我想要的”以及“如果我要改应该改哪个条目”。这一步相当于动手前的勘查千万别跳过去。2.3 对照 /proc/cmdline 确认当前生效参数有人会问grubby --info里显示的 args 和系统当前生效的参数是不是一回事严格来说/proc/cmdline才是当前内核真正拿到的启动参数grubby --info显示的是配置文件里的“静态参数”。正常情况两者是吻合的但还有一类参数是“运行时合并”进来的。比如通过grub2-set-bootflag、efibootmgr设置的一次性启动参数或者内核在启动过程中自己追加的BOOT_IMAGE字段都会出现在/proc/cmdline里但不一定写进了 grubby 的配置。我建议养成一个习惯改参数前后都执行cat /proc/cmdline看一眼。改完配置不等于生效重启之后确认/proc/cmdline里出现了你想要的内容才算闭环。3. 修改内核启动参数核心场景实操3.1 给指定内核添加参数改参数是grubby最核心的使用场景。比如现在默认内核是 5.14.0-362我要给这个内核追加一个参数mitigationsoffgrubby --update-kernelDEFAULT --argsmitigationsoffDEFAULT是“当前默认内核”的简写等价于自动替换成默认内核路径。也可以直接指定具体内核grubby --update-kernel/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64 --argsmitigationsoff--args的含义是“追加”不是“整体覆盖”。如果这个参数本来不存在它就加上如果已经存在它不会重复添加这一点我实测过多次grubby对参数去重处理得不错。执行完之后可以先看确认grubby --infoDEFAULT看到 args 里已经有了mitigationsoff再重启验证。这里有一个细节需要注意--update-kernel不写后缀时默认操作的是全部内核条目也就是等于ALL。比如直接写grubby --update-kernel --argsquiet会给所有内核都加上quiet而写grubby --update-kernelDEFAULT --argsquiet只操作默认的那个。这个区别特别容易踩坑我见过有人本来只想改单个内核结果所有内核都被加了参数看起来没事但后续排查时非常迷惑。3.2 批量修改所有内核条目有一种合理场景确实需要“所有内核一起改”比如企业安全基线要求所有内核都关闭rd.lvm.lv的某些调试参数或者统一追加审计参数grubby --update-kernelALL --argsaudit1 audit_backlog_limit8192这样每个引导条目都会被追加这两个参数。在 RHEL 8/9 上grubby会把这类全局追加写入/etc/kernel/cmdline你可以直接查看这个文件确认cat /etc/kernel/cmdline这个文件是“系统级内核参数”的持久化位置之一。grubby在更新所有条目时会保证/etc/kernel/cmdline里的内容与当前每个 BLS 条目里的 args 一致。手动改 BLS 文件而不同步这里下次生成配置时又会出现“漂移”。3.3 删除参数与参数保留机制删除参数对应的选项是--remove-args。比如上一节加了audit1现在想撤掉grubby --update-kernelALL --remove-argsaudit1注意--remove-args只接受参数名不需要带值。比如要删crashkernel1G-4G:192M直接写--remove-argscrashkernel就行grubby 会匹配以crashkernel开头的整段参数。有几个参数在 grubby 里被特殊保护即使你用了--remove-args它也不会真的删掉。其中最重要的就是root和initrd这俩属于“引导必需参数”grubby 的逻辑是不允许你通过它删除避免手滑把系统搞到无法启动。如果你真需要动 root 参数那说明你打算改根文件系统路径这是另一个层面的大手术建议小心行事不要用--remove-args硬删。3.4 实战案例禁用默认网卡命名我拿一个真实场景演示完整流程。新装的 CentOS 9 上网卡名变成了enp3s0这种形式但业务脚本里写的是eth0需要禁用一致性网卡命名让网卡回到eth0这种传统命名。需要追加的内核参数是两个net.ifnames0 biosdevname0。只给默认内核加grubby --update-kernelDEFAULT --argsnet.ifnames0 biosdevname0确认grubby --infoDEFAULT | grep args重启后检查ip a cat /proc/cmdline看到net.ifnames0 biosdevname0写进/proc/cmdline并且网卡名真的变回eth0这个操作就算成功了。有一点需要提醒这个参数对命令的验证时机要求非常明确。不是所有参数重启后立刻能看到效果比如网络相关参数要等 systemd-udev 重新枚举设备但/proc/cmdline是重启后立刻生效的。如果你在两个阶段看到的结果不一致优先检查是不是被其他机制覆盖了比如 NetworkManager 的 ifcfg 文件里也设置了NAMEeth0这时候参数是对的但连接配置也要跟着调整。4. 调整默认启动顺序要改就改得干净4.1 三种指定默认启动项的方式调整默认启动项grubby提供三种方式分别对应不同场景用索引指定grubby --set-default-index1用内核文件路径指定grubby --set-default-kernel/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64用菜单标题指定grubby --set-default-titleRocky Linux (5.14.0-362.8.1.el9_3.x86_64) 9.3从可读性角度我最推荐--set-default-kernel。原因很简单索引跟菜单顺序强相关一旦系统里安装了新内核索引可能整体变化标题也可能因为版本号或者系统厂商定制而写得不一样。唯独内核文件路径是稳定且唯一的跟具体的内核版本一一对应。设置完之后用grubby --default-kernel验证一遍确保指向的是你想要的。4.2 与 systemd 默认目标的联动有人会把“默认启动的内核”和“默认启动的目标multi-user.target 还是 graphical.target”搞混。grubby只负责前者也就是选哪个内核后者归 systemd 管systemctl set-default multi-user.target这两个概念是完全独立的你可以默认启动某个旧内核同时默认进入图形界面也可以默认启动新内核但默认进入命令行。生产服务器建议用multi-user.target已经踩过太多因为图形界面占资源导致的性能问题。4.3 grubby 与 /etc/default/grub 的协作关系grubby修改默认启动项时RHEL 8/9 上还会同步更新/etc/default/grub里的GRUB_DEFAULT变量吗这个问题我专门查过文档也实测过。结论是在 BLS 风格的系统上RHEL 8grubby 主要操作 BLS 目录下的.conf文件/etc/default/grub里的GRUB_DEFAULT变得不再那么核心因为 GRUB 会动态识别 BLS 条目。但是如果你手动执行grub2-mkconfig -o /boot/grub2/grub.cfg它依赖的GRUB_DEFAULT设定仍然可能影响整体引导配置的生成逻辑。所以我的建议是日常用 grubby 操作 OK但如果你的习惯是定期重新生成 GRUB 配置先把 grubby 设置好的默认项再同步到/etc/default/grub保持两边一致。具体操作是/etc/default/grub里的GRUB_DEFAULT写成 saved然后执行grub2-set-default也有效。不过既然有了 grubby我更建议统一走 grubby别再新旧工具混着用了。5. 添加与删除引导条目从复制到自己建5.1 添加条目的完整流程与参数说明grubby也能添加全新的引导条目这在测试新内核、做多系统引导时非常有用。核心命令结构是grubby --add-kernel/路径/vmlinuz-版本 --initrd/路径/initramfs-版本.img --title自定义标题 --copy-default --args额外参数实操示例grubby --add-kernel/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64 --initrd/boot/initramfs-5.14.0-362.8.1.el9_3.x86_64.img --titleMy Custom Entry --copy-default --argstestarg1--copy-default的作用是继承当前默认条目的所有参数、root 设置等避免你手动把 root 参数抄错。然后--args再追加自己需要的参数。这个组合非常实用相当于“复制默认配置再改一点”。添加完用grubby --infoALL检查会看到多了一条 index 排在最前面的自定义条目。5.2 删除条目与清理内核文件删除引导条目用grubby --remove-kernel/boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64这里有个重点grubby --remove-kernel只是把“引导菜单里的选项”移除不会把/boot下的内核文件和 initramfs 文件删除。如果确认这个内核完全不需要了还得用包管理器清理dnf remove kernel-core-5.14.0-362.8.1.el9_3.x86_64或者用dnf remove --oldinstallonly清理旧内核。只删引导条目、不删内核文件的后果是/boot分区空间被无谓占用这也是很多服务器/boot满的常见原因。反过来也有另一个坑如果你直接用rm -f /boot/vmlinuz-xxx从磁盘上删了内核文件却没有用 grubby 移除条目那么重启时 GRUB 菜单里会有一个指向不存在文件的“死条目”选进去直接 boot failure。正确的清理顺序是先用 grubby 删条目再用 dnf 删包。5.3 进阶软链接内核与特殊引导场景生产环境还有一种需求需要引导一个不在/boot下的内核文件。比如你在/opt/kernels/放了一个自定义编译的 vmlinuz。grubby 同样支持grubby --add-kernel/opt/kernels/vmlinuz-custom --initrd/opt/kernels/initramfs-custom.img --titleCustom Kernel --copy-default我测试过直接指定非/boot路径是可以的grubby 会把它作为新条目写入。但这里有一个兼容性问题很多系统的 GRUB 在以 BLS 模式启动时要求内核路径必须是/boot下的路径否则可能进不去。稳妥做法是在/boot下创建软链接ln -s /opt/kernels/vmlinuz-custom /boot/vmlinuz-custom ln -s /opt/kernels/initramfs-custom.img /boot/initramfs-custom.img然后再用软链接路径添加。这个细节在现场救过我一次写在这里省得大家走弯路。6. 实操记录一次完整的内核参数调整全流程6.1 环境信息以下是我在测试环境的一次完整操作记录系统是 Rocky Linux 9.3内核版本 5.14.0-362.8.1.el9_3.x86_64。需求是给默认内核追加spectre_v2on和slab_nomerge两个安全加固参数同时确认默认启动顺序没变。6.2 操作步骤与验证第一步记录初始状态grubby --default-kernel /boot/vmlinuz-5.14.0-362.8.1.el9_3.x86_64 grubby --infoDEFAULT | grep args argscrashkernel1G-4G:192M,4G-64G:256M,64G-:512M rhgb quiet第二步添加参数grubby --update-kernelDEFAULT --argsspectre_v2on slab_nomerge第三步确认配置grubby --infoDEFAULT | grep args argscrashkernel1G-4G:192M,4G-64G:256M,64G-:512M rhgb quiet spectre_v2on slab_nomerge第四步重启系统正常进入后检查生效情况cat /proc/cmdline BOOT_IMAGE(hd0,gpt2)/vmlinuz-5.14.0-362.8.1.el9_3.x86_64 root/dev/mapper/rl-root ro crashkernel1G-4G:192M,4G-64G:256M,64G-:512M rhgb quiet spectre_v2on slab_nomerge参数出现在/proc/cmdline里说明已经由内核接收并生效。这里有个小技巧不要只看 grubby 返回的内容一定要看/proc/cmdline因为这是内核真正认到的参数。6.3 回滚方案万一加了参数导致启动异常回滚路径是这样的启动时在 GRUB 菜单按e编辑命令行手动去掉刚才加的spectre_v2on slab_nomerge按Ctrlx启动。进入系统后再执行grubby --update-kernelDEFAULT --remove-argsspectre_v2on slab_nomerge grub2-mkconfig -o /boot/grub2/grub.cfg这里特别强调一下回滚时执行grub2-mkconfig -o /boot/grub2/grub.cfg是没问题的因为你要“整体恢复默认生成逻辑”。但如果只是日常改参数千万不要没事就重新生成 grub.cfg会让 grubby 的增量控制失效反而引入不一致。7. 常见问题与排查技巧实录7.1 修改了参数但重启后没生效这是被问得最多的问题。场景是这样的执行了grubby --update-kernelDEFAULT --argsxxxgrubby --infoDEFAULT也显示参数在但重启后cat /proc/cmdline里没有。排查思路按顺序走确认操作的内核就是实际启动的内核grubby --default-kernel和uname -r对应上别改了默认内核启动的其实是从救援模式进去的另一个内核。确认 UEFI 机器有没有双份配置有些机器既有/boot/grub2/grub.cfg又有/boot/efi/EFI/redhat/grub.cfggrubby 一般会同步但不排除固件里引导入口指向了另一份。看是否被 One-shot 启动项干扰grub2-set-bootflag设置的一次性启动参数只对下一次启动有效之后恢复原状。最后的大招是把问题拆开验证grubby --infoALL逐个看每个条目的 args 是否包含你要的参数。如果只有默认条目有其他没有而实际启动的是其他条目那自然看不到效果。7.2 UEFI 与 BIOS 场景的差异grubby本身会自动适配 UEFI 和 BIOS但从业者心里要有数。BIOS 机器上配置文件是/boot/grub2/grub.cfgUEFI 机器上是/boot/efi/EFI/redhat/grub.cfg且在 RHEL 8/9 上还会涉及 BLS 目录/boot/loader/entries/。如果你在 UEFI 机器上手动编辑了 BIOS 路径的 grub.cfg改完发现不生效那太正常了——你改的文件根本不在引导链路里。用 grubby 就不用担心这个问题它会自己判断。但排查问题时我建议先确认当前是 UEFI 还是 BIOS[ -d /sys/firmware/efi ] echo UEFI || echo BIOS这个命令简单高效建议先跑一下。7.3 修改后系统无法启动的紧急恢复如果改的内核参数导致系统起不来优先推荐救援模式而不是重装。思路是在 GRUB 菜单按e进入编辑找到linux行删掉有问题的参数按Ctrlx启动。如果机器连 GRUB 菜单都进不去按Esc或者从引导 U 盘进入 rescue 模式挂载根文件系统后再用 grubby 把对应 BLS 配置里的问题参数清掉。这个方法我在真实故障里用过两次非常可靠。关键是不要慌先恢复启动再说等系统能进去了再老老实实用grubby --remove-args把问题参数删干净。7.4 grubby 在 CentOS 6 / GRUB Legacy 下的区别CentOS 6 上也有grubby但底层是 GRUB Legacy不是 GRUB2所以用法有一些差异配置文件是/boot/grub/grub.conf而不是/boot/grub2/grub.cfg。不支持 BLS没有/boot/loader/entries/。--infoALL的输出格式与 RHEL 7 略有不同但字段差不多。--update-kernelALL的行为类似但需要自己注意确认落盘文件。如果你维护的机器既有 CentOS 6 又有 CentOS 9建议每次操作 grubby 之前先看一眼前缀版本grubby --version不同版本虽然大框架一致但细节上有不少差异别把一个环境的经验无脑照搬到另一个环境。比如 CentOS 6 上--default-title的输出不带gnu/linux前缀导致脚本里解析菜单标题时容易出错这种细节差一不留神就坑人。写在最后我现在每次给 Red Hat 系服务器改内核参数第一反应就是 grubby不会再直接去翻 grub.cfg。它比我最初想象的要可靠得多特别是在 BLS 架构的 RHEL 8/9 上grubby 基本上是“唯一的正道”——因为你手动改 BLS 下的.conf文件改了头顾不了尾而 grubby 能帮你把所有关联文件一次性同步干净。如果你刚开始接触 grubby我建议先从--infoALL开始把你手头机器的全部引导条目过一遍搞清楚默认项是哪个、哪些旧内核该清理、参数列表里有没有遗留的调试项。等心里有数了再动手改--args或者调--default-kernel这时候你会发现很多“奇怪问题”其实都是因为一开始没看清楚自己机器上到底是什么状态。这套工具链用熟了之后内核参数调整、默认启动顺序切换、自定义引导条目添加这些事都能在几分钟内稳准狠地完成而且每一步都可以随时复查、随时回滚。这才是生产环境里该有的操作方式。