1. 为什么我劝你在Linux上用nmcli,而不是继续手改配置文件

接触Linux运维这些年,我踩过不少网络配置的坑。早期维护一批CentOS服务器时,最头疼的莫过于给机器加个临时IP。传统思路是打开

/etc/sysconfig/network-scripts/ifcfg-eth0

,复制出一个新文件,改掉DEVICE和IPADDR,然后重启网络服务。这套流程操作一次还好,一旦批量操作几十台,或者要在无图形界面的服务器上配置无线网卡,效率和正确率都会出问题。后来我全面转向了nmcli,这个工具已经成为我日常管理Linux网络的主力。

Linux 网络配置:nmcli 优于手改 ifcfg 文件
图片素材来自免费商用图库(pixabay),非本站项目实拍。

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%的命令都落在这几个对象上:

对象 作用 常用子命令

connection

(简称

con

)
管理连接配置:增删改查、激活、停用
show


add


mod


del


up


down

device

(简称

dev

)
查看/操作物理设备状态
status


show


connect


disconnect

general

(简称

g

)
查看NetworkManager全局状态、版本、权限
status


hostname


permissions

networking
开关整套网络功能
on


off


connectivity

radio
无线/移动宽带射频控制
all


wifi


wwan

命令的通用格式是:

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 或线缆接触不良;无线与有线混排时优先固化上联端口;变更防火墙前在测试环境验证并保留回滚命令。运维类故障的闭环是:复现 → 定位 → 临时恢复 → 根因修复 → 复盘沉淀。

相关阅读