4、批量配置工具:sed/awk批量修改GRUB配置、Ansible自动化管理启动参数、Puppet/Chef在启动参数管理中的应用
说实话,手动改GRUB配置这事,我干过太多次了。早期运维那会儿,几十台服务器要统一加个iommu=pt参数,我愣是一台台重启、进编辑模式、改、保存。后来想想,真是傻得可以。批量配置这件事,说白了就是「把重复劳动交给脚本,把决策留给自己」。
这一章,我带你看看怎么用sed/awk快速搞定单次批量修改,再用Ansible这类工具把启动参数管理纳入自动化体系。嗯,这里有个坑我先说——千万别在生产环境直接跑未经测试的sed命令,我曾经手滑把/etc/default/grub改成了空文件,那场面...不提了。
4.1 用sed/awk快速批量修改GRUB配置
sed和awk,是Linux运维的两把瑞士军刀。处理GRUB配置这种结构化文本,它们比Python更轻量,比Vim更高效。
4.1.1 sed实战:修改GRUB_CMDLINE_LINUX
最常见的场景,就是给GRUB_CMDLINE_LINUX这一行追加或替换内核参数。比如我要在所有机器上加一个mitigations=off(关闭CPU漏洞缓解,提升性能)。
# 在GRUB_CMDLINE_LINUX行尾追加参数
sed -i 's/^GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 mitigations=off"/' /etc/default/grub
# 验证修改结果
grep GRUB_CMDLINE_LINUX /etc/default/grub
这里有个细节:\(.*\)是sed的捕获组,把原有参数原封不动保留,再追加新参数。我习惯先不加-i跑一遍,确认输出正确再真正写入。
GRUB_CMDLINE_LINUX=""),上面的正则匹配不到内容。需要单独处理空行情况。建议先检查:grep -c 'GRUB_CMDLINE_LINUX=""' /etc/default/grub
4.1.2 awk实战:按条件筛选并修改
awk更适合做「条件判断+修改」的场景。比如我只想修改包含quiet参数的主机,去掉quiet以便调试启动过程。
# 去掉GRUB_CMDLINE_LINUX中的quiet参数
awk '/^GRUB_CMDLINE_LINUX=/ {
gsub(/quiet/, "", $0);
# 去除多余空格
gsub(/ +/, " ", $0);
print $0;
next
} {print}' /etc/default/grub > /tmp/grub_new && mv /tmp/grub_new /etc/default/grub
你看,awk的gsub函数直接做全局替换,比sed的s///g更直观。我个人习惯用awk处理多条件逻辑,比如「如果包含quiet且不包含debug,则去掉quiet」——这种逻辑用sed写起来就费劲了。
4.1.3 批量执行与更新GRUB
改完配置文件,别忘了更新GRUB。我一般写个脚本一条龙搞定:
#!/bin/bash
# 批量修改并更新GRUB
for host in $(cat server_list.txt); do
ssh "$host" "
sed -i 's/^GRUB_CMDLINE_LINUX=\"\(.*\)\"/GRUB_CMDLINE_LINUX=\"\1 mitigations=off\"/' /etc/default/grub
grub2-mkconfig -o /boot/grub2/grub.cfg
echo '配置已更新,请手动重启: shutdown -r now'
"
done
reboot。先更新配置,等业务低峰期再统一重启。我曾经半夜被电话叫醒,就是因为脚本自动重启了数据库主库...
4.2 Ansible自动化管理启动参数
当服务器数量超过两位数,ssh循环脚本就不够看了。Ansible才是正经的批量配置工具。它天然支持幂等性——你跑100次和跑1次,结果一样。
4.2.1 用Ansible模块修改GRUB
Ansible有专门的lineinfile模块,比sed更安全:
---
- name: 批量配置GRUB启动参数
hosts: all
become: yes
tasks:
- name: 确保GRUB_CMDLINE_LINUX包含iommu=pt
lineinfile:
path: /etc/default/grub
regexp: '^GRUB_CMDLINE_LINUX='
line: 'GRUB_CMDLINE_LINUX="quiet splash iommu=pt"'
backrefs: no
notify: 更新GRUB配置
handlers:
- name: 更新GRUB配置
command: grub2-mkconfig -o /boot/grub2/grub.cfg
这里用notify触发handler,只有文件真正被修改了才会执行grub2-mkconfig。嗯,这个设计很巧妙——避免每次跑playbook都重新生成GRUB配置。
4.2.2 参数模板化与变量管理
不同环境需要不同参数?用变量分离:
# group_vars/production.yml
grub_extra_params: "mitigations=off iommu=pt"
# group_vars/testing.yml
grub_extra_params: "mitigations=off iommu=pt debug"
# 模板文件 templates/grub.j2
GRUB_CMDLINE_LINUX="quiet splash {{ grub_extra_params }}"
我习惯把quiet splash这种基础参数写在模板里,把环境差异参数放在变量文件。这样改一个环境,改一个变量文件就行,不用动模板。
4.2.3 滚动更新与回滚策略
批量改启动参数最怕什么?改完起不来。Ansible可以配合滚动更新:
---
- name: 滚动更新GRUB配置
hosts: all
serial: 1 # 一次只更新一台
tasks:
- name: 修改GRUB配置
lineinfile: ...
- name: 更新GRUB
command: grub2-mkconfig -o /boot/grub2/grub.cfg
- name: 重启并等待
reboot:
reboot_timeout: 300
register: reboot_result
- name: 验证启动参数
command: cat /proc/cmdline
register: cmdline
- name: 回滚如果参数不对
fail:
msg: "参数验证失败,请手动检查"
when: "'iommu=pt' not in cmdline.stdout"
serial: 1确保一次只处理一台机器。如果这台机器重启后参数不对,playbook会失败,不会继续祸害下一台。我管这叫「慢就是快」。
4.3 Puppet/Chef在启动参数管理中的应用
Ansible适合「推模式」,Puppet和Chef则是「拉模式」的代表。如果你的环境已经用了Puppet/Chef,没必要为了改个GRUB参数再引入Ansible。
4.3.1 Puppet管理GRUB配置
Puppet用augeas模块修改配置文件,比直接sed更安全:
class grub_config {
augeas { 'modify_grub_cmdline':
context => '/files/etc/default/grub',
changes => [
"set GRUB_CMDLINE_LINUX '\"quiet splash iommu=pt\"'",
],
}
exec { 'update-grub':
command => 'grub2-mkconfig -o /boot/grub2/grub.cfg',
refreshonly => true,
subscribe => Augeas['modify_grub_cmdline'],
}
}
Puppet的augeas模块会校验语法,如果改出来的配置不合法,它不会应用。我在项目中遇到过,有人用sed把引号搞丢了,Puppet直接报错,避免了灾难。
4.3.2 Chef管理GRUB配置
Chef用ruby_block或line资源:
ruby_block 'modify_grub_cmdline' do
block do
file = Chef::Util::FileEdit.new('/etc/default/grub')
file.search_file_replace_line(
/^GRUB_CMDLINE_LINUX=/,
'GRUB_CMDLINE_LINUX="quiet splash iommu=pt"'
)
file.write_file
end
notifies :run, 'execute[update-grub]', :immediately
end
execute 'update-grub' do
command 'grub2-mkconfig -o /boot/grub2/grub.cfg'
action :nothing
end
Chef的ruby_block给了你完全的Ruby能力——你可以写正则、做条件判断、甚至调用外部API。但说实话,我建议尽量用line资源,少用ruby_block,因为后者可读性差,新人接手容易懵。
4.3.3 三种工具对比
| 工具 | 模式 | 幂等性 | 学习曲线 | 适用场景 |
|---|---|---|---|---|
| sed/awk | 脚本 | 需手动保证 | 低 | 临时批量修改、小规模 |
| Ansible | 推 | 天然支持 | 中 | 中大规模、无Agent环境 |
| Puppet | 拉 | 天然支持 | 高 | 大规模、已有Puppet基础设施 |
| Chef | 拉 | 天然支持 | 高 | 大规模、Ruby技术栈团队 |
4.4 本章知识体系
下面这张图,帮你理清批量配置启动参数的整体思路:
说白了,选哪个工具取决于你的场景。临时改几台机器,sed/awk一把梭;管理几十上百台服务器,Ansible是首选;如果公司已经上了Puppet/Chef,那就别折腾,直接在现有体系里扩展。
我个人最常用的组合是:日常巡检用sed快速验证,正式变更走Ansible playbook。这样既灵活又可控。嗯,记住一点——无论用哪个工具,改完一定要验证/proc/cmdline,别信配置文件,信内核。
cat /proc/cmdline 查看当前生效的启动参数。如果和配置文件不一致,说明GRUB没更新或者重启没生效。
可可精品资料库