先跟你说个我踩过的场景有次给客户升级内核重启后默认进了一个新内核结果网卡驱动没匹配上业务直接断流。当时我人不在机房唯一能远程的通道就是带外管理敲命令必须一次成功。那个时候我才真正把 grubby 的每个参数翻来覆去研究透。这次就把它完整拆开讲清楚特别是修改内核启动参数、调整启动顺序、增删引导条目这三块顺便把网上很少写明白的坑一起盘一盘。这篇文章适合刚接手 Linux 服务器、或者已经在用 RHEL/CentOS/Fedora/openEuler 做运维的工程师。就算你以前只看过 Linux 常用命令大全、没系统学过引导管理按着这里的命令走一遍也能把内核启动项的主动权拿回自己手里。1. grubby 到底是什么它凭什么能管引导项1.1 它不直接改 grub.cfg而是改“生成配置的源头”很多人第一次遇到 grubby 是在改内核启动参数的时候。以前手动改过/boot/grub2/grub.cfg的朋友应该深有体会在那个文件里加一个参数看起来很简单但是下次重新生成配置改动全没了。grubby 不一样的地方在于它操作的是引导条目的“源头”。在旧版 RHEL/CentOS 7 这类系统上grubby 直接维护/boot/grub2/grub.cfg或者 BLS 规范下的/boot/loader/entries/*.conf。在 RHEL 8/9、Fedora、openEuler 这些 BLS 风格的系统上grubby 则是直接修改/boot/loader/entries/下的内核条目文件。也就是说它不是一个事后修补工具而是从根上帮你把引导配置管起来。这样设计有个好处系统的其他工具在重新扫描内核、更新 initramfs 的时候不会轻易把你用 grubby 设置的东西覆盖掉。前提是你别再用 grub2-mkconfig 去重新生成配置文件否则两个工具写同一块地方还是会打架。1.2 和 grub2-mkconfig、grub2-set-default 的关系Grub2 体系里常用的是grub2-mkconfig -o /boot/grub2/grub.cfg它会读取/etc/default/grub以及/etc/grub.d/下的脚本生成一份全新的引导配置。grubby 定位更轻它直接面向“内核镜像 启动参数 默认启动项”这几个点做增删改查不需要你把整个 grub 配置重新生成一遍。打个比方grub2-mkconfig 像是把整个房子重新装修一遍而 grubby 是只换掉某个房间的灯。日常加一个内核参数、调换默认启动的内核完全没必要惊动全屋装修。grub2-set-default和 grubby 的功能有一点重叠但 grubby 是更统一的工具箱既能查、能改、能设默认还能增删条目。1.3 一个命令覆盖“查改设增删”五件事grubby 之所以在学习曲线上一开始会让人发懵是因为它把太多功能集合在一个二进制文件里。但换个角度看这也是它的优势只要记住一套工具几乎所有引导项操作都能完成。常用子命令主要有这些查看状态--info、--default-kernel、--default-index修改参数--update-kernel配合--args、--remove-args设置默认--set-default、--set-default-index添加引导条目--add-kernel删除引导条目--remove-kernel很多内核启动问题的排查链路里这些命令恰好就是全部闭环。2. 动手前先查清楚当前引导项到底是什么状态2.1 三条命令摸清现状不管你想改什么第一步永远是确认当前真实状态。我习惯先敲这三条grubby --default-kernel grubby --default-index grubby --infoALL第一条会直接输出默认内核的完整路径比如/boot/vmlinuz-5.14.0-362.13.1.el9_3.x86_64。第二条输出的是默认条目在 grub 菜单里的索引号从 0 开始数。第三条会把当前所有引导条目都列出来信息最全。如果只想看某个具体内核的情况可以直接指定内核文件grubby --info/boot/vmlinuz-$(uname -r)这里$(uname -r)是当前正在运行的内核版本这样写的好处是无论机器上装了多少内核都能精准查到正在用的那一个。有朋友会问为什么不直接看 grub.cfg因为 grub.cfg 是最终渲染结果一旦系统用了 BLS直接看这个文件往往看不到完整的参数来源。grubby 输出的才是当前引导条目真正生效的配置。2.2 学会看 --info 的输出字段拿一条典型输出来说index0 kernel/boot/vmlinuz-5.14.0-362.13.1.el9_3.x86_64 argsro crashkernel1G-4G:192M,4G-64G:256M,64G-:512M rd.lvm.lvrl/root rhgb quiet root/dev/mapper/rl-root initrd/boot/initramfs-5.14.0-362.13.1.el9_3.x86_64.img titleRocky Linux (5.14.0-362.13.1.el9_3.x86_64) 9.3重点看几个字段index这个条目在引导菜单中的位置grubby --set-default-index就是按这个值来指定默认启动项。kernel内核镜像的实际路径后续--update-kernel、--add-kernel都要以这个路径为锚点。args给内核传的启动参数这里是最核心的修改对象。root根文件系统设备。添加新条目或者改启动参数时这个字段千万别弄错否则内核起来以后挂不上根分区。initrdinitramfs 镜像路径缺失或不对会导致系统无法加载必要的驱动。很多内核启动参数的问题比如 I/O 调度器不生效、串口控制台连不上、内存大页配置丢失最终都归结为args这一行的增删。2.3 查看某个标题对应的索引服务器上装了多套内核或者多系统时经常要确认某个菜单标题排在第几位。可以这样查grubby --infoALL | grep -E ^index|^title或者在 Python 里更精确地解析。不过绝大多数情况下直接看--infoALL输出已经足够不需要额外工具。真正麻烦的是某些发行版默认引导菜单里有“救援模式”“恢复模式”这类隐藏项它们的 index 和用户看到的不一定一致。这时候以grubby --infoALL的输出为准最靠谱。3. 修改内核启动参数加参数、删参数、临时调试3.1 追加参数用 --update-kernel 配合 --args最常见需求是给某个内核追加启动参数。比如服务器要开 IOMMU常见参数是grubby --update-kernel/boot/vmlinuz-$(uname -r) --argsintel_iommuon iommupt这条命令会把参数追加到指定内核的args字段后面。如果想给当前所有内核一次性追加把内核路径换成ALLgrubby --update-kernelALL --argsintel_iommuon iommupt这里有个经验不要随便用--update-kernelALL加调试性参数比如临时开启某个内核的dyndbg应该只加到当前内核或者指定内核上。因为调试完要删如果所有内核都有清理的时候容易漏。新加参数之后可以立刻验证grubby --info/boot/vmlinuz-$(uname -r) | grep args我一般会在重启前把这条输出截图或者记到笔记里方便出问题时对比。3.2 删除参数--remove-args 才是对的做法有些朋友会把内核参数改错或者某个参数在新内核里不再需要。删除参数用的还是--update-kernel但是搭配的是--remove-argsgrubby --update-kernel/boot/vmlinuz-$(uname -r) --remove-argsquiet一次可以同时删多个参数用空格隔开就行grubby --update-kernelALL --remove-argsrhgb quiet注意--remove-args后面跟的是参数名不用带值。如果你想删除一个带值的参数比如ipv6.disable1只需要写--remove-argsipv6.disablegrubby 匹配的是参数名会把完整的ipv6.disable1一并去掉。3.3 临时调试和持久修改怎么选grubby 改的是持久引导配置不是当前运行的内核。当前运行内核如果想临时开启某些 debug 参数比如sysctl能解决的就不改引导参数非要改的就得等下次重启。有一种场景是先用 grub 启动菜单临时编辑测试参数是否有效再写进 grubby重启后出现 grub 菜单时按e编辑当前条目在linux开头那一行末尾手动追加参数按Ctrlx启动这套临时流程非常适合验证参数是否有效。验证完没问题再用 grubby 永久写入。我个人的习惯顺序一直是这样临时试、确认有效、持久化、再次重启确认。跳过验证直接写 grubby出问题后排查面会大很多。3.4 和 /etc/default/grub 的纠缠没有使用 BLS 风格的旧系统上/etc/default/grub里的GRUB_CMDLINE_LINUX是 grub2-mkconfig 生成配置的重要来源。而 grubby 直接作用于当前引导条目两者都有可能影响最终参数。如果在 RHEL/CentOS 7 上又用 grubby 又用 grub2-mkconfig顺序不对就会相互覆盖。我给一个比较稳的操作顺序先编辑/etc/default/grub把长期需要的参数写进去再执行grub2-mkconfig -o /boot/grub2/grub.cfg最后用 grubby 做针对某个内核的定制。日常只针对单个内核调试时优先用 grubby别频繁重新生成 grub.cfg。RHEL 8/9 的 BLS 模式下grub2-mkconfig 仍会读取/etc/default/grub生成新的 BLS 片段如果不想让某些定制条目丢失需要留意自己改的是不是生成源头的文件。这就是为什么很多长期做内核参数管理的工程师最终都默认 grubby 优先。4. 调整默认启动顺序让系统按你的意愿进内核4.1 用 --set-default 或 --set-default-index 指定默认启动项升级内核后默认启动项悄悄变了这是最常见的“意外”。想把默认启动项指定回原来的内核或者指定到新内核命令很简单grubby --set-default/boot/vmlinuz-5.14.0-362.13.1.el9_3.x86_64也可以直接用索引号grubby --set-default-index0两条命令作用一样区别是适用场景。指定内核路径更精确适合内核多、索引容易看花眼的情况。指定索引更快适合你已经从--infoALL里明确看到目标位置的情况。设置完成后确认是否生效grubby --default-kernel grubby --default-index这里有一个注意点grubby 修改的是/boot/grub2/grubenv里的saved_entry变量。grubby --default-kernel返回的是解析后的结果但它不一定等于你手动指定的内核。比如你指定了一个 grub2 菜单里不存在的条目grubby 可能会忽略或者退回默认所以一定要看设置后的输出。4.2 多内核场景别用索引直接用路径服务器上经常留了不止一个内核比如生产环境跑着旧内核为了避免兼容性问题暂时不升级到新版。这时候我强烈建议用路径设置默认项不要用索引。原因很简单系统每次内核更新、安装新内核索引都可能变化。今天索引为 2 的内核可能明天因为新内核插入就变成 3 了。用路径指定则不会出错。另外生产环境建议在确认内核稳定前不要设置 “自动跟随最新内核” 的策略。很多发行版默认会在安装新内核后把默认启动项切到新内核这时候用 grubby 把默认项锁到当前稳定内核非常常见grubby --set-default/boot/vmlinuz-$(uname -r)这行命令意味着“只要我不主动升级内核永远启动当前正在运行的版本”对线上环境很友好。4.3 双系统场景想默认进 Windows 怎么搞装了 Windows 和 Linux 双系统的人经常想默认进 Windows。grubby不是为 Windows 设计的它主要管 Linux 内核但你仍可以通过指定菜单标题或者索引来处理。先看grubby --infoALL找到 Windows Boot Manager 对应的索引然后grubby --set-default-indexN这里的 N 就是 Windows 菜单项的索引。不过要提醒一句双系统场景下 Windows 的引导条目通常不是 vmlinuz 内核grubby 的--set-default-kernel对它无效只能用索引设置。另外如果系统更新后 grub.cfg 重建Windows 条目的 index 可能变化需要重新确认。5. 添加和删除引导条目把内核玩得更灵活5.1 用 --add-kernel 添加自定义引导条目有时候某个内核不在默认引导列表里但你又需要临时进去测试。grubby 可以手动添加grubby --add-kernel/boot/vmlinuz-custom --initrd/boot/initramfs-custom.img --titleMy Custom Kernel --root-device/dev/mapper/rl-root参数含义--add-kernel指定内核镜像路径--initrd指定对应的 initramfs 镜像--title菜单里显示的名字随意起但要能认出是谁--root-device根文件系统所在设备添加之后用grubby --infoALL检查应该能看到新条目。这里有个很容易忽略的点--root-device一定要和系统实际的根分区对得上。在 GRUB 2 下root 参数错误会导致内核启动时挂不上根文件系统直接进紧急模式或者卡在 initramfs。如果你不确定根分区是什么可以先查当前默认条目的 root 字段grubby --default-kernel | xargs grubby --info或更简单grubby --infoALL | grep ^root把正在用的 root 值抄下来加新条目时填一样的最稳。5.2 用 --remove-kernel 清理不需要的引导项内核装多了以后引导菜单越来越长一些老内核完全没人用就可以清理掉。grubby 删除条目的命令很简单grubby --remove-kernel/boot/vmlinuz-old指定路径后grubby 会把它在引导配置里对应的条目删除。如果你愿意也可以一次删多个内核grubby --remove-kernel/boot/vmlinuz-old1 --remove-kernel/boot/vmlinuz-old2执行前建议先做一件事记录当前默认内核。因为如果删掉的恰好是默认内核grubby 会自动把默认项切到剩余的第一个内核这可能是你没想到的变化。5.3 内核文件本身要不要一起删grubby 只负责引导配置层面的移除它不会顺手帮你删/boot下边的内核文件和 initramfs。所以完整删除一个内核通常分两步用grubby --remove-kernel删引导条目用包管理器删内核软件包比如dnf remove kernel-core-xxx如果只用包管理器删除内核现代发行版通常也会同步更新引导配置但有些定制过的条目可能残留。先用 grubby 清理再删软件包是最干净的顺序。在管理大量服务器时我习惯先写个脚本查一遍所有条目再决定删谁避免误删正在使用的内核。6. 常见问题与避坑实录6.1 系统里根本没有 grubby不是所有 Linux 发行版都自带 grubby。Debian/Ubuntu 系的引导管理逻辑不一样通常用update-grub和编辑/etc/default/grub来管理默认没有 grubby。用 Arch 的不需要 grubby直接改 grub.cfg 或/etc/default/grub反而更直接。如果你在 RHEL 系发行版上找不到 grubby一般是因为装的精简版或者容器镜像可以手动安装dnf install grubby我见过不少基于 RHEL 的国产 Linux 镜像和云厂商定制镜像里也保留了 grubby因为它是系统管理工具很多内部初始化流程依赖它。6.2 改了参数重启后完全不生效这是最常见的坑通常有几种原因。第一种你改的是“当前运行内核”但重启后引导的是“另一个内核”。比如默认启动项早就被切到新内核了你却给旧内核加了参数那当然不生效。解决方法是先查grubby --default-kernel确认自己改的目标是不是会被实际启动的内核。第二种修改后又被其他工具覆盖。如果你在修改 grubby 之后又跑了grub2-mkconfig重新生成配置grubby 的定制可能被冲掉。顺序问题一定要留意。第三种BLS 模式下你改的条目文件不是当前默认的 loader entry。检查时可以看grubby --default-index对应的kernel路径和--info里kernel字段确保一致。6.3 BLS 风格下的特殊注意点RHEL 8/9、Fedora 这些系统默认采用 Boot Loader Specificationgrubby 看起来命令没变但背后操作的文件变成了/boot/loader/entries/下的*.conf。这些文件由内核软件包安装和更新时自动生成也会被grub2-mkconfig重新生成。在这种模式下我强烈建议把 grubby 当作主要修改入口而不是直接去编辑/boot/loader/entries/下的文件。直接编辑那个文件虽然也能生效但内核包一更新文件可能会被重新生成你的改动就丢了。grubby 修改时会保留已有参数和内核包的自动更新逻辑兼容性更好。6.4 内核升级后默认引导项被替换很多发行版在安装新内核后会默认把新内核设为默认启动项。这本来是功能但对跑着特殊驱动的生产机来说可能是事故。我遇到的案例是网卡驱动依赖旧内核模块新内核模块还没适配重启后网卡起不来。这种情况下可以这样锁定默认内核grubby --set-default/boot/vmlinuz-稳定版本同时留意/etc/default/grub里的GRUB_DEFAULTsaved配合GRUB_SAVEDEFAULTtrue会让 grub 记住手动选择的启动项。不过 grubby 的设置优先级更高日常管理够用了。6.5 命令速查表操作场景命令示例备注查看默认内核路径grubby --default-kernel最常用于确认现状查看默认项索引grubby --default-index索引从0开始查看所有引导条目grubby --infoALL信息最全给指定内核追加参数grubby --update-kernel/boot/vmlinuz-$(uname -r) --args参数改完记得确认给所有内核追加参数grubby --update-kernelALL --args参数谨慎使用删除指定参数grubby --update-kernel/boot/vmlinuz-xxx --remove-args参数只写参数名不带值设置默认启动项路径grubby --set-default/boot/vmlinuz-xxx推荐用于多内核场景设置默认启动项索引grubby --set-default-indexN适合双系统添加引导条目grubby --add-kernel路径 --initrd路径 --title名称 --root-device设备root-device不能写错删除引导条目grubby --remove-kernel/boot/vmlinuz-xxx不会自动删内核文件验证修改结果grubby --info/boot/vmlinuz-$(uname -r)每次修改后必做我自己的习惯是把这张表贴在笔记里。平时排查问题时先用查询类命令定位再动手修改改完立刻验证。这样就算哪一步出了偏差也能及时回退。7. 再分享几个自己用出来的小经验grubby 这东西平时很少被当成核心知识点讲但真正遇到内核升级翻车、串口控制台参数配错、双系统引导顺序不对时它是能救急的工具。我在生产环境里最常用的其实是那几条查询命令因为不管改什么第一件事永远是搞清当前引导状态。加参数的时候我建议给每个服务器记录一下原始参数和变更原因。grubby 修改的是引导配置一旦有人登录服务器改了参数又没留记录后面的人排查会非常痛苦。比如rd.lvm.lv这类根分区映射参数改动时手一抖系统可能直接起不来。如果你管理的服务器是远程机房进不了本地控制台那改任何引导参数之前都先做一遍确认grubby --infoALL再对照当前默认项确保不会改错目标。加完参数后如果没有特殊原因不要立刻重启空出几分钟把配置再核对一遍。操作后如果要重启验证最好确认带外管理或者 KVM 通道可用这样万一进不了系统还能在看得到启动日志的地方干预。最后提醒一句grubby 不是万能的它管不了 initramfs 里面的内容和内核模块本身。你可以在启动参数里加rd.debug但根因还是要在系统起来以后看日志判断。工具只是把门打开真正的排查还得靠 dmesg、journalctl 这些老朋友。
