远程登录一台机器,敲下一条命令改 IP,回显还没刷完,终端就卡死了——这个画面我相信每个做过运维的人都见过不止一次。nmcli这个工具之所以值得单独拿出来讲,不是因为它命令多难记,而是因为它是少数几个“一条命令就能让你失去服务器”的工具,同时又几乎是当下 Linux 上配置网络最省事、最可脚本化、最容易回滚的方案。它属于 NetworkManager 的命令行前端,负责把“连接配置”写成文件、把配置激活到网卡上、把 DNS 和路由一起带起来。会用它的人,改地址、加网关、配双网卡、切 Wi-Fi 都是几十秒的事;不会用它的人,往往在/etc/resolv.conf和/etc/sysconfig/network-scripts之间来回折腾,改完重启一测还是老样子。这篇内容面向已经能登录 Linux、但对 NetworkManager 这套模型不太熟的人,从“它到底管什么”讲到远端改 IP 的自保手法,再到多网卡、VLAN、网桥这些变体和排错链路,尽量把踩过的坑都摆出来。
1. nmcli 管的不是网卡,而是“连接”
刚接触这套工具的人最容易混淆的地方,就是把“设备”和“连接”当成一个东西。一旦这个认知没建立起来,后面所有命令都会用错,包括最典型的“我明明改了配置,为什么网络还是原来的样子”。
1.1 device 和 connection 是两套对象
nmcli device描述的是内核眼里真实存在的网络接口,比如eth0、ens33、wlan0、lo,它能列出这些接口的状态:connected、disconnected、unmanaged、unavailable。而nmcli connection描述的是“一份配置方案”,它有自己的名字(con-name)、UUID、以及一大堆ipv4.*、ethernet.*属性。一份连接配置可以被套到某张网卡上激活,激活之后这张网卡才真正拥有 IP、路由和 DNS。
这个分离带来一个非常实用的能力:同一张网卡可以准备多份连接配置。比如一张网卡上同时存着“办公室静态地址”和“家里 DHCP”两份配置,插到哪儿就激活哪一份,不需要每次都手动改参数。也可以把一份连接配置复制(nmcli connection clone)给另一张网卡用,改个ifname就行。这些操作的前提,都是你清楚自己在操作的是“配置”还是“设备”。
判断标准很简单:带connection的命令改的是文件里的内容,带device的命令改的是当下内核里的状态。nmcli connection modify只是改文件,不碰正在跑的接口;nmcli device disconnect eth0是直接把接口断掉,但配置文件还在。
1.2 配置最终落在哪个文件里
nmcli connection add和modify写出来的东西,在绝大多数发行版上都会落到/etc/NetworkManager/system-connections/目录下,文件名就是连接名加.nmconnection后缀。这是一个 keyfile 格式的文本文件,内容大致长这样:
[connection] id=eth0-static uuid=8f3c1e2a-...-9a7b type=ethernet interface-name=eth0 autoconnect=true [ipv4] method=manual address1=192.168.10.50/24,192.168.10.1 dns=223.5.5.5;119.29.29.29; may-fail=false [ipv6] method=auto这个文件有两个必须知道的细节。第一,权限必须是 600,因为里面可能存着 Wi-Fi 密码或者企业网络的凭据,NetworkManager 检测到权限不对会直接拒绝加载,日志里会写一条insufficient permissions。第二,手改这个文件之后必须执行nmcli connection reload,否则 NetworkManager 内存里还是旧配置,你改的等于没改。很多人踩的“我明明改了文件为什么不生效”,九成是漏了这条 reload。
不同发行版对老格式还留了兼容,比如/etc/sysconfig/network-scripts/ifcfg-*(部分系统)和/etc/netplan/(另一套体系)。如果你的机器上同时存在 NetworkManager 和其他网络管理服务,那就要格外小心,两套东西抢同一张网卡,症状是地址一会儿有一会儿没有。
1.3 “配置”和“生效”之间隔着一次激活
这是新手最容易掉进去的坑,也是远端操作最危险的环节。nmcli connection modify执行完,命令会安静地返回 0,没有任何提示,很多人以为改完了,一测还是旧地址。原因就是配置只是写进了文件的待生效区,必须再执行一次nmcli connection up <连接名>才会把新参数灌进内核。
反过来更危险:nmcli connection up会先把接口 down 掉再 up,这期间 IP 会消失、SSH 会话会断。如果你改的恰好是当前 SSH 正在用的那张网卡,而且新配置有问题(网关写错、地址冲突、掩码写错),那这次断线就是永久性的——除非你还有别的通道能进去。
所以正确的心理模型是:nmcli的每一次up,都是一次“拔网线再插回去”。理解了这一点,后面所有关于“远端改 IP 怎么不把自己搞死”的手法,就都有了统一的解释。
2. 动手前先把现状摸清楚,顺手留一条后路
改网络之前不做侦察,等于闭着眼睛改数据库。花三十秒把当前状态看清楚,能省掉后面半小时的排查。
2.1 三条侦察命令的分工
日常我用得最多的三条,职责分得很清楚:
nmcli general status nmcli device status nmcli connection showgeneral status给出的是全局视角:NetworkManager 本身是connected还是asleep,有没有开networking,有没有开 Wi-Fi 无线电,以及当前主机名。如果这里显示networking enabled: no,那后面所有命令都白搭,先用nmcli networking on打开。
device status是设备清单,重点看两列:STATE和CONNECTION。connected表示这张卡已经套了一份配置在跑,disconnected表示网卡在但没有可用配置,unmanaged表示这张卡根本不归 NetworkManager 管——最后这个状态非常关键,如果一张网卡显示unmanaged,你改多少配置它都不会响应,原因通常是/etc/NetworkManager/NetworkManager.conf里写了unmanaged-devices,或者这张卡被别的服务接管了。
connection show列出所有配置方案,注意看NAME和DEVICE两列,DEVICE为空说明这份配置当前没有被任何网卡激活。真实环境里经常出现一份废弃的旧配置残留,名字和新配置很像,改错对象就是这么来的。
2.2 把完整配置导出来当回滚点
这一步我认为比什么都重要。在改任何参数之前,先把当前生效的完整配置存一份:
mkdir -p /root/netbak nmcli connection show "eth0-static" > /root/netbak/eth0-static.before.txt cp /etc/NetworkManager/system-connections/eth0-static.nmconnection /root/netbak/ ip addr show > /root/netbak/ipaddr.before.txt ip route show > /root/netbak/route.before.txt cat /etc/resolv.conf > /root/netbak/resolv.before.txtnmcli connection show <名字>不带-f参数时,会把这份连接的所有属性全打出来,包括那些你从来没设置过、用的是默认值的字段。这份输出就是一张完整的快照,出问题时对照着看,比凭记忆猜要可靠得多。
备份文件拷到本地一份更稳妥。.nmconnection文件可以直接被另一台机器用nmcli connection load导入,这也是后面讲批量下发时的基础。
2.3 确认 DNS 到底谁在管
DNS 这一块是最容易出问题的灰色地带,因为现在有三套东西可能同时在管/etc/resolv.conf:NetworkManager 自己、systemd-resolved、以及老式的dhclient钩子。先看一眼现状:
ls -l /etc/resolv.conf如果输出是resolv.conf -> /run/systemd/resolve/stub-resolv.conf这样的软链,说明走的是systemd-resolved,此时你在nmcli里配的 DNS 会被转交给它,查 DNS 生效与否要看resolvectl status。如果它是一个普通文件,打开看头两行有没有# Generated by NetworkManager的注释,有的话就是 NetworkManager 直接写的。
注意:直接编辑
/etc/resolv.conf在几乎所有现代发行版上都不可靠,重启或者重新激活连接时会被覆盖。要么在nmcli里配ipv4.dns,要么就正经去改resolved的配置。
这一步看着像仪式感,实际上决定了你后面配 DNS 该往哪写、验证该看哪个命令。我见过不止一次有人抱怨“nmcli里配了 DNS 但ping 域名不通”,最后发现机器上resolved在跑,但连接上ipv4.ignore-auto-dns没设成yes,DHCP 下发的 DNS 排在前面,把手工配的挤掉了。
3. 静态地址一次写对:参数逐个拆开看
真正落地静态 IP 的时候,命令本身不长,但每一个参数都有它存在的理由,少一个就可能出问题。
3.1 完整的一条命令长什么样
假设要在eth0上配192.168.10.50/24,网关192.168.10.1,DNS 两个,最完整而不啰嗦的写法是:
nmcli connection add type ethernet con-name eth0-static ifname eth0 \ ipv4.method manual \ ipv4.addresses 192.168.10.50/24 \ ipv4.gateway 192.168.10.1 \ ipv4.dns "223.5.5.5 119.29.29.29" \ ipv4.ignore-auto-dns yes \ connection.autoconnect yes然后激活:
nmcli connection up eth0-static如果配置已经存在,只是改参数,那就用modify:
nmcli connection modify eth0-static ipv4.addresses 192.168.10.60/24 nmcli connection modify eth0-static ipv4.gateway 192.168.10.1 nmcli connection up eth0-static这里有个细节值得说清楚:modify可以一条命令改多个属性,把多个key value串在后面就行,比反复调用快得多。但不要在一条命令里既改地址又改网关又激活,出了问题不好定位是哪一项写错了。我的习惯是改完先nmcli connection show eth0-static | grep ipv4核对一遍,确认无误再up。
3.2 那些必须写、但文档里不强调的参数
ipv4.method manual是必须显式写上的。connection add的默认值是auto,也就是走 DHCP。如果你只写了ipv4.addresses却不写manual,行为会变得很奇怪——NetworkManager 会先按 DHCP 要一次地址,拿到的地址和你的静态地址同时挂在网卡上,两个地址、两条默认路由,路由表乱成一锅粥。我遇到过最离谱的情况是 DHCP 拿到的地址抢先拿到了默认路由,静态网关被忽略,机器能通内网但出不了外网,排查了半天才发现是这个原因。
ipv4.addresses里的前缀长度不能省。写成192.168.10.50而漏掉/24,NetworkManager 会按默认值处理,大概率按/32或者从ipv4.prefixes里凑,结果就是同网段的其他机器都 ping 不通。这个错误在命令行里很容易犯,因为 IP 地址大家都习惯只写四段。写完之后一定用ip addr show eth0复核,看那一行的inet后面有没有正确的/24。
connection.autoconnect yes决定开机时这份配置会不会自动激活。如果你做了多份配置准备手动切换,那其中几份应该设成no,否则开机时它们会抢同一张网卡,最后谁赢取决于激活顺序,行为不可预测。
3.3 追加和删除属性的加号、减号写法
这是nmcli一个非常好用但很多人不知道的语法。直接写ipv4.dns 8.8.8.8是覆盖整个列表,而写+ipv4.dns 8.8.8.8是追加,写-ipv4.dns 8.8.8.8是移除指定项。地址、路由、DNS 这些列表型属性都支持:
# 追加一个备用地址,保留原有地址 nmcli connection modify eth0-static +ipv4.addresses 192.168.10.51/24 # 移除其中一个 DNS,保留其他 nmcli connection modify eth0-static -ipv4.dns 119.29.29.29这个语法在脚本里特别有用。批量给几十台机器加同一个备用 DNS,用+就不会把每台机器原有的配置冲掉;如果用了覆盖写法,那些有特殊 DNS 需求的机器就全毁了。同理,给一台机器挂第二个地址做迁移过渡时,+ipv4.addresses是唯一安全的写法,因为它不会动原有地址。
提示:
+和-这两个前缀只在modify里生效,add里写了会被当成普通值。另外,删除网关不能用-ipv4.gateway,因为网关不是列表属性,要清空得写成ipv4.gateway ""。
3.4 DNS 的两个入口和它们的优先级
ipv4.dns和ipv4.ignore-auto-dns是一对必须配合使用的参数。前者是你手工指定的 DNS 服务器,后者决定要不要忽略 DHCP 或者 PPP 对端下发的 DNS。
如果ignore-auto-dns是默认的no,那么最终生效的 DNS 列表是“手工配的 + DHCP 下发的”合并结果,而且顺序上 DHCP 下发的可能排在前面。这就解释了那个经典现象:你在nmcli里认认真真配了内网 DNS,结果ping 内网域名就是解析不出来,因为公网 DNS 排在它前面,把查询吃掉了。
所以只要你是手工指定 DNS 的场景,就顺手把这一项加上:
nmcli connection modify eth0-static ipv4.ignore-auto-dns yes还有ipv4.dns-search这个属性,用来配搜索域。公司内网用短域名(比如直接ping gitlab而不是ping gitlab.corp.example)的时候,靠的就是它。配上去之后resolv.conf里会出现search行,短名解析才工作。
4. 远端改 IP 不断线的几种活命手法
前面说过,connection up本质上是一次接口重启。人在机房或者有带外管理的时候这都不是事,但如果只有一根 SSH 连着,就得想办法给自己留退路。下面这几种手法我按可靠性从高到低排。
4.1 延迟执行加自动回滚,最稳的一招
核心思路是:把“改配置并激活”这个动作推迟几分钟执行,同时准备好一条“如果新配置不通就恢复旧配置”的兜底命令。如果新配置没问题,你手动取消定时任务;如果断线了,等几分钟它自己回滚,你又能连上。
# 先备份现有配置作为回滚源 cp /etc/NetworkManager/system-connections/eth0-static.nmconnection /root/netbak/eth0-static.good # 准备一个回滚脚本 cat > /root/netbak/rollback.sh <<'EOF' #!/bin/bash cp /root/netbak/eth0-static.good /etc/NetworkManager/system-connections/eth0-static.nmconnection chmod 600 /etc/NetworkManager/system-connections/eth0-static.nmconnection nmcli connection reload nmcli connection up eth0-static logger "netrollback: 已回滚到旧网络配置" EOF chmod +x /root/netbak/rollback.sh # 5 分钟后执行回滚 echo "/root/netbak/rollback.sh" | at now + 5 minutes然后你再去改新配置、up。新配置如果通,立刻atrm掉那个任务;如果不通,SSH 断了,五分钟(或者你设的任意时长)之后机器自己回到旧配置,重新连上去排查就行。
这套方法依赖atd服务,有些精简系统没装。装不了的话用nohup加sleep也能达到同样效果:
nohup bash -c 'sleep 600; /root/netbak/rollback.sh' >/dev/null 2>&1 &缺点是进程没有at那么好管理,取消要kill掉 PID。所以我会把 PID 写进文件,方便随时取消。
4.2 双地址过渡:先加后删,全程不断
如果只是换 IP,网段不变、网关不变,那有个更优雅的办法:先用+ipv4.addresses把新地址加上去并激活,此时网卡上同时有两个地址,旧的 SSH 会话靠旧地址还活着;确认新地址能 ping 通之后,再从本地新开一个 SSH 连到新地址,最后用-ipv4.addresses把旧地址摘掉。
# 第一步:追加新地址,激活 nmcli connection modify eth0-static +ipv4.addresses 192.168.10.60/24 nmcli connection up eth0-static # 第二步:从另一个终端连新地址验证 ssh user@192.168.10.60 # 第三步:确认无误后删除旧地址 nmcli connection modify eth0-static -ipv4.addresses 192.168.10.50/24 nmcli connection up eth0-static这套流程的关键在于,connection up虽然会重置接口,但因为配置里同时包含新旧两个地址,重置之后两个地址都会重新加上,SSH 会话即使短暂中断也能自动重连。整个过程不需要任何定时任务。
这个办法的适用范围有明确边界:跨网段迁移不能用。跨网段意味着默认网关也要换,而一份连接配置只能有一个ipv4.gateway。想要让两个网段的地址同时可用,得靠策略路由或者第二份连接配置,复杂度上升一个量级。
4.3 用--wait控制激活超时
新版本的nmcli在connection up上支持--wait参数,单位是秒,用来指定等待激活完成的最长时间:
nmcli --wait 30 connection up eth0-static默认情况下up会一直等到激活成功或明确失败,如果新配置有语法问题,这个等待过程会拖得很久,你的脚本也跟着卡住。加上--wait之后,超时就返回非零退出码,脚本可以用它来判断是否触发回滚。写自动化脚本的时候这个参数基本是必备的。
配合if判断大概是这样:
if nmcli --wait 30 connection up eth0-static; then logger "netapply: 新配置激活成功" else logger "netapply: 激活超时,执行回滚" /root/netbak/rollback.sh fi注意:
--wait只是控制“等多久”,不代表激活成功之后网络一定通。地址生效了但网关写错,命令照样返回 0。所以激活之后的连通性验证(ping网关、ping外部地址、解析域名)一步都不能少。
4.4 断线之后怎么爬回来
万一前面几条都没做,SSH 已经断了,也别慌,按下面的顺序找通道。
第一优先是云控制台或者 IPMI/BMC 之类的带外管理,这是最干净的路径,相当于直接坐在机器前面。第二是串口控制台,很多物理机都配了。第三是让同机房的同事帮忙接个显示器和键盘。
如果这三种都没有,那就只能走恢复模式:重启进 GRUB 菜单,在启动参数里加rd.break(某些系统)或者init=/bin/bash,进到一个最小 shell,把网络配置文件修好,或者直接把/etc/NetworkManager/system-connections/下那个坏掉的文件删掉,让系统按默认配置启动。修改之后要注意,这种模式下根文件系统可能是只读挂载的,需要mount -o remount,rw /才能写入。
还有一种情况是配置没错但NetworkManager服务自己起不来,那就要看日志:
journalctl -u NetworkManager -b --no-pager | tail -50日志里如果有keyfile: invalid connection或者insufficient permissions,基本就是文件格式或者权限问题。权限问题用chmod 600解决,格式问题就得对着nmcli connection show的输出逐行核对了。
5. 一套网卡玩出花:多 IP、多网卡、Wi-Fi、VLAN
真实环境很少只有一张网卡一个地址,下面这些变体是日常最可能碰到的。
5.1 一张网卡挂多个地址和路由优先级
前面提过+ipv4.addresses可以追加地址,其实一份配置里地址部分写成逗号分隔也能一次加多个:
nmcli connection modify eth0-static ipv4.addresses "192.168.10.50/24,192.168.10.51/24,192.168.10.52/24"这种写法是覆盖式的,会清掉原来所有地址,所以改之前一定要先nmcli connection show eth0-static | grep addresses看一眼现状。
多个地址挂上去之后,默认路由还是只有一条(由ipv4.gateway决定)。如果你需要让不同地址走不同网关,那就得用ipv4.routes加策略路由,这已经超出nmcli单条命令能覆盖的范围了,需要配合ip rule和路由表来配。
5.2 两张网卡抢默认网关
这是多网卡机器上的经典问题。eth0连内网、eth1连外网,两份配置里都写了ipv4.gateway,结果路由表里出现两条default,实际走哪条取决于 metric 谁小。
解决方式有两种,我通常用第一种:把内网那张卡的ipv4.never-default设成yes,明确告诉它不要装默认路由。
nmcli connection modify eth0-internal ipv4.never-default yes nmcli connection up eth0-internal这样默认路由就只会由外网那张卡提供,不会打架。如果两张卡确实都需要默认路由(比如做备份链路),那就用 metric 控制优先级:
nmcli connection modify eth0-primary ipv4.route-metric 100 nmcli connection modify eth1-backup ipv4.route-metric 200metric 小的优先级高。这个值还可以和connection.autoconnect-priority配合用,后者控制的是开机时谁先激活,两个概念别搞混。
| 参数 | 作用层级 | 典型用途 |
|---|---|---|
ipv4.never-default | 单连接 | 内网卡不参与默认路由选举 |
ipv4.route-metric | 单连接 | 多条默认路由时排优先级 |
connection.autoconnect-priority | 单连接 | 开机时多份配置的激活顺序 |
connection.autoconnect-retries | 单连接 | 激活失败后重试次数,设 -1 表示无限 |
5.3 无线网卡的两步走
Wi-Fi 的配置逻辑和有线不太一样,通常分两步:先扫描看信号,再连。
nmcli device wifi list nmcli device wifi connect "MyOfficeWiFi" password "yourpassword" name wlan-office第二条命令会顺手创建一份连接配置并立即激活,name参数指定配置名,不写的话默认用 SSID 当名字。连上之后如果想让这份配置只对wlan0生效,可以再modify一下ifname。
隐藏 SSID 需要显式指定:
nmcli device wifi connect "HiddenSSID" password "pwd" hidden yes无线排错时先看nmcli radio wifi有没有打开,再看nmcli device status里wlan0是不是unmanaged(有些机器的无线网卡驱动需要额外装固件,装不上就会一直显示不可用)。
5.4 VLAN 和网桥的基本建法
VLAN 的配置非常直接,把type写成vlan,指定父接口和 VLAN ID:
nmcli connection add type vlan con-name vlan100 dev eth0 id 100 \ ipv4.method manual ipv4.addresses 10.0.100.10/24 ipv4.gateway 10.0.100.1 nmcli connection up vlan100网桥稍微复杂一点,要先把物理网卡挂到桥上,再给桥配地址:
# 建桥 nmcli connection add type bridge con-name br0 ifname br0 \ ipv4.method manual ipv4.addresses 192.168.20.10/24 ipv4.gateway 192.168.20.1 # 把 eth1 挂上去(不配地址) nmcli connection add type ethernet con-name br0-port1 ifname eth1 \ master br0 ipv4.method disabled ipv6.method disabled nmcli connection up br0 nmcli connection up br0-port1顺序很重要:先up桥,再up端口。反过来的话端口会因为找不到 master 而激活失败。另外物理网卡挂到桥上之后,它自己不能再有 IP,所以ipv4.method要设成disabled,这一点漏掉会导致地址冲突。
6. 网不通的时候,按这个顺序查
排错最忌讳东一榔头西一棒子,有一套固定的检查顺序能大幅缩短时间。
6.1 从底层往上的排查链路
我的习惯是从“配置有没有被加载”开始,一层层往上推:
| 现象 | 先查这条命令 | 常见原因 |
|---|---|---|
| 网卡没 IP | nmcli device status | 设备unmanaged,或被其他网络服务接管 |
| 改了配置没变化 | nmcli connection show <名字> | 忘了up,或改的不是当前激活的那份配置 |
| 有 IP 但 ping 不通网关 | ip route show | 网关没配上,或网段/前缀写错 |
| 能通 IP 但不通域名 | cat /etc/resolv.conf | DNS 被 DHCP 覆盖,或ignore-auto-dns没开 |
| 重启后配置丢失 | ls /etc/NetworkManager/system-connections/ | 配置文件权限不是 600,被拒绝加载 |
| 激活报错 | journalctl -u NetworkManager -b | 参数冲突、UUID 重复、文件格式错误 |
按这个表走一遍,大部分问题在头两步就能定位。
6.2 和其他网络管理服务打架
这是最隐蔽的一类问题。症状是配置看起来完全正确,nmcli也说激活成功了,但过一会儿地址自己变了或者消失了。
排查方法:
systemctl list-unit-files | grep -Ei 'network|netplan|wicked'如果看到systemd-networkd.service在enabled状态,同时NetworkManager也开着,那就找到问题的根源了。这两个服务都想去管同一张网卡,结果就是互相覆盖。处理方式很明确:留一个,关掉另一个。
systemctl disable --now systemd-networkd同样的道理适用于某些老系统上的network.service。停掉之后建议重启一次 NetworkManager,让它重新接管所有设备:
systemctl restart NetworkManager注意:
systemctl restart NetworkManager会造成短时间的网络中断,因为所有连接都会被重新激活。在远端执行这个命令之前,最好也挂上前面说的at回滚任务。
6.3 resolv.conf 被反复覆盖的真相
如果你发现手工改的/etc/resolv.conf过几分钟就被改回去,那说明有个服务在管它。查一下:
ls -l /etc/resolv.conf ps aux | grep -E 'resolved|dhclient|dhcpcd'如果resolv.conf是软链,那就是systemd-resolved在管,你要改配置得改nmcli里的ipv4.dns,它会通过 D-Bus 同步给resolved。如果是普通文件但内容里带# Generated by字样,说明是 NetworkManager 写的,同样要在nmcli里配。
还有一种情况是有人在/etc/dhcp/dhclient-enter-hooks.d/里放了脚本,每次 DHCP 续约就重写resolv.conf。这种脚本通常是历史遗留,找出来删掉或者改成走nmcli才是正路。
6.4 用-g和-t让输出适合脚本消费
排查到最后往往要写成脚本自动化,这时候nmcli两种输出格式就派上用场了。-t是 terse 模式,用冒号分隔字段,适合awk切;-g是 get 模式,直接只输出值:
# 只取值,适合脚本里判断 nmcli -g IP4.ADDRESS device show eth0 nmcli -g GENERAL.STATE device show eth0 # 制表符分隔,适合 awk nmcli -t -f NAME,DEVICE connection show-g输出的是属性路径,字段名写成大写的IP4.ADDRESS、GENERAL.STATE这种形式,和nmcli connection show里显示的字段名对应。写监控脚本或者健康检查的时候,这个组合比解析文本输出可靠得多。
7. 把配置变成可复用的资产
一台机器调好之后,同类机器还有几十台,这时候靠手敲就不现实了。
nmcli connection export可以把一份连接导出成 keyfile 格式:
nmcli connection export eth0-static /tmp/eth0-static.nmconnection导出的文件里带着 UUID 和interface-name,直接拿到别的机器上用nmcli connection load导入:
nmcli connection load /tmp/eth0-static.nmconnection但这里有个坑:UUID 会冲突。如果目标机器上已经有同名同 UUID 的配置,导入会失败或者覆盖。批量下发的时候我会先用sed把 UUID 行删掉,让 NetworkManager 在导入时自动生成新的:
sed -i '/^uuid=/d' /tmp/eth0-static.nmconnection sed -i 's/^interface-name=.*/interface-name=eth0/' /tmp/eth0-static.nmconnection nmcli connection load /tmp/eth0-static.nmconnection nmcli connection up eth0-static地址也得按机器改,所以实际下发时通常是用一个模板加变量替换,或者干脆直接调nmcli connection modify去改那几个关键字段,比整个文件搬过去更可控。
我个人在批量场景下更倾向于后一种做法:写一个脚本,参数是网卡名、IP、网关、DNS,内部就是add或者modify加上up和验证。这样每台机器上的配置文件都是本地生成的,不会出现 UUID、接口名这类残留问题。
#!/bin/bash set -e IFACE=$1; IP=$2; GW=$3; DNS1=$4; CONN="static-$1" if nmcli -t -f NAME connection show | grep -qx "$CONN"; then nmcli connection modify "$CONN" ipv4.addresses "$IP" ipv4.gateway "$GW" ipv4.dns "$DNS1" else nmcli connection add type ethernet con-name "$CONN" ifname "$IFACE" \ ipv4.method manual ipv4.addresses "$IP" ipv4.gateway "$GW" \ ipv4.dns "$DNS1" ipv4.ignore-auto-dns yes connection.autoconnect yes fi nmcli --wait 30 connection up "$CONN" ping -c 2 -W 2 "$GW" >/dev/null && echo "OK" || { echo "FAIL"; exit 1; }这个脚本里set -e和最后的ping验证是关键,前者让任何一步失败就停下,后者保证“命令成功”和“网络真的通了”是两件事。
最后分享一个我觉得最省事的习惯:改网络之前,先在另一个终端跑一条while true; do date; sleep 5; done,然后所有操作都在这个“心跳”窗口里做。SSH 一断,这个循环立刻停住,你一眼就能确认断在哪个时间点,配合journalctl --since精确到秒去看日志,比事后回忆强太多。另外,nmcli的所有属性名都支持 Tab 补全,nmcli connection modify eth0-static ipv4.<TAB><TAB>能列出全部可选项,不确定参数名的时候别去搜,直接按两下 Tab 比什么都快。