在CentOS 7和CentOS 8的运维工作中,调整内核启动参数是一项高频操作。不管是关闭安全加固、调整内存分配,还是指定硬件驱动黑名单,直接编辑/etc/default/grub再重生成配置的传统方式,在批量管理或脚本化运维时显得笨重且容易出错。grubby这个命令行工具就是为精准修改特定内核的启动参数而生的,它能直接操作/boot/loader/entries下的启动条目,不依赖完整的grub2-mkconfig重建流程,效率高且不易引发配置漂移。

grubby的核心定位与适用场景

grubby在RHEL/CentOS生态中主要用于管理bootloader配置条目。它不是grub2的替代品,而是一个专注于单个内核条目参数增删改查的辅助工具。在需要给某个特定内核版本添加crashkernel=auto、rd.break或systemd.unified_cgroup_hierarchy=0这类参数时,grubby可以直接定位到对应条目,无需手工解析复杂的grub.cfg。这在排查启动问题、临时禁用某个内核功能、或者批量部署标准化内核参数时特别实用。

查看当前可用内核及参数

在动手修改之前,先搞清楚系统里有哪些内核以及它们当前的启动参数。执行以下命令可以列出所有内核条目:

grubby --info=ALL

这条命令会输出每个内核的index、kernel路径、initrd路径、root设备以及args字段。args字段就是我们要修改的启动参数。如果只想看当前默认启动的内核信息,可以简化为:

grubby --default-kernel
grubby --info=$(grubby --default-kernel)

输出中args那一行可能会很长,包含了root=、ro、rhgb quiet等默认参数。注意观察这些参数,确认你要添加或删除的内容是否已经存在,避免重复操作。

添加新的内核启动参数

最常见需求是给默认内核追加参数。比如要关闭透明大页,可以添加transparent_hugepage=never:

grubby --update-kernel=DEFAULT --args="transparent_hugepage=never"

这里DEFAULT是关键字,代表当前默认启动的内核。如果想给所有已安装内核都加上这个参数,把DEFAULT换成ALL即可:

grubby --update-kernel=ALL --args="transparent_hugepage=never"

需要同时添加多个参数时,把它们放在同一对引号内,用空格分隔:

grubby --update-kernel=DEFAULT --args="audit=0 selinux=0"

添加参数时grubby会自动处理空格和引号,不会重复添加已经存在的参数。如果参数已经存在但值不同,新值会覆盖旧值,这一点需要特别注意。比如原本有audit=1,执行--args="audit=0"后,最终参数会变成audit=0。

删除指定的内核启动参数

某些场景下需要移除某个参数,比如之前加了nomodeset,现在显卡驱动问题解决了要去掉它:

grubby --update-kernel=DEFAULT --remove-args="nomodeset"

删除操作同样支持DEFAULT和ALL两种模式。可以一次删除多个参数:

grubby --update-kernel=DEFAULT --remove-args="nomodeset rdblacklist=nouveau"

需要注意的是,删除参数时grubby只做精确匹配。如果参数带有值,必须完整写出参数名和值才能删除。比如要删除audit=0,不能只写--remove-args="audit",必须写成--remove-args="audit=0"。这个细节在实际操作中很容易踩坑,导致删除不成功还找不到原因。

修改已有参数的值

grubby没有直接的修改参数命令,但可以通过组合删除和添加来实现。比如把crashkernel从auto改成512M:

grubby --update-kernel=DEFAULT --remove-args="crashkernel=auto" --args="crashkernel=512M"

这条命令会先删除crashkernel=auto,再添加crashkernel=512M,最终效果就是修改。注意顺序不能反,如果先添加再删除,新添加的参数会被立即删掉。另外,如果原参数没有值只有参数名本身,比如quiet,删除时直接写quiet即可,不需要等号。

针对特定内核版本操作

生产环境中经常保留多个内核版本,有时只需要修改某个特定版本。可以用内核文件的完整路径来指定:

grubby --info=/boot/vmlinuz-4.18.0-348.el8.x86_64
grubby --update-kernel=/boot/vmlinuz-4.18.0-348.el8.x86_64 --args="maxcpus=4"

也可以使用内核版本号的部分匹配,grubby会自动找到匹配的内核条目。但为了精确性,建议使用完整路径。在CentOS 8中,内核文件通常位于/boot/vmlinuz-<version>,而启动条目配置文件在/boot/loader/entries/目录下,文件名是长串的机器ID加内核版本。

修改内核启动顺序和默认内核

除了参数调整,grubby还能设置默认启动内核。当需要固定使用某个老内核时:

grubby --set-default=/boot/vmlinuz-4.18.0-305.el8.x86_64

设置完成后可以用grubby --default-kernel验证是否生效。这个操作会修改/etc/default/grub中的GRUB_DEFAULT或直接修改bootloader的saved_entry。对于使用UEFI引导的CentOS 8系统,grubby会正确更新/boot/efi/EFI/centos/grubenv文件中的saved_entry变量。

验证参数是否生效的完整流程

修改完参数后,必须确认两件事:配置文件已更新,以及重启后内核实际使用了新参数。先检查配置层面:

grubby --info=DEFAULT | grep args

这条命令直接输出当前默认内核的完整启动参数,肉眼确认修改是否成功写入。如果参数中包含空格或特殊字符,输出中会正确显示。接着可以查看实际的内核命令行,在系统运行时执行:

cat /proc/cmdline

这个文件显示的是当前运行内核实际接收到的启动参数。如果刚修改完还没重启,这里看到的还是旧参数。必须重启系统后再次检查,才能确认新参数真正生效。重启后执行:

cat /proc/cmdline | tr ' ' '\n' | grep transparent_hugepage

如果返回transparent_hugepage=never,说明参数已正确传递到内核。对于某些需要在内核启动早期生效的参数,比如crashkernel、rd.break,通过/proc/cmdline验证是最可靠的方式。

通过sysfs和内核接口验证参数效果

有些内核参数会在运行时通过sysfs暴露状态,可以进一步验证参数是否真的起了作用。以transparent_hugepage为例:

cat /sys/kernel/mm/transparent_hugepage/enabled

输出中括号包围的就是当前生效的策略,如果是[never]说明参数生效。再比如audit=0,可以通过auditctl -s检查审计子系统状态。对于selinux=0,可以用getenforce确认是否处于Disabled模式。这种双重验证机制在关键系统上非常重要,避免因参数拼写错误或与其他参数冲突导致预期外的行为。

grubby操作的实际文件变化

了解grubby到底修改了哪些文件,有助于在出问题时手工恢复。在CentOS 8中,grubby主要操作/boot/loader/entries/目录下以机器ID命名的.conf文件。每个文件对应一个内核条目,内容格式类似:

title CentOS (4.18.0-348.el8.x86_64) 8
version 4.18.0-348.el8.x86_64
linux /vmlinuz-4.18.0-348.el8.x86_64
initrd /initramfs-4.18.0-348.el8.x86_64.img
options root=UUID=xxx ro crashkernel=auto resume=UUID=xxx rhgb quiet

grubby修改的就是options这一行。同时,如果修改了默认内核,还会更新/boot/efi/EFI/centos/grubenv或/boot/grub2/grubenv中的saved_entry变量。在传统BIOS引导的CentOS 7上,grubby会直接编辑/boot/grub2/grub.cfg中对应menuentry的linux行参数。理解这些底层文件的位置,可以在grubby出现异常时直接手工修正。

常见问题与排错思路

问题一:修改后重启发现参数没生效。先检查grubby --info输出是否确实包含了新参数,如果没有,可能是命令执行时指定了错误的内核路径。如果配置文件正确但/proc/cmdline不对,可能是系统启动时选择了其他内核条目。用grubby --default-kernel确认默认内核是否是你修改的那个。

问题二:参数被重复添加或出现冲突值。这种情况多发生在多次执行--args操作时。grubby不会去重,如果同一个参数出现两次,内核通常取最后一个值。建议修改前先查看当前参数,用--remove-args清理干净后再添加。

问题三:CentOS 7和CentOS 8行为差异。CentOS 7的grubby版本较老,对DEFAULT和ALL关键字的支持可能不完整,建议直接使用内核文件路径。CentOS 8的grubby功能更完善,但在某些小版本中可能存在bug,比如对BLS(Boot Loader Specification)条目的处理异常。遇到问题可以升级grubby包到最新版本。

问题四:UEFI和传统BIOS的区别。UEFI系统的启动配置更复杂,涉及/boot/efi分区。grubby在UEFI系统上修改默认内核时,需要确保/boot/efi分区已挂载,否则会报错。如果/boot/efi未挂载,先mount再操作。

脚本化批量管理的最佳实践

在管理数十台甚至上百台CentOS服务器时,通过Ansible或Shell脚本调用grubby是标准做法。一个健壮的脚本应该包含以下步骤:先备份当前内核参数配置,再执行修改,然后验证配置写入,最后设置标志位等待维护窗口重启。示例片段:

#!/bin/bash
KERNEL=$(grubby --default-kernel)
cp /boot/loader/entries/*.conf /tmp/backup/
grubby --update-kernel=$KERNEL --args="audit=0 selinux=0"
if grubby --info=$KERNEL | grep -q "audit=0"; then
    echo "参数添加成功"
else
    echo "参数添加失败,请检查"
    exit 1
fi

对于需要重启生效的参数,务必在脚本中做好标记,比如在/etc/motd中添加提醒,或者通过监控系统设置维护窗口。不要在没有人工确认的情况下自动重启生产服务器。

与grub2-mkconfig的关系和选择

很多运维人员习惯直接编辑/etc/default/grub然后运行grub2-mkconfig -o /boot/grub2/grub.cfg。这种方式在需要统一修改所有内核参数时依然有效,但它会完全重建grub.cfg,如果之前有过手工调整可能会丢失。grubby的优势在于精准修改单个条目,不影响其他内核配置,而且操作可逆。对于日常的参数微调,优先使用grubby;对于大范围调整或修改GRUB_CMDLINE_LINUX这种全局变量,再用grub2-mkconfig。两者可以配合使用,互不冲突。

安全注意事项和回滚策略

修改内核启动参数有风险,错误的参数可能导致系统无法启动。操作前务必确认:有控制台访问权限或带外管理,知道如何通过单用户模式或救援模式恢复。如果修改的是生产环境,先在测试机上验证。对于特别关键的参数,可以考虑先在新内核上测试,保留一个已知良好的旧内核作为回退选项。grubby不会删除内核,所以即使新参数有问题,重启时在grub菜单选择旧内核即可恢复。在CentOS 8中,默认的grub菜单超时时间可能很短甚至隐藏,提前修改/etc/default/grub中的GRUB_TIMEOUT确保有足够时间选择内核。

掌握了grubby的正确用法,内核参数管理就从手工编辑变成了精确的命令行操作,既减少了人为失误,又便于审计和自动化。每次修改后严格执行验证流程,把配置检查和运行时检查结合起来,才能确保系统按预期行为运行。