1. 为什么我劝你在Linux上用nmcli,而不是继续手改配置文件
接触Linux运维这些年,我踩过不少网络配置的坑。早期维护一批CentOS服务器时,最头疼的莫过于给机器加个临时IP。传统思路是打开
/etc/sysconfig/network-scripts/ifcfg-eth0
,复制出一个新文件,改掉DEVICE和IPADDR,然后重启网络服务。这套流程操作一次还好,一旦批量操作几十台,或者要在无图形界面的服务器上配置无线网卡,效率和正确率都会出问题。后来我全面转向了nmcli,这个工具已经成为我日常管理Linux网络的主力。

nmcli是NetworkManager的命令行工具。很多人对NetworkManager有误解,觉得它是桌面Linux上的东西,服务器上应该禁用。这个观点在早期或许有道理,但现在的NetworkManager早已不是当年那个"一重启就搞乱resolv.conf"的毛头小子了。RHEL/CentOS 7之后,NetworkManager已经成为网络配置的默认管理框架,即便你选择了"不启用NetworkManager"的安装方式,系统里依然会存在
/etc/sysconfig/network-scripts
中的ifcfg文件,很多第三方工具也会依赖NetworkManager提供的DBus接口。与其抗拒它,不如把nmcli用熟练,它带来的效率提升非常明显。
nmcli相比传统配置文件方案,有几个实质性的优势:
-
原子化操作
:一条命令完成"改配置+生效",不需要重启网络服务,也不会出现改了半截文件导致网络中断的中间状态。 -
持久化与临时状态分离
:nmcli能明确区分"当前生效的配置"和"重启后依然保留的配置",传统ifcfg文件方案很难直观表达这种区别。 -
跨发行版一致
:无论Ubuntu(Netplan底层)、RHEL系还是Arch,只要底层是NetworkManager,nmcli的语法基本一致。你不需要在每台机器上重新学习一套网络配置逻辑。 -
脚本友好
:输出是结构化的文本,方便grep、awk二次处理,也容易嵌进自动化脚本。
我见过不少老运维到现在还在用
ifconfig eth0 192.168.1.10 netmask 255.255.255.0 up
这种即时生效但重启就失效的命令,或者改
/etc/network/interfaces
后手动
ifdown/ifup
。这些方法不是不能用,但它们都缺乏对连接(connection)的完整管理能力。所谓连接,不是指网卡物理链路,而是指一组网络配置参数的集合——IP地址怎么来、DNS用什么、是否自动连接、MTU多少——这些参数被打包成一个"配置对象",由NetworkManager统一管理,nmcli就是对这组对象进行操作的工具。理解这一点,后面所有命令都不难懂了。
这篇文章我不打算做成man手册的翻译,而是按我实际使用nmcli的路径来写:先讲清楚它的核心概念和对象体系,再给出高频操作、静态IP配置、进阶网络场景(网桥、VLAN、无线)、脚本化思路,最后是我这些年实际踩过的坑。README里查不到的东西,这里都有。
2. 先搞懂nmcli的对象体系,后面的命令才不会绕晕
2.1 connection和device到底有什么区别
我第一次用nmcli的时候也被这两个概念搞混过。简单说:
device(设备)是物理网卡本身,connection(连接)是配置在网卡上的一个"参数快照"
。
打个比方:device就像你家墙上的网口插座,connection就像插在网口上的那根网线以及网线另一端连的交换机的配置。一个插座上可以插不同的网线,一个网卡上也可以配置多个connection,但同一时刻只有一个connection是激活状态。
这个区别在命令里体现得很明显:
# 查看物理网卡状态
nmcli device status
# 查看所有连接配置(包括未激活的)
nmcli connection show
device status
的输出能看到每块网卡的物理状态,比如eth0是否connected、是否是外部连接。
connection show
则列出系统里所有保存过的网络配置,即使某套配置当前没有在任何网卡上激活,它也会出现在列表里。
为什么要区分这两个概念?因为实际运维中经常遇到这种情况:服务器上有一块物理网卡eth0,但你需要在不同的时间使用不同的网络参数——比如白天连接办公网,晚上连接测试网。你可以为eth0配置两个connection对象,分别命名为office和test,需要切换时用
nmcli connection up office
或
nmcli connection up test
即可,不需要改任何配置文件。
2.2 核心对象与常用子命令
nmcli的整套命令可以归纳为操作几个核心对象。我用一张表来总结它们的用途,日常运维90%的命令都落在这几个对象上:
| 对象 | 作用 | 常用子命令 |
|---|---|---|
(简称 ) |
管理连接配置:增删改查、激活、停用 |
|
(简称 ) |
查看/操作物理设备状态 |
|
(简称 ) |
查看NetworkManager全局状态、版本、权限 |
|
|
开关整套网络功能 |
|
|
无线/移动宽带射频控制 |
|
命令的通用格式是:
nmcli [选项] 对象 动作 [参数]
对象和动作都支持缩写,这对于脚本提速很有用。比如
nmcli c s
等于
nmcli connection show
,
nmcli d s
等于
nmcli device status
。但如果你在写一个要长期维护的脚本,我个人建议写全称——半年后回看脚本时,缩写容易让人费解。
另外需要特别提一下
nmcli general status
这个命令。它输出的内容包括NetworkManager的整体状态、当前主机名、联网状态等。排查"网络怎么又不通了"这类问题,我习惯先敲这一条,确认NetworkManager本身没挂:
[root@localhost ~]# nmcli general status
状态:已连接(全局),正在连接(本地)
主机名:localhost.localdomain
如果这里显示"已停止"或者异常,那后面所有针对connection的操作都可能不生效,得先处理NetworkManager服务本身。
2.3 显示字段的读取方法
nmcli connection show
默认只输出名称、UUID、类型和设备四列。实际排查时需要看某个连接的完整参数,用:
nmcli connection show eth0
或者精确指定属性:
nmcli -f ipv4.addresses,ipv4.gateway,ipv4.dns connection show eth0
-f
参数是
--fields
的缩写,后面跟逗号分隔的字段名。这对脚本处理特别有用,比如我想批量收集所有服务器的IP和网关:
nmcli -t -f NAME,ipv4.addresses,ipv4.gateway connection show | grep eth
-t
是
--terse
模式,输出不含表头、分隔符用冒号,非常适合脚本解析。这是我在做资产盘点时最常用的一个组合。
3. 日常运维高频操作:连接激活、参数修改与配置清理
3.1 查看连接状态与手工切换激活
先看最常用的查看连接状态命令:
nmcli connection show --active
这条命令只列出当前激活的连接。很多新手只知道
nmcli con show
,输出一大串,然后找不到哪个才是当前生效的。加上
--active
后清晰很多。
手工切换连接的激活状态,用:
# 激活名为eth0的连接
nmcli connection up eth0
# 断开当前激活的连接(注意,是disconnect设备,不是down连接)
nmcli device disconnect eth0
这里有个细节值得注意:
nmcli connection down eth0
和
nmcli device disconnect eth0
的效果有区别。
connection down
会让该连接变为"未激活"状态,网卡上如果没有其他connection,网络就断了;
device disconnect
则是让设备断开与当前连接的关联,设备保持空闲。如果之后你希望这台机器的网络完全恢复自动管理,可以用
nmcli device connect eth0
重新连上。
我的习惯是:日常切换配置时用
connection up
,临时断开网络排查问题时用
device disconnect
。用错了命令虽然也能恢复,但会多绕几步。
3.2 修改连接参数:modify命令的用法
修改连接配置是
nmcli connection modify
(缩写
mod
),这是我认为nmcli最值钱的命令。传统方式改LikeIP要编辑文件再重启服务,用nmcli只需要一句话:
# 将eth0连接的IP地址改为192.168.10.5/24,网关改为192.168.10.1
nmcli connection modify eth0 ipv4.addresses 192.168.10.5/24 ipv4.gateway 192.168.10.1
注意,这里要加
ipv4.method manual
才能让手动IP生效。很多新手改了addresses却发现不生效,原因就是method还是auto。正确的完整写法:
nmcli connection modify eth0
ipv4.method manual
ipv4.addresses 192.168.10.5/24
ipv4.gateway 192.168.10.1
ipv4.dns 223.5.5.5,114.114.114.114
ipv4.dns
支持逗号分隔多个DNS地址。如果希望DNS从DHCP获取,只需要把
ipv4.dns
设为空并删除相关记录:
nmcli connection modify eth0 ipv4.method auto ipv4.dns ""
修改后必须重新激活连接才能生效:
nmcli connection down eth0 && nmcli connection up eth0
这里有一个我踩过的坑:修改connection参数后,如果当前连接正在使用中,部分参数(比如IP地址)并不会自动应用,必须down再up。而up的时候如果没有其他备用连接,网络会短暂中断。生产环境操作时要特别小心,建议提前准备好带外管理通道,或者把命令写成一条原子操作避免中间状态。
3.3 添加新连接与删除旧连接
添加连接的完整形式是
nmcli connection add
。最常用的场景是给一块网卡添加第二套静态IP配置,或者创建一套全新的连接供后续切换使用:
# 创建一个名为backup的静态连接,绑定到eth0
nmcli connection add
con-name backup
type ethernet
ifname eth0
ipv4.method manual
ipv4.addresses 10.0.0.2/24
ipv4.gateway 10.0.0.1
没有指定
autoconnect
属性时,NetworkManager默认会让新连接在网卡可用时自动连接。但如果同一块网卡上已经有一个激活的连接,新连接并不会立刻顶替它,而是等当前连接down掉后再自动启用。这点很多人容易混淆:以为add完就生效了,实际还需要
nmcli connection up backup
手动激活。
删除连接用:
nmcli connection delete backup
删除连接不会影响物理网卡本身,只是删掉这套配置。如果误删了,重新add一个即可,只要网卡还在系统里,配置就能重建。
3.4 修改连接名称与UUID
连接名称和UUID是连接的标识。UUID在创建时自动生成,不需要手动改;但连接名称有时需要整理,比如统一命名规范:
nmcli connection modify eth0 connection.id lan1
修改名称后,后续所有操作都要用新名称。这个命令在批量初始化服务器时很好用,可以用脚本把每台机器的连接统一改成标准名称,比如
eth0-public
、
eth1-storage
。统一命名后,后续的自动化脚本会好写很多。
4. 从DHCP到静态IP的完整实操:一个标准流程
4.1 场景设定与初始状态确认
假设你有台刚装好的CentOS Stream服务器,网卡叫eth0,自动从DHCP获取到了IP。现在要求改成静态IP:192.168.100.50/24,网关192.168.100.1,DNS用223.5.5.5和119.29.29.29。
第一步永远是对当前状态做快照:
# 查看网卡状态
nmcli device status
# 查看当前激活的连接及其IP
nmcli connection show --active
nmcli -f ipv4.addresses,ipv4.gateway,ipv4.dns connection show eth0
确认当前连接名是eth0(有些系统默认叫
System eth0
或
Wired connection 1
,要根据输出实际名称操作,别想当然)。如果默认连接名带空格,比如
Wired connection 1
,所有命令都要用引号括起来:
nmcli connection show "Wired connection 1"
4.2 静态IP修改流程
第二步,一次性完成修改:
nmcli connection modify eth0
connection.autoconnect yes
ipv4.method manual
ipv4.addresses 192.168.100.50/24
ipv4.gateway 192.168.100.1
ipv4.dns 223.5.5.5,119.29.29.29
这里我加了
connection.autoconnect yes
。默认情况下这个属性就是yes,但只要我手上有"不让它自动连"的需求,我就会格外留意这个字段。加上它,确保修改后重启系统网络能自动恢复。
第三步,重新激活连接让修改生效:
nmcli connection down eth0
nmcli connection up eth0
第四步,验证:
ip addr show eth0
ip route show
cat /etc/resolv.conf
重点看ip addr中eth0是否有了192.168.100.50,路由网关是否指向192.168.100.1,DNS是否写入。这里有个容易踩的坑:
NetworkManager默认会管理resolv.conf
,即使你改了
ipv4.dns
,如果系统的
/etc/NetworkManager/NetworkManager.conf
里
dns
设置成了
none
,DNS不会自动写入resolv.conf。检查方法:
grep -i "^dns" /etc/NetworkManager/NetworkManager.conf
如果显示
dns=none
,说明NetworkManager不管理resolv.conf,你需要自己维护这个文件。很多从CentOS 6时代过来的老运维会手动配置resolv.conf,然后发现系统重启后被还原,就是因为没搞懂这个开关。
4.3 一个常见的"配完不生效"问题排查路径
有次我在客户环境改静态IP,命令执行成功,connection up也显示正常,但ping网关就是不通。排查发现是网卡配置里没有指定
HWADDR
,而systemd的网卡命名规则把网卡名从eth0变成了ens33,连接虽然绑定了ifname eth0,但系统里根本没有eth0这个设备。
这种场景下的正确做法是用UUID或MAC地址来绑定连接,或者在修改前先确认网卡的准确名称:
nmcli device status
看到NAME列是ens33,就应该把
ifname ens33
作为绑定目标,而不是沿用文档里的eth0。这个教训我记了很久:nmcli命令本身不会出错,出错的是我们对物理设备的认知。
4.4 配置双IP与多网卡
静态IP配置并不局限于单个IP。很多业务场景需要在一块网卡上配置两个网段IP,比如一边连接内网一边对外提供服务。nmcli完全支持:
nmcli connection modify eth0
ipv4.addresses "192.168.100.50/24,10.10.10.5/24"
ipv4.gateway "192.168.100.1"
注意addresses用逗号分隔多个IP,但
ipv4.gateway
只能有一个默认网关。如果第二个IP所在的网段也有网关需求,你需要添加路由规则而不是简单配置网关:
nmcli connection modify eth0 +ipv4.routes "10.20.0.0/16 10.10.10.1"
+
前缀表示追加一条路由规则而不是覆盖原配置。这条命令的含义是:访问10.20.0.0/16网段的流量经由10.10.10.1转发。理解
+
和
-
前缀是nmcli进阶的关键——
+
追加、
-
移除、不加前缀则是覆盖。这三个符号能处理几乎所有多值属性的修改场景。
5. 进阶场景:网桥、VLAN与无线连接的实战用法
5.1 创建Linux网桥(Bridge)
做虚拟化时经常需要网桥。比如KVM虚拟机要和宿主机共享物理网络,最常见的方案就是创建bridge接口,然后让物理网卡和虚拟机的虚拟网卡都加入这个bridge。
传统做法是手动配置brctl然后再设置IP,现在用nmcli可以一步到位:
# 创建网桥连接br0
nmcli connection add
type bridge
con-name br0
ifname br0
ipv4.method manual
ipv4.addresses 192.168.100.50/24
ipv4.gateway 192.168.100.1
# 把物理网卡eth0加入br0,注意这里创建一个从属连接
nmcli connection add
type ethernet
con-name bridge-slave-eth0
ifname eth0
master br0
slave-type bridge
两个连接都准备好后,启动网桥:
nmcli connection up br0
这时eth0不再配置IP,IP地址全部落在br0上。虚拟机网卡以tap/tun方式桥接后,就能和宿主机走同一个二层网络。这里有个细节:物理网卡eth0加入网桥后,原来的eth0连接不能再激活,否则会出现地址冲突。NetworkManager在设计上会自动处理这种冲突,但保险起见,建议把原来的eth0普通连接删除或设置
autoconnect no
。
5.2 配置VLAN子接口
VLAN隔离在服务器运维里也很常见。传统的做法是编辑ifcfg-eth0.100之类的文件,用nmcli创建VLAN连接非常直接:
# 在eth0上创建VLAN ID为100的子接口
nmcli connection add
type vlan
con-name vlan100
ifname eth0.100
dev eth0
id 100
ipv4.method manual
ipv4.addresses 192.168.100.5/24
激活后,你会在系统里看到eth0.100这个子接口,IP已经配置好。和网桥一样,VLAN子接口的父接口不需要有IP。这个能力在配置IP电话、监控网段分流时非常好用——物理上只有几根网线,逻辑上却能划分出多个互不干扰的二层网段。
5.3 无线网络连接:命令行操作Wi-Fi
无图形界面的Linux设备要连Wi-Fi,nmcli几乎是唯一顺手的方式。虽然大部分文章都写"服务器有线,不需要Wi-Fi",但树莓派这类微型主机、嵌入式设备、临时应急通信场景,用命令行连接Wi-Fi是刚需。
查看可用Wi-Fi:
nmcli device wifi list
连接一个开放的Wi-Fi:
nmcli device wifi connect "MyWiFi"
连接一个需要密码的Wi-Fi并保存配置:
nmcli device wifi connect "MyWiFi" password "mypassword" hidden no
hidden
参数:如果你的Wi-Fi隐藏了SSID,需要指定
hidden yes
,否则扫描列表里没有这个网络,连接会失败。连接成功后,NetworkManager会创建同名Wi-Fi连接,并默认设置为自动连接。
如果公司Wi-Fi是企业级认证(WPA2-Enterprise,需要用户名密码和CA证书),nmcli也能处理,但参数会复杂很多:
nmcli connection add
type wifi
con-name corporate
ssid "CorpNet"
wifi-sec.key-mgmt wpa-eap
802-1x.eap peap
802-1x.identity "username@domain"
802-1x.password "password"
802-1x.phase2-auth mschapv2
这类配置如果手写容易出错,我的建议是先在有图形界面的环境用NetworkManager连接一次,然后导出配置:
nmcli connection show corporate
再看具体参数填到脚本里。NetworkManager的802-1x模块在命令行配置时字段名很容易记混,用图形界面生成参考值是最稳妥的。
5.4 Team或Bonding多网卡聚合
多网卡绑定,老派做法是
modprobe bonding
然后配置ifcfg-bond0。用nmcli操作更清晰:
nmcli connection add type bond con-name bond0 ifname bond0 bond.options "mode=active-backup,miimon=100"
nmcli connection add type ethernet con-name bond0-slave-eth0 ifname eth0 master bond0
nmcli connection add type ethernet con-name bond0-slave-eth1 ifname eth1 master bond0
nmcli connection up bond0
mode=active-backup
表示主备模式,
miimon=100
表示每100毫秒检测一次链路状态。生产环境建议先理解bonding的几种mode(balance-rr、active-backup、balance-xor、802.3ad等)再动手,不要照抄命令。nmcli只是管理工具,它不会替你判断哪种mode更合适。
6. 把nmcli写进自动化:脚本、批量配置与一致性检查
6.1 批量设置静态IP的脚本模板
运维工作最忌讳的是重复手工操作,nmcli天然适合脚本化。下面是一段我常用的批量初始化脚本(以bash为例):
#!/bin/bash
# 批量配置服务器静态IP
DEVICE="ens33"
NEWIP="192.168.100.50/24"
GATEWAY="192.168.100.1"
DNS1="223.5.5.5"
DNS2="119.29.29.29"
# 获取当前激活的连接名
CONN=$(nmcli -t -f NAME device show $DEVICE | head -1)
echo "当前连接: $CONN"
nmcli connection modify "$CONN"
connection.autoconnect yes
ipv4.method manual
ipv4.addresses "$NEWIP"
ipv4.gateway "$GATEWAY"
ipv4.dns "$DNS1,$DNS2"
nmcli connection down "$CONN"
nmcli connection up "$CONN"
脚本里有两处值得注意:一是用
nmcli -t -f NAME device show $DEVICE
动态获取连接名,而不是硬编码;二是down和up之间没有任何sleep,因为NetworkManager处理down/up状态切换足够快,但如果你在脚本中马上要执行依赖网络的命令,最好还是加一句
sleep 2
缓冲。实际批量执行时,我会把所有需要操作的主机IP和参数写进一个CSV文件,然后用循环读取,配合expect或ansible执行。核心逻辑都一样,就是上面这三板斧。
6.2 一致性检查:用nmcli命令做配置巡检
除了配置,nmcli还能帮我们做巡检。比如检查所有服务器上某块网卡的IP是否符合规范:
# 列出所有激活连接及其IP地址
for conn in $(nmcli -t connection show --active | cut -d: -f1); do
echo "=== $conn ==="
nmcli -f ipv4.addresses,ipv4.gateway connection show "$conn"
done
这段脚本的输出可以直接和CMDB里的期望值比对。我维护的一批服务器曾经因为某次初始化脚本bug,把网关都写成了192.168.100.254,后来就是用这种方式扫出来的。发现问题后批量修复也就一条for循环的事。
6.3 与systemd、云init之间的配合
现代Linux发行版初始化网络的方式越来越统一。在系统启动早期,NetworkManager会读取
/etc/NetworkManager/system-connections/
下的连接配置(CentOS系还存在
/etc/sysconfig/network-scripts/ifcfg-*
,NetworkManager会做兼容解析)。你用
nmcli connection add
创建的配置,最终就落在这两个目录里。
云环境的初始化工具(如cloud-init)也大量使用NetworkManager或Netplan。如果你在公有云上创建自定义镜像,强烈建议保留NetworkManager服务开机自启,否则cloud-init写入网络配置时可能找不到管理接口。很多"云主机重启后IP丢失"的问题,根源就在于系统里NetworkManager被禁用,而cloud-init期望的配置管理通道不存在。
一、分层排障模型(从物理层到应用层)
网络故障排查最忌”乱试”。按 OSI 自底向上:物理层(网卡/线缆/光模块/端口灯)→ 数据链路层(VLAN、MAC、STP、协商速率)→ 网络层(IP、网关、路由、ARP)→ 传输层(TCP/UDP 端口、ACL)→ 应用层(DNS、代理、证书)。先确认链路通断(网卡 up、协商速率正常),再 ping 网关,再 traceroute 看断点在第几跳,最后查应用端口与日志。
二、排障工具箱
- ping / pathping / mtr:看连通性与逐跳丢包延迟。
- traceroute / tracert:定位故障跳点,区分运营商侧还是内网侧。
- Wireshark:抓包看 TCP 重传、RST、DNS 超时、ARP 风暴,可复现 NAT 穿透与三次握手异常。
- 交换机端口:err-disable、CRC 错包、双工不匹配、loop guard 是端口故障高频原因,show interface 看 counters 是第一步。
- 防火墙:iptables/firewalld/nftables/ufw 规则顺序与默认策略决定放行,改前先备份规则、确认 SSH 不会被锁死。
三、工程经验
交换机端口频繁 err-disable 多因 BPDU guard 或线缆接触不良;无线与有线混排时优先固化上联端口;变更防火墙前在测试环境验证并保留回滚命令。运维类故障的闭环是:复现 → 定位 → 临时恢复 → 根因修复 → 复盘沉淀。
相关阅读
本文为转载作品。版权归原作者所有;本站仅作技术学习与方案参考,如涉侵权请联系我们删除。



评论 0
还没有评论,来抢沙发吧。