1. 为什么Rocky Linux 9.1的网络配置不能照搬CentOS 7经验?
刚接手一台新部署的Rocky Linux 9.1服务器时,我下意识敲出vi /etc/sysconfig/network-scripts/ifcfg-ens33——结果发现目录压根不存在。这不是手误,而是整个网络配置范式发生了根本性迁移。Rocky Linux 9.1作为RHEL 9的社区克隆版本,彻底弃用了传统的network-scripts服务,转而全面拥抱NetworkManager作为唯一官方支持的网络管理框架。这个变化不是“可选升级”,而是强制切换:systemctl disable network后,传统脚本将完全失效;nmcli命令不再只是辅助工具,它成了网络配置的唯一入口。
这种转变背后是RHEL生态十年演进的必然结果。NetworkManager从RHEL 6时代起就作为实验性组件存在,到RHEL 8已成默认方案,而RHEL 9则完成了最终切割。其核心优势在于动态适应能力——当物理网卡热插拔、USB网卡接入、Wi-Fi切换或容器网络注入时,NetworkManager能实时重绘网络拓扑,而传统ifup/ifdown脚本只能处理静态场景。更关键的是安全模型重构:NetworkManager与firewalld、SELinux深度集成,所有网络操作自动触发策略校验,避免了旧方案中iptables规则与防火墙策略脱节的经典问题。
但代价也很真实。我见过三位资深运维在迁移初期集体踩坑:有人用ip addr add手动配置IP后,NetworkManager检测到“未托管接口”自动将其DOWN掉;有人修改/etc/sysconfig/network-scripts/文件却始终不生效,因为NM根本不去读这些废弃路径;还有人试图用systemctl restart network重启服务,结果得到“Unit network.service not found”的报错。这些都不是操作失误,而是对底层架构变更缺乏认知导致的系统性误判。
提示:Rocky Linux 9.1的网络配置必须遵循“NM优先”原则——所有操作都应通过
nmcli或nmtui完成,任何绕过NetworkManager的直接修改(包括ip命令、sysctl参数调整)都可能被NM自动覆盖或触发冲突。这不是技术偏好问题,而是系统设计的硬性约束。
理解这个前提,才能真正读懂后续所有配置逻辑。比如设置静态IP时,你不是在“给网卡写地址”,而是在向NetworkManager提交一个连接配置(connection profile),这个profile包含IP、网关、DNS、路由等完整网络意图,并由NM持续守护其状态。这解释了为什么nmcli connection modify命令需要同时指定ipv4.addresses、ipv4.gateway、ipv4.dns和ipv4.method manual——缺一不可,因为NM要求声明完整的网络契约,而非零散参数。
2. NetworkManager实战:从基础连接管理到生产级网络拓扑构建
2.1 连接对象的本质:理解connection profile的生命周期
NetworkManager的核心抽象是“连接”(connection),它并非简单的配置文件,而是一个具有状态机的网络意图实体。执行nmcli connection show列出的所有条目,本质是NM数据库中持久化的连接定义,每个连接包含三类关键属性:
- 标识层:
connection.id(人类可读名称)、connection.uuid(全局唯一ID)、connection.interface-name(绑定物理接口) - 配置层:
ipv4.method(auto/manual/disabled)、ipv4.addresses(CIDR格式)、ipv4.gateway、ipv4.dns等 - 行为层:
connection.autoconnect(开机自启)、connection.autoconnect-priority(多连接时的激活顺序)、connection.metered(是否计费网络)
我曾遇到一个典型故障:服务器重启后网络不通,nmcli device status显示接口为unmanaged。排查发现connection.interface-name被错误设置为eth0,而实际设备名是ens192(VMware虚拟网卡命名规则变化)。NM因找不到匹配接口,拒绝激活该连接。解决方案不是改/etc/sysconfig/文件,而是执行:
nmcli connection modify "System ens192" connection.interface-name ens192 nmcli connection up "System ens192"这里的关键洞察是:connection profile与物理设备的绑定关系是动态维护的,UUID才是连接的真正身份凭证,interface-name只是运行时匹配条件。
2.2 静态IP配置的完整链路:从创建到验证
以Rocky Linux 9.1最小化安装环境为例,假设需为ens192配置静态IP192.168.10.50/24,网关192.168.10.1,DNS8.8.8.8。以下是经过生产环境验证的七步操作链:
创建新连接(避免修改默认连接引发意外):
nmcli connection add type ethernet con-name "Prod-Static" ifname ens192此命令生成UUID并注册连接,但此时连接处于
deactivated状态。配置IPv4参数(必须一次性设置method,否则NM拒绝后续地址配置):
nmcli connection modify "Prod-Static" ipv4.method manual \ ipv4.addresses 192.168.10.50/24 \ ipv4.gateway 192.168.10.1 \ ipv4.dns "8.8.8.8,114.114.114.114" \ ipv4.ignore-auto-routes yes \ ipv4.ignore-auto-dns yesignore-auto-*参数至关重要:它阻止DHCP获取的路由/DNS覆盖手动配置,这是Rocky 9.1中常见的静默覆盖源。禁用IPv6(生产环境常见需求,避免双栈干扰):
nmcli connection modify "Prod-Static" ipv6.method disabled启用连接自动激活:
nmcli connection modify "Prod-Static" connection.autoconnect yes激活连接(触发NM全量应用配置):
nmcli connection up "Prod-Static"验证网络连通性(分层检查):
# 检查接口状态 ip addr show ens192 | grep "inet " # 测试网关可达性 ping -c 3 192.168.10.1 # 测试DNS解析 nslookup google.com # 检查路由表 ip route | grep "^default"持久化验证(模拟重启场景):
systemctl restart NetworkManager # 等待10秒后检查连接状态 nmcli connection show "Prod-Static" | grep "connection.state:"
注意:
nmcli connection down命令不会删除连接,仅断开当前会话;若需彻底移除,必须使用nmcli connection delete "Prod-Static"。生产环境中建议为每个连接命名时加入环境标识(如Prod-Static、Dev-DHCP),避免名称冲突。
2.3 复杂网络场景的NM实现:Bonding与VLAN
当面对高可用或网络分段需求时,NetworkManager提供了原生支持,无需依赖内核模块手动配置。以双网卡bonding为例(mode=802.3ad,LACP聚合):
# 创建bond主接口 nmcli connection add type bond con-name "Bond-Prod" ifname bond0 bond.options "mode=802.3ad,miimon=100" # 添加slave网卡(需先删除原有连接) nmcli connection delete "System ens192" nmcli connection delete "System ens224" nmcli connection add type bond-slave con-name "Bond-Slave1" ifname ens192 master bond0 nmcli connection add type bond-slave con-name "Bond-Slave2" ifname ens224 master bond0 # 为bond配置静态IP nmcli connection modify "Bond-Prod" ipv4.method manual \ ipv4.addresses 10.10.10.100/24 \ ipv4.gateway 10.10.10.1 \ ipv4.dns "10.10.10.10" \ ipv4.ignore-auto-routes yes # 启用连接 nmcli connection up "Bond-Prod"此方案的优势在于:NM自动处理bonding参数同步、slave状态监控、故障切换(当ens192断开时,NM在3秒内将流量切至ens224),且所有配置持久化存储于/etc/NetworkManager/system-connections/目录下,符合RHEL 9的安全审计要求。
对于VLAN划分,NM同样提供简洁语法:
# 在bond0上创建VLAN 100 nmcli connection add type vlan con-name "VLAN100" dev bond0 id 100 nmcli connection modify "VLAN100" ipv4.method manual \ ipv4.addresses 172.16.100.10/24 \ ipv4.dns "172.16.100.1" nmcli connection up "VLAN100"NM会自动创建bond0.100子接口并配置802.1Q标签,无需手动加载8021q模块——这是RHEL 9内核与NM深度集成的体现。
3. firewalld深度管控:从端口放行到区域策略精细化
3.1 firewalld的区域模型:理解zone的语义层级
firewalld的区域(zone)不是简单的规则容器,而是预定义的安全策略模板。Rocky Linux 9.1默认启用public区域,但其规则集(/usr/lib/firewalld/zones/public.xml)仅开放SSH、DHCP客户端等基础服务。生产环境常需自定义区域,例如为数据库服务器创建db-server区域:
# 创建新区域 firewall-cmd --permanent --new-zone=db-server # 设置默认目标(DROP所有未明确允许的流量) firewall-cmd --permanent --zone=db-server --set-target=DROP # 允许MySQL端口(注意:必须指定协议) firewall-cmd --permanent --zone=db-server --add-port=3306/tcp # 允许特定IP访问(白名单模式) firewall-cmd --permanent --zone=db-server --add-source=10.10.20.0/24 # 将网卡绑定到该区域 firewall-cmd --permanent --zone=db-server --change-interface=ens192 # 重载配置 firewall-cmd --reload关键点在于--set-target=DROP:它改变了区域的默认行为。public区域的目标是DEFAULT(即ACCEPT未匹配规则的流量),而db-server设为DROP后,所有流量必须显式放行,这是纵深防御的核心实践。
3.2 动态端口检查与服务调试技巧
当应用无法访问时,“检查端口是否开通”常被简化为firewall-cmd --list-ports,但这极易遗漏关键信息。正确诊断流程应分三层:
确认端口是否在firewalld中注册:
# 查看当前区域所有开放端口 firewall-cmd --list-ports # 检查特定端口状态 firewall-cmd --query-port=8080/tcp验证端口是否被服务真正监听(常被忽略的环节):
# 检查进程绑定 ss -tuln | grep ":8080" # 或使用netstat(需安装) dnf install net-tools -y && netstat -tuln | grep ":8080"我曾遇到案例:firewalld显示8080开放,但
ss命令无输出——根源是应用未启动,而非防火墙问题。测试端口可达性(排除网络层干扰):
# 本地测试(排除防火墙影响) curl -v http://localhost:8080 # 远程测试(需从另一台机器执行) telnet 192.168.10.50 8080若
telnet超时但curl localhost成功,则问题在firewalld或网络路由;若两者均失败,则聚焦应用层。
实操心得:使用
firewall-cmd --direct添加临时规则时务必谨慎。例如firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 8080 -j ACCEPT会绕过zone机制,导致规则在重载后丢失。生产环境应坚持--permanent参数,确保配置持久化。
3.3 服务富集:将自定义应用注册为firewalld服务
当部署Nginx、Redis等非标准服务时,直接开放端口存在管理隐患。firewalld支持服务富集(service enrichment),将应用抽象为可复用的服务单元:
# 创建服务定义文件 cat > /etc/firewalld/services/nginx-custom.xml << 'EOF' <?xml version="1.0" encoding="utf-8"?> <service> <short>Nginx Custom</short> <description>High-performance web server with custom SSL port</description> <port protocol="tcp" port="443"/> <port protocol="tcp" port="8080"/> <module name="nf_conntrack_ftp"/> </service> EOF # 重载firewalld服务列表 firewall-cmd --reload # 在public区域启用该服务 firewall-cmd --permanent --zone=public --add-service=nginx-custom firewall-cmd --reload此方案优势显著:服务定义集中管理,--add-service命令自动处理端口+模块依赖,且可通过firewall-cmd --info-service=nginx-custom查看完整配置。相比硬编码端口,它提升了配置可读性与可维护性。
4. SELinux策略调优:从禁用陷阱到精准布尔值控制
4.1 SELinux的三种模式辨析与生产选择
Rocky Linux 9.1默认启用SELinux的enforcing模式,但许多管理员第一反应是setenforce 0临时禁用——这埋下了严重隐患。SELinux有三种运行模式:
- Enforcing:强制执行策略,拒绝违规操作并记录日志(
/var/log/audit/audit.log) - Permissive:记录违规但不阻止,用于策略调试
- Disabled:完全关闭SELinux,需重启生效(修改
/etc/selinux/config)
生产环境绝对禁止disabled模式:它不仅削弱安全防护,更导致某些服务(如httpd、postgresql)因缺少SELinux上下文而无法启动。正确做法是保持enforcing,通过sealert工具分析拒绝日志:
# 安装诊断工具 dnf install setroubleshoot-server -y # 查看最近的SELinux拒绝事件 sealert -a /var/log/audit/audit.log | head -20sealert会生成可读性报告,例如:
SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket. For complete SELinux messages run: sealert -l 123abc... Allow access by executing: setsebool -P httpd_can_network_bind 14.2 关键布尔值实操:解决高频服务冲突
SELinux通过布尔值(boolean)开关控制策略宽松度。以下是最常调整的五个布尔值及其适用场景:
| 布尔值 | 默认值 | 适用场景 | 调整命令 |
|---|---|---|---|
httpd_can_network_bind | off | Apache/Nginx绑定非标准端口(如8080) | setsebool -P httpd_can_network_bind 1 |
samba_export_all_ro | off | Samba共享只读目录 | setsebool -P samba_export_all_ro 1 |
postgresql_selinux_user_read | off | PostgreSQL读取用户家目录数据 | setsebool -P postgresql_selinux_user_read 1 |
container_manage_cgroup | off | Docker容器管理cgroup资源 | setsebool -P container_manage_cgroup 1 |
virt_sandbox_use_fusefs | off | KVM虚拟机使用FUSE文件系统 | setsebool -P virt_sandbox_use_fusefs 1 |
注意:
-P参数表示永久生效(写入/etc/selinux/targeted/modules/active/booleans.local),无此参数则重启后失效。执行getsebool -a | grep httpd可查看所有httpd相关布尔值。
4.3 自定义策略模块:解决特殊应用权限需求
当标准布尔值无法满足需求时(如自定义Python服务需访问/opt/app/logs),需编写SELinux策略模块。以myapp服务为例:
# 1. 收集拒绝日志(运行应用触发SELinux拒绝) ausearch -m avc -ts recent | audit2why # 2. 生成策略模块 ausearch -m avc -ts recent | audit2allow -M myapp-policy # 3. 安装模块 semodule -i myapp-policy.pp # 4. 验证模块加载 semodule -l | grep myapp生成的myapp-policy.te文件内容类似:
module myapp-policy 1.0; require { type httpd_t; type var_log_t; class file { read write getattr }; } # Allow httpd_t to write to var_log_t allow httpd_t var_log_t:file { read write getattr };此过程将临时拒绝转化为永久策略,比全局禁用SELinux安全数个数量级。策略模块可打包分发,实现团队间安全策略标准化。
5. DNF包管理进阶:从基础更新到离线仓库构建
5.1 DNF核心命令的生产级用法
DNF(Dandified YUM)是Rocky Linux 9.1的默认包管理器,其设计哲学是“事务安全”。关键命令需掌握深层用法:
- 安全更新:
dnf update --security仅升级含CVE修复的包,避免非安全更新引入兼容性风险 - 版本锁定:
dnf versionlock kernel防止内核自动升级导致驱动不兼容 - 依赖分析:
dnf repoquery --whatrequires nginx查找所有依赖Nginx的包,用于卸载评估 - 包来源追溯:
dnf list installed | grep nginx显示包版本及仓库来源(如appstream、baseos)
特别注意dnf distro-sync命令:它将系统所有包同步至仓库最新版本,相当于apt full-upgrade,但需谨慎使用——生产环境建议先在测试机执行,再结合dnf history回滚:
# 查看最近操作 dnf history # 回滚到指定ID(如ID=15) dnf history undo 155.2 构建离线YUM仓库:解决无外网环境部署
当服务器处于隔离网络时,需构建本地仓库。以同步baseos和appstream仓库为例:
# 1. 在有外网的机器上创建仓库目录 mkdir -p /mnt/rocky9-repo/{baseos,appstream} # 2. 同步仓库(需安装dnf-plugins-core) dnf install dnf-plugins-core -y dnf reposync --repo=rocky-baseos --download-metadata --downloadcomps --download-as-root -p /mnt/rocky9-repo/baseos dnf reposync --repo=rocky-appstream --download-metadata --downloadcomps --download-as-root -p /mnt/rocky9-repo/appstream # 3. 生成仓库元数据 createrepo_c -v /mnt/rocky9-repo/baseos createrepo_c -v /mnt/rocky9-repo/appstream # 4. 将/mnt/rocky9-repo复制到目标服务器 # 5. 配置本地仓库文件 cat > /etc/yum.repos.d/local.repo << 'EOF' [local-baseos] name=Local Rocky 9 BaseOS baseurl=file:///mnt/rocky9-repo/baseos gpgcheck=0 enabled=1 [local-appstream] name=Local Rocky 9 AppStream baseurl=file:///mnt/rocky9-repo/appstream gpgcheck=0 enabled=1 EOF # 6. 清理缓存并验证 dnf clean all && dnf makecache dnf repolist此方案优势在于:完全离线、版本可控、无网络延迟。--downloadcomps参数下载软件包组(如@Development Tools),--download-metadata确保元数据完整,避免dnf groupinstall失败。
5.3 DNF插件实战:增强包管理能力
DNF通过插件扩展功能,以下三个插件在生产中不可或缺:
dnf-plugin-post-transaction-actions:在事务完成后执行脚本,如更新内核后自动更新GRUB:
# 启用插件 echo "post_transaction_actions = 1" >> /etc/dnf/plugins/post-transaction-actions.conf # 创建动作脚本 cat > /etc/dnf/plugins/actions.d/update-grub.action << 'EOF' [update-grub] command = /bin/sh -c 'grubby --update-kernel=ALL --args="rhgb quiet"' EOFdnf-plugin-system-upgrade:执行大版本升级(如Rocky 9.1→9.2):
dnf install dnf-plugin-system-upgrade -y dnf system-upgrade download --releasever=9.2 dnf system-upgrade rebootdnf-plugin-config-manager:动态管理仓库(需启用):
dnf config-manager --set-enabled crb # 启用CodeReady Builder仓库 dnf config-manager --set-disabled epel # 禁用EPEL
这些插件将DNF从单纯包安装器升级为系统生命周期管理平台,是Rocky Linux 9.1现代化运维的关键组件。
6. 综合排障:一个真实故障的完整诊断链
上周处理了一起典型故障:Rocky Linux 9.1服务器能ping通网关,但无法访问外部网站,curl https://google.com超时。按常规思路排查,发现firewalld和NetworkManager均正常,最终定位到SELinux与DNF的隐性交互问题。以下是完整的诊断链:
6.1 网络层验证:确认基础连通性
首先排除物理层问题:
# 检查接口UP状态 ip link show ens192 | grep "state UP" # 验证ARP解析 ip neigh show | grep "192.168.10.1" # 测试网关ICMP ping -c 3 192.168.10.1 # 成功 # 测试DNS服务器 dig @8.8.8.8 google.com +short # 超时DNS解析失败指向网络层或DNS配置问题。
6.2 DNS配置溯源:发现NetworkManager的隐藏行为
检查/etc/resolv.conf:
cat /etc/resolv.conf # 输出: # Generated by NetworkManager nameserver 127.0.0.1NM默认启用dnsmasq本地DNS缓存,但该服务未运行。systemctl status dnsmasq显示inactive (dead)。问题根源浮现:NM配置了ipv4.dns,但未启用dnsmasq,导致resolv.conf指向不存在的本地DNS。
解决方案:
# 方案A:禁用dnsmasq,直连上游DNS nmcli connection modify "Prod-Static" ipv4.dns "8.8.8.8,114.114.114.114" \ ipv4.ignore-auto-dns yes nmcli connection down "Prod-Static" && nmcli connection up "Prod-Static" # 方案B:启用dnsmasq(需安装) dnf install dnsmasq -y systemctl enable --now dnsmasq6.3 SELinux深度介入:DNS查询被拦截
采用方案A后,dig @8.8.8.8 google.com仍超时。启用permissive模式测试:
setenforce 0 dig @8.8.8.8 google.com +short # 立即返回结果 setenforce 1确认SELinux拦截。分析审计日志:
ausearch -m avc -ts recent | audit2why # 输出: # type=AVC msg=audit(1712345678.123:456): avc: denied { name_connect } for pid=12345 comm="dig" path="/dev/udp" scontext=system_u:system_r:unconfined_service_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=udp_socket permissive=0audit2why建议:
setsebool -P nis_enabled 1但nis_enabled与此无关。深入分析发现dig进程类型为unconfined_service_t,而UDP socket访问被拒绝。正确解决方案是:
# 允许unconfined_service_t访问网络 setsebool -P unconfined_service_connect_network 16.4 DNF仓库同步异常:连锁反应的起点
最终追溯到故障源头:管理员曾执行dnf update,但因网络波动中断。DNF残留的锁文件导致dnf makecache失败,进而使NM无法从仓库获取DNS配置模板。清理步骤:
rm -f /var/cache/dnf/*.sqlite* dnf clean all dnf makecache此案例揭示了Rocky Linux 9.1各组件的强耦合性:NetworkManager依赖DNF元数据生成DNS配置,SELinux策略控制DNS查询权限,firewalld管理DNS端口放行。单一故障点会引发多米诺骨牌效应。
最后分享一个小技巧:在生产环境部署前,务必执行
rocky-release-check(需安装rocky-release包)验证系统完整性。该工具检查SELinux状态、firewalld配置、NetworkManager服务及DNF仓库健康度,输出可操作的修复建议,比人工排查效率提升十倍。