上周有个朋友找我,说他的 Ubuntu Server 改完 IP 之后 SSH 直接断了,问我是不是网卡坏了。我让他把/etc/netplan/下的文件贴过来,一看renderer写的是 NetworkManager,而机器上 NetworkManager 服务根本没启用,netplan apply之后谁都不认这份配置,网卡就一直挂着 DHCP 的旧地址。这类问题我这些年遇到过太多次,根源都指向同一个认知盲区:把 netplan、NetworkManager、systemd-networkd 当成三个可以随便替换的东西。实际上它们压根不在一个层面上——一个是配置前端,两个是真正干活的后端守护进程。搞清楚这层关系,你在 Ubuntu、Debian、RHEL 上折腾网络配置时,基本不会再出现改完就断网、断网还得进机房的场面。这篇就把这三套东西的定位、配置文件格式、生成关系、实操命令和排查套路一次讲透,不管你是刚接手几台云主机的新手,还是天天跟几十台物理机打交道的运维,都能直接拿去用。1. 三个网络配置工具,到底谁在管哪一段1.1 从 ifupdown 到声明式配置,这次换代为什么发生早些年管 Linux 网络,基本是/etc/network/interfaces加ifup、ifdown那一套,也就是 ifupdown。它的模型是命令式的:你写好接口和参数,然后手动敲命令让脚本去执行。这套东西在单机、静态配置的场景下够用,但放在今天这个环境里就力不从心了。云主机开机能动态识别网卡、笔记本要随身切换 WiFi 和有线、容器和虚拟机需要大量虚拟网卡、服务器要做 bond 和 VLAN——ifupdown 的脚本模型处理这些组合时非常笨重,而且它只管启动时执行一次,运行期间的状态变化基本不跟进。systemd 生态起来之后,整个系统的服务管理都转向了声明式 状态机的思路。systemd-networkd 就是这套思路在网络层的落地:你描述期望的网络状态,守护进程持续比对现实和期望,不一致就修正。NetworkManager 走的是另一条路,它的出发点是桌面和移动场景,关注的是连接(Connection)这个概念,WiFi 热点切换、有线插拔、移动宽带、蓝牙共享全都归它管,还提供 D-Bus 接口给图形界面调用。netplan 出现得最晚,是 Ubuntu 在 17.10 前后推出来的。它要解决的具体痛点是:同是 Ubuntu,Server 版用 networkd、Desktop 版用 NetworkManager,配置方式完全不同,自动化部署脚本得写两套。netplan 的想法很直接——提供一个统一的 YAML 前端,后端由renderer字段指定,同一个 YAML 在两种环境下都能用。1.2 不是三选一:netplan 是前端,另外两个是后端这是最容易搞混的一点,也是我那位朋友踩坑的直接原因。三者的关系可以这样类比:netplan 像一份装修需求书,systemd-networkd 和 NetworkManager 是两个不同的施工队。需求书本身不会动手,它只负责把需求翻译成对应施工队能看懂的图纸。具体到文件流转上,过程是这样的:你写/etc/netplan/01-netcfg.yaml,执行netplan apply,netplan 读取 YAML 后按renderer字段分流。如果renderer: networkd,它就生成/run/systemd/network/10-netplan-网卡名.network这类文件,然后通知 systemd-networkd 重新加载;如果renderer: NetworkManager,它生成的是 NetworkManager 的 keyfile,扔到/run/NetworkManager/system-connections/下面。所以你在 Ubuntu Server 上systemctl status NetworkManager看到 inactive,是完全正常的,因为默认根本不走它。反过来,如果你在 renderer 写 networkd 的机器上手动用nmcli建了个连接,NetworkManager 又会和 networkd 抢同一块网卡,表现就是地址忽有忽无。判断当前机器实际用的是哪套,最直接的办法是看/run/systemd/network/和/run/NetworkManager/system-connections/这两个目录里有没有东西。组件层级定位配置来源典型使用场景netplan配置前端(翻译层)/etc/netplan/*.yamlUbuntu 系列统一配置入口systemd-networkd后端守护进程/etc/systemd/network/*.network服务器、云主机、容器宿主NetworkManager后端守护进程 连接管理keyfile 或 D-Bus桌面、笔记本、需要频繁切换网络ifupdown传统命令式脚本/etc/network/interfaces老旧系统、部分 Debian 环境1.3 选型之前先看清自己的发行版和使用场景很多人问到底该用哪个,我的回答永远先反问两个问题:你跑的是什么发行版,这台机器是服务器还是桌面。Ubuntu Server 从 17.10 起默认就是 netplan 加 systemd-networkd,桌面版是 netplan 加 NetworkManager(实际渲染到 NM)。Debian 服务器版长期默认 ifupdown,Debian 12 桌面才开始默认 NetworkManager。RHEL 8/9 和 Fedora 全线是 NetworkManager,而且 RHEL 9 之后旧的 ifcfg 格式虽然还能读,但新配置一律推荐 keyfile。Arch 比较自由,装什么用什么。场景维度上,判断标准更清楚:机器一旦跑起来就不动、不需要图形界面、也基本不插拔网卡,那 systemd-networkd 最省心,它轻、启动快、跟 systemd 集成度高。反过来,如果这台机器会连 WiFi、会切换网络、需要用图形界面点两下改配置、或者要配合云平台的一些网络管理逻辑,NetworkManager 才是对的选择。服务器上硬上 NetworkManager 不是不行,只是多了一层 D-Bus 和一套连接状态机,出问题时排查面反而更大。提示:不要在一台机器上同时启用 systemd-networkd 和 NetworkManager 去管理同一块物理网卡。两者都会尝试配置接口,冲突时的表现非常难查,通常是一方生效一方报错,日志里还各说各话。2. 核心机制拆解:配置怎么被读进去,谁最终碰了网卡2.1 netplan 的 YAML 结构、renderer 与生成物netplan 的配置文件放在/etc/netplan/下,后缀必须是.yaml,而且文件权限建议设成 600。这不是洁癖,netplan 自己会检查,权限过宽时会打印警告,某些版本甚至拒绝应用。文件名按字典序处理,01-、50-这种前缀就是为了控制加载顺序,后面的文件可以覆盖前面的同名配置。一份最基本的静态地址配置长这样:network: version: 2 renderer: networkd ethernets: ens33: dhcp4: false addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: [223.5.5.5, 119.29.29.29]几个关键点值得展开。version: 2是固定写法,不能省。顶层除了ethernets,还支持bonds、bridges、vlans、tunnels、wifis等类型,按需选用。renderer可以写在顶层作为全局默认,也可以写在单个网卡下面做局部覆盖,这个特性在做混合配置时很有用。最需要注意的是网关的写法。老教程里常见的gateway4: 192.168.1.1从 netplan 0.103 起就被标记为废弃,新版本会直接告警。正确做法是改用routes加to: default。这个变化很多人不知道,照抄旧文档后配置虽然还能用,但日志里一堆 deprecation 警告,升级系统时容易出问题。同样地,nameservers里可以配search域名后缀,在做内网 DNS 解析时很实用。2.2 systemd-networkd 的三类配置文件与匹配规则如果你跳过 netplan 直接写 networkd 配置,需要认识三类文件,它们分工明确。.network文件管地址、路由、DNS 等网络层参数;.netdev文件用来创建虚拟网络设备,比如 bond、bridge、vlan、vxlan;.link文件管更底层的链路参数,包括网卡重命名、MTU、MAC 地址策略。它们都存放在/etc/systemd/network/、/run/systemd/network/、/usr/lib/systemd/network/三个目录之一,优先级从高到低,同名文件高优先级目录会覆盖低优先级。匹配规则是 networkd 里最容易理解错的部分。每个.network文件开头有[Match]段,可以按网卡名(Name)、MAC 地址(MACAddress)、驱动、路径等条件匹配。networkd 会按文件名字典序依次读入,第一个匹配成功的.network生效,后面的就不再看了。这就是为什么文件名习惯用10-、20-前缀——你把更具体的规则放在前面。一份独立于 netplan 的静态配置示例:# /etc/systemd/network/10-static.network [Match] Nameens33 [Network] Address192.168.1.100/24 Gateway192.168.1.1 DNS223.5.5.5 DNS119.29.29.29 [Route] Destination10.0.0.0/8 Gateway192.168.1.1 Metric100改完执行systemctl restart systemd-networkd生效。注意这里用的Gateway是合法的,networkd 的 ini 语法跟 netplan 的 YAML 完全是两套东西,别把routes: to: default那套写法搬过来。2.3 NetworkManager 的连接模型与 keyfile 格式NetworkManager 的核心概念是连接(Connection),一个连接是一份完整的配置档案,网卡只是它绑定的目标设备。这个模型的好处是你可以给同一块网卡准备多份档案,比如公司有线家里有线,按优先级自动选择。配置存储有两种格式。老的是ifcfg-*,来自 Red Hat 系传统;新的是 keyfile,文件名形如xxx.nmconnection,放在/etc/NetworkManager/system-connections/,权限必须是 600,否则 NetworkManager 拒绝加载并在日志里抱怨。keyfile 的格式长这样:[connection] idstatic-ens33 typeethernet interface-nameens33 autoconnecttrue [ipv4] methodmanual address1192.168.1.100/24,192.168.1.1 dns223.5.5.5;119.29.29.29; dns-searchcorp.local [ipv6] methodignoreaddress1里逗号后面跟的是网关,这个写法跟其他工具都不太一样,第一次看到容易懵。另外 NetworkManager 默认会做连通性检查(连一个固定地址看能不能通),在一些纯内网环境下会一直报limited connectivity,看着像故障其实不影响使用,可以在配置里关掉。日常操作基本不用手写 keyfile,用nmcli命令行更省事,它改完会自动写成 keyfile 并重载。2.4 DNS 这件事,到底由谁负责DNS 这块是三大工具交叠最深的地方,也是最容易配了不生效的地方。现代 systemd 系统上,/etc/resolv.conf通常是一个软链接,指向/run/systemd/resolve/stub-resolv.conf,由systemd-resolved统一管理。也就是说,你直接编辑/etc/resolv.conf写 DNS,重启或者网络状态一变就会被覆盖回去。正确的做法是在配置源头写 DNS:netplan 里写nameservers,networkd 的.network里写DNS,NetworkManager 里写ipv4.dns。这些配置会被传给 systemd-resolved,由它按网卡分别记录并按优先级查询。验证 DNS 是否生效,不要只cat /etc/resolv.conf,那个文件看不出哪块网卡贡献了哪些服务器。用resolvectl status看,它会按接口列出当前生效的 DNS、搜索域和 DNSSEC 状态,信息完整得多。如果发现某块网卡的 DNS 没进去,基本就是配置文件的位置或者字段名写错了。注意:如果 systemd-resolved 服务没启用,而/etc/resolv.conf又指向了 stub 文件,会出现域名完全解析不了的情况。这种时候要么启用 resolved,要么把软链接改回真实的 resolv.conf 文件,别两个都不管。3. 实操:几套最常用的配置照着抄3.1 netplan 加 networkd:给 Ubuntu Server 配静态 IP这是服务器上最高频的操作,也是远程操作风险最大的操作。流程我建议固定成四步,顺序别换。第一步,先确认网卡名和现有配置:ip -br link ls /etc/netplan/ cat /etc/netplan/*.yaml第二步,备份原文件。这一步别偷懒,尤其你是通过 SSH 连上去的时候:sudo cp /etc/netplan/01-netcfg.yaml /etc/netplan/01-netcfg.yaml.bak第三步,写新配置。假设网卡是ens33,要设成192.168.1.100/24,网关192.168.1.1:network: version: 2 renderer: networkd ethernets: ens33: dhcp4: false dhcp6: false addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: [223.5.5.5, 119.29.29.29]第四步,也是关键的一步,用netplan try而不是直接apply:sudo chmod 600 /etc/netplan/01-netcfg.yaml sudo netplan trynetplan try会应用配置并启动一个 120 秒的倒计时,期间你在另一个终端确认网络是不是通的。如果配错了导致断网,什么都不用做,等倒计时结束它会自动回滚到之前的配置。这个机制救过我至少三次,尤其是在改远程机器的默认网关时。确认没问题后按回车接受,配置就固化了。真要直接应用,也可以先netplan generate看看生成的产物对不对,再netplan apply。3.2 nmcli:桌面和笔记本上的首选NetworkManager 环境下我基本不手写配置文件,nmcli已经足够覆盖 95% 的场景。先看现状:nmcli device status nmcli connection show写一个静态有线连接:nmcli connection add type ethernet con-name static-ens33 ifname ens33 \ ipv4.method manual \ ipv4.addresses 192.168.1.100/24 \ ipv4.gateway 192.168.1.1 \ ipv4.dns 223.5.5.5 119.29.29.29 \ ipv6.method ignore nmcli connection up static-ens33如果是 WiFi:nmcli device wifi list nmcli device wifi connect 你的SSID password 你的密码改已有连接不用删了重建,直接改属性再拉起来就行:nmcli connection modify static-ens33 ipv4.addresses 192.168.1.101/24 nmcli connection up static-ens33有一个细节值得说:nmcli connection modify之后连接不会自动重启,必须显式up一次,或者用nmcli connection reload让改动落到磁盘。这点跟很多人的直觉相反,他们以为改完就生效了,结果一直在测旧地址。3.3 systemd-networkd 裸配置文件:不依赖 netplan 的写法Debian 服务器、Arch、以及一些定制镜像上不一定装 netplan,那就直接写 networkd 配置。以配置 bond 为例,需要.netdev加.network两个文件配合。先建 bond 设备:# /etc/systemd/network/10-bond0.netdev [NetDev] Namebond0 Kindbond [Bond] Modeactive-backup MIIMonitorSec100ms再把两块物理网卡绑进去:# /etc/systemd/network/20-bond0-slave1.network [Match] Nameens33 [Network] Bondbond0# /etc/systemd/network/21-bond0-slave2.network [Match] Nameens34 [Network] Bondbond0最后给 bond0 本身配地址:# /etc/systemd/network/30-bond0.network [Match] Namebond0 [Network] Address192.168.1.100/24 Gateway192.168.1.1 DNS223.5.5.5文件编号的顺序在这里很讲究:.netdev要先于引用它的.network被读取,slave 的绑定要先于给 bond 配地址。用 10、20、21、30 这样的编号就是为了保证加载顺序正确。改完统一重启服务:sudo systemctl restart systemd-networkd sudo networkctl status bond03.4 稍微复杂一点的场景:VLAN 与网卡重命名VLAN 在 netplan 里的写法比想象中简洁,不需要单独建设备文件:network: version: 2 renderer: networkd ethernets: ens33: dhcp4: false vlans: vlan100: id: 100 link: ens33 addresses: [10.0.100.2/24] routes: - to: default via: 10.0.100.1link指向父接口,id是 VLAN tag,netplan 会自动生成对应的.netdev和.network。用 nmcli 做同样的事:nmcli connection add type vlan con-name vlan100 ifname ens33.100 \ dev ens33 id 100 \ ipv4.method manual ipv4.addresses 10.0.100.2/24网卡重命名解决的是另一个烦人问题:虚拟机克隆或者换硬件后,网卡名从ens33变成了ens34,所有配置全失效。用 netplan 的match加set-name,按 MAC 地址锁定并重命名:network: version: 2 renderer: networkd ethernets: lan0: match: macaddress: 52:54:00:12:34:56 set-name: lan0 dhcp4: true这样不管系统原本给它起什么名,最终都会被改成lan0,配置文件不用动。同样的功能在 networkd 里用.link文件实现,在 NetworkManager 里可以用connection.interface-name配合ethernet.mac-address完成。3.5 改完之后怎么验证:命令清单配置改完别急着关终端,下面这套命令走一遍,基本能覆盖所有常规问题。用途命令说明看接口和地址ip -br a一屏看完所有接口状态看路由表ip route show确认默认路由存在看 networkd 状态networkctl status ens33显示地址、网关、DNS、状态机看 NM 设备状态nmcli device status区分 connected/disconnected/unmanaged看 DNS 生效情况resolvectl status按接口列出 DNS 和搜索域看 netplan 生成物ls -l /run/systemd/network/确认 YAML 真被翻译成了后端配置看服务日志journalctl -u systemd-networkd -b排查匹配失败、地址冲突调试 apply 过程sudo netplan --debug apply输出翻译和后端重载的详细过程这张表里我最常用的是networkctl status和resolvectl status。前者能直接告诉你某块网卡的配置是从哪个文件来的、DHCP 有没有拿到租约、状态机停在哪一步;后者能确认 DNS 到底有没有被正确下发。很多能通 IP 但解析不了域名的问题,用这两条命令三分钟就能定位。4. 常见故障与排查实录4.1 故障速查表网络配置故障有个特点:现象类似但根因完全不同,盲目重启服务往往解决不了问题。下面这张表是我这些年攒下来的对应关系,按现象查更快。现象最可能的原因排查入口netplan apply后 SSH 断连地址或网关写错,或配了不存在的网卡名用netplan try重来,本地控制台检查接口一直没地址网卡名不匹配,配置文件里 Match 条件写错networkctl status看匹配结果有地址但没默认路由用了废弃的gateway4,或路由表被覆盖ip route show确认DHCP 拿不到地址DHCP 客户端与后端冲突,或网卡被标记 unmanagednmcli device status看是否 unmanaged域名解析失败resolv.conf 指向 stub 但 resolved 未启动resolvectl status直接看改配置不生效存在多份配置文件互相覆盖,或权限不对看/etc/netplan/全部文件,检查 600 权限WiFi 连不上但密码正确连接档案里旧密码残留,或频段不匹配nmcli connection show name逐项看重启后配置丢失改的是/run下的运行时文件而非/etc确认修改路径4.2 我自己踩过的几个坑坑一:把运行时目录当配置目录改。有一次我在/run/systemd/network/下发现一份配置写得不对,顺手改了,当时生效了,重启之后一切回到原样。这个目录是 netplan 或 systemd 自动生成的,每次启动都会重建,只读不写。真正要改的源头在/etc/netplan/或者/etc/systemd/network/。坑二:YAML 缩进用了 Tab。YAML 规范禁止用 Tab 做缩进,netplan 报的错误信息又比较含糊,只说解析失败,不告诉你在第几行。我后来养成习惯,netplan 文件一律用两个空格,写完先python3 -c import yaml,sys; yaml.safe_load(open(sys.argv[1])) 文件路径验一遍语法,比事后猜快得多。坑三:在 renderer 与后端不匹配的机器上硬改。就是我那位朋友的情况。判断方法很简单,看服务状态加目录内容:systemctl is-active systemd-networkd systemctl is-active NetworkManager ls /run/systemd/network/ 2/dev/null ls /run/NetworkManager/system-connections/ 2/dev/null哪个目录有内容,哪个服务 active,就说明这套在管事。如果两边都有内容,那就是配置打架了,得先把其中一套停掉并清理掉它管的接口。坑四:改完不做回滚保护。远程改网络最怕的就是改完立刻断,断了还没有本地访问途径。我现在固定做法是:能用netplan try就用;不能用的话,先挂一个后台延时任务,比如sleep 300 cp 备份文件 原文件 netplan apply,相当于给自己留了五分钟后悔时间;再不济,提前确认好带外管理或者云控制台的 VNC 能用。提示:如果机器在云上,改网络配置前一定先在控制台确认串口或 VNC 登录可用,再动手。很多云主机的重置密码重启功能都依赖网络,机器断网之后这些功能基本等于没有。5. 混合环境下的共存与迁移5.1 netplan 与 NetworkManager 同时存在时的边界Ubuntu 桌面版是这种共存最典型的环境:netplan 装在系统里,NetworkManager 也在跑,/etc/netplan/下还有一份 YAML。这时候到底谁说了算?规则其实很明确:netplan 只处理它生成的配置,而它生成的内容会落到/run/NetworkManager/system-connections/,然后由 NetworkManager 加载执行。也就是说,对于 netplan 管到的那块网卡,你不能同时再用nmcli connection add建一个同名设备的新连接,否则会出现两个连接抢同一接口,自动连接时谁先谁后完全看优先级和状态。实用的判断方法是看 NetworkManager 有没有把接口标成 unmanaged:nmcli device status如果某块网卡显示 unmanaged,说明它被 netplan 或者/etc/NetworkManager/conf.d/里的规则排除在 NetworkManager 管辖之外了。想在桌面上完全用 nmcli 接管,那就把 netplan 里关于这块网卡的配置删掉,只保留别的部分,或者干脆把 YAML 里的renderer改成NetworkManager,让 netplan 直接翻译成 NM 的连接文件。一个容易忽略的点是配置文件的生命周期。/run/NetworkManager/system-connections/是运行时目录,重启就没了,内容完全由 netplan 重新生成。所以你在桌面版上如果手动往/etc/NetworkManager/system-connections/写了一个连接,它和 netplan 生成的那些是共存的,两边都可能生效。想让手写的那份稳定起作用,就得保证 netplan 不碰同一块网卡。5.2 从 ifupdown 迁过来的注意事项老机器升级或者接手别人的 Debian 服务器时,常遇到/etc/network/interfaces里留着配置,同时又装了 NetworkManager 或 systemd-networkd 的情况。这种三套并存的状态,排查起来极其痛苦,因为任何一套都可能在某次启动时抢先配置网卡。迁移步骤我一般这么走。第一,先把现有 interfaces 文件完整备份,并记录当前实际生效的地址、路由、DNS,用ip a、ip r、resolvectl status三件套存成文本。第二,决定目标后端,服务器优先选 systemd-networkd,桌面选 NetworkManager。第三,把 interfaces 里的配置逐条翻译过去,注意 ifupdown 的post-up那类钩子脚本不能直接照搬,需要用 systemd 的服务单元或者 NetworkManager 的 dispatcher 脚本替代。第四,禁用 ifupdown 的服务,Debian 上是systemctl disable --now networking,然后启用目标后端。翻译过程中有几个细节容易出问题。ifupdown 的dns-nameservers依赖 resolvconf,迁到 networkd 之后要改成.network文件里的DNS,否则 DNS 会丢。allow-hotplug这种配置在声明式模型里没有直接对应物,networkd 会自动处理热插拔,不需要额外声明。静态路由的写法差异也大,ifupdown 用up ip route add,networkd 用[Route]段,netplan 用routes列表,三者语法完全不同,千万别混着写。迁移完跑一段时间观察日志,重点看journalctl -b里有没有多个服务同时报同一块网卡的错误。确认干净之后再把旧配置彻底删掉,别留着当备份,留着就是隐患。我个人在实际操作中的体会是,这三套工具本身没有优劣,真正的坑都来自没搞清楚哪一套在管事。所以每次接手一台新机器,我第一件事不是改配置,而是先花三分钟把服务状态、配置目录、运行时生成物这三处看一遍,把链条理顺。理清之后,不管是加 VLAN、配 bond 还是把地址从 DHCP 换成静态,都是几分钟的事;理不清,就会出现改一处坏一处的连锁反应,越修越乱。
