systemd-networkd 与 netplan 网络配置实战:告别 ifupdown 的静态 IP、网桥与多网卡管理全流程

为什么要放弃 ifupdown 改用 systemd-networkd

很多从 CentOS 时代过来的站长,习惯了一辈子只用 ifcfg-eth0 和 /etc/network/interfaces。这套配置方式确实简单直观,但它有两个绕不开的硬伤:一是"配了不一定生效",改了文件之后必须手动 ifdown/ifup,中间那几秒服务器会短暂断网,如果是远程 SSH 操作,手一抖就再也连不上了;二是它和现代网络管理栈(NetworkManager、netplan、systemd-networkd)互相打架,谁最后启动谁说了算,导致"我明明改了配置,重启后又变回去了"这种经典疑难杂症。

systemd-networkd 是 systemd 家族里负责网络配置的守护进程。它不是简单的"配置文件换个位置",而是彻底改变了网络配置的模型:它是声明式的,你只描述"我要什么状态",由它负责让系统收敛到这个状态;它是事件驱动的,网卡插拔、DHCP 租约到期、路由变化都会实时响应;它是可组合的,把"配置网络设备"和"配置网络连接"拆成两个独立对象,复用一个连接配置可以套到多个网卡上。

对个人站长来说,systemd-networkd 有三个实际好处:第一,它是随系统启动的,配置改完 networkctl reload 就能平滑生效,不需要 ifdown 那一刀;第二,它天生支持多网卡、网桥、VLAN、Bond,一台 VPS 上做复杂网络拓扑不用装额外工具;第三,它的日志走 journald,排查时 journalctl -u systemd-networkd 一条命令就能把网卡为什么没起来看得清清楚楚。

核心概念:.network、.netdev、.link 三类配置文件

systemd-networkd 的配置全在 /etc/systemd/network/ 目录下,按扩展名分成三类,理解这三类就理解了一切:

  • .link 文件——作用于"物理设备本身",按 MAC 地址或网卡名匹配。它的典型用途是给网卡改名(比如把 enp3s0 固定改名成 wan0)、调整 MTU、开关某个特性。它在网卡一出现时就生效,早于 .network。
  • .netdev 文件——用来"创建虚拟网络设备",比如网桥(Bridge)、聚合口(Bond)、VLAN、VXLAN、隧道。只有需要创建虚拟设备时才写,普通物理网卡直接用 .network 即可。
  • .network 文件——作用于"网络连接",按网卡名匹配,负责配 IP、网关、DNS、路由。这是最常用的类型。

排序规则很关键:.link 先于 .netdev,.netdev 先于 .network。命名上建议用数字前缀控制优先级,例如 10-wan0.link、20-br0.netdev、30-br0.network。匹配用的是通配符,Match 段里可以写 Name=en*、MACAddress=xx:xx:xx:xx:xx:xx,多个条件之间是"与"关系,满足全部条件才匹配。

实战第一步:用 .network 配置静态 IP

假设我们在 Debian 12 上有一块网卡 ens3,要配成静态 IP。先确认网卡名字和当前状态:

ip -br link
networkctl status ens3

然后创建配置文件 /etc/systemd/network/20-ens3.network:

[Match]
Name=ens3

[Network]
Address=203.0.113.10/24
Gateway=203.0.113.1
DNS=1.1.1.1
DNS=8.8.8.8
IPv6AcceptRA=no

这里有两个易错点。第一,Address= 后面的掩码是CIDR 前缀(/24),不是传统的 255.255.255.0,写成点分十进制会直接报错。第二,Gateway= 只应在一个 .network 文件里出现,如果在多块网卡上都写了默认网关,systemd-networkd 会按文件名顺序取第一个,另一个静默失效——这是"双网卡服务器默认路由乱跳"的常见根因。

要配 DHCP 则更简单:

[Match]
Name=ens3

[Network]
DHCP=yes

IPv4 和 IPv6 可以分开控制,DHCP=ipv4 或 DHCP=ipv6。如果想保留 DHCP 分配的地址同时再叠加几个静态地址,用 DHCP=yes 配合额外的 Address= 行即可,两者是叠加而非互斥关系。

让配置生效:平滑 reload 而不是 ifdown

这是 systemd-networkd 相比 ifupdown 最爽的地方。改完配置后执行:

systemctl restart systemd-networkd

注意这里是 restart 而不是 reload。很多人以为网络配置应该用 reload,但 systemd-networkd 的 reload 只是重新读取磁盘上的配置文件、不重新应用到已配置的接口,所以"我 reload 了怎么没变化"就成了高频疑问。真正要让新配置作用于接口,要么 restart 服务(它会重新处理所有接口),要么对单个接口执行:

networkctl reconfigure ens3

用 reconfigure 单接口是远程操作时最安全的方式——它只重配指定网卡,其他网卡和现有连接不受影响。即便如此,改 IP 类操作仍建议提前准备一条带外通道(VNC 控制台或云厂商的救援模式),因为一旦新 IP 网段填错,SSH 会话会在几秒后断开且无法恢复。

验证是否生效,用 networkctl 而不是传统 ip addr 就能看到更多信息:

networkctl status ens3
networkctl list

networkctl list 会列出所有接口及其状态(configured 表示已按 .network 文件配置成功,unmanaged 表示没有被 systemd-networkd 接管)。如果某个网卡显示 unmanaged,说明没有匹配的 .network 文件,这是个非常好用的自检信号。

进阶一:用 .netdev 创建网桥 br0

把多块网卡桥接成一个二层交换域,是自建 KVM 虚拟机、跑 LXC 容器时最常见的需求。systemd-networkd 里分两步走。

第一步创建虚拟网桥设备 /etc/systemd/network/20-br0.netdev:

[NetDev]
Name=br0
Kind=bridge

[Bridge]
STP=no

个人服务器上通常关掉 STP(生成树协议),因为只有一个网桥不存在环路,开着 STP 反而会让首次转发延迟几十秒。

第二步创建网桥的连接配置 /etc/systemd/network/30-br0.network,把 IP 配在网桥上而不是物理口上:

[Match]
Name=br0

[Network]
Address=192.168.10.1/24
DNS=192.168.10.1

第三步创建物理口的"从属"配置 /etc/systemd/network/30-ens4.network,把它挂到网桥上,注意不要给物理口配 IP:

[Match]
Name=ens4

[Network]
Bridge=br0

这里最容易踩的坑是:给物理口和网桥都配了 IP,结果物理口上的 IP 直接可达、网桥上的 IP 又不可达,虚拟机的流量全乱。记住一条铁律:被桥接的物理口只做"线",不配 IP;IP 只配在网桥这个"逻辑交换机"上。

进阶二:netplan——Ubuntu 的抽象层

Ubuntu 从 17.10 开始引入了 netplan,它本身不是网络守护进程,而是一个YAML 格式的配置抽象层,负责把你的意图翻译成 systemd-networkd 或 NetworkManager 能懂的配置。也就是说,Ubuntu 上你写的是 /etc/netplan/xx.yaml,真正干活的还是 systemd-networkd。

一个静态 IP 的 netplan 配置长这样(/etc/netplan/01-netcfg.yaml):

network:
  version: 2
  renderer: networkd
  ethernets:
    ens3:
      addresses:
        - 203.0.113.10/24
      routes:
        - to: default
          via: 203.0.113.1
      nameservers:
        addresses: [1.1.1.1, 8.8.8.8]

写完执行校验和套用:

netplan try

netplan try 会在应用前给你一个 120 秒的回滚窗口——如果改变了 IP 导致 SSH 断开,时间一到它会自动回滚到旧配置。这是 netplan 相比裸改 systemd-networkd 最大的人性化设计,远程改网络一定要先用 netplan try 而不是 netplan apply。

netplan 的 YAML 有两个必须注意的细节:一是缩进必须用空格、绝对不能有 Tab,一个 Tab 就能让整个文件解析失败;二是 routes 段里新版语法用 to: default(旧版是 gateway4),写成旧语法虽有兼容但会打印废弃警告。改完 netplan 后 systemd-networkd 会被自动触发重载,不需要你手动 restart。

真实场景:一次"配置正确却连不上"的排查

我在一台 Debian 12 的 VPS 上做过一次网络迁移:把原来 ifupdown 管的 eth0 换成 systemd-networkd 管的 ens3。配置写好后 networkctl list 显示 configured,ip addr 也能看到正确的 IP,但就是 ping 不通网关。

排查过程是这样的:先看服务日志,journalctl -u systemd-networkd -n 50 显示接口配置成功,没有报错;再看路由,ip route 发现默认路由是有的;接着查 ARP,ip neigh 显示网关的 MAC 地址状态一直是 FAILED。这说明二层就不通,问题不在 IP 层。

最后定位到根因:原来的 ifupdown 配置里有个 mtu 1400 的设定(某些云厂商的 overlay 网络要求),而新的 .network 文件漏了这个参数,接口用了默认 MTU 1500。云厂商的封装网络对超长帧做了丢弃,导致网关 ARP 请求被吞。在 [Link] 段加上 MTUBytes=1400 后立刻恢复。

这个案例的教训是:迁移网络配置时,必须逐条清点旧配置里的每一个非默认参数(MTU、MAC、bond 参数、VLAN ID 等),不能只搬 IP 和网关。systemd-networkd 的默认值很可能和旧配置的默认值不一样,而这些差异平时不显山露水,只在特定网络环境下才暴露。

五个必踩的坑

  • 混淆 reload 与 restart:改配置后 reload 不生效,要用 restart 或 networkctl reconfigure。这是最高频的疑问。
  • 多网卡都写默认网关:只有一个 .network 文件的 Gateway 会生效,其余静默失效。多网卡要用静态路由策略而不是多个默认网关。
  • 网桥物理口也配 IP:物理口只做线不配 IP,IP 只配网桥。否则虚拟机和宿主机流量走向混乱。
  • netplan 用了 Tab 缩进:YAML 只认空格,一个 Tab 就解析失败,而且报错信息很含糊,肉眼看不出哪里错了。
  • 改远程网络不准备带外通道:无论是 networkd 还是 netplan,改 IP 前先确认云控制台 / VNC 能进,且优先用 netplan try 或 networkctl reconfigure 这种带保护的操作。

总结:什么时候该用 systemd-networkd

systemd-networkd 不是"更好的 ifupdown",而是为现代场景设计的网络管理栈。它的价值在复杂拓扑下才充分体现:多网卡、网桥、Bond、VLAN、隧道这些需求,用 systemd-networkd 只需要几个声明式文件,而用 ifupdown 要写一堆 pre-up 脚本还不一定稳妥。

对个人站长而言,一个务实的迁移路径是:新装机器(Debian 12 / Ubuntu 22.04 之后)直接用 systemd-networkd 或 netplan;老机器如果只有一张网卡、一个静态 IP,继续用现有方式也没问题,不必为了迁移而迁移。真正需要迁移的信号是:你开始需要网桥、Bond,或者厌倦了改配置必须 ifdown 掉线的提心吊胆。那时候,systemd-networkd 会给你一个更稳、更可观测、更容易回滚的网络层。

Last modification:October 14th, 2026 at 12:25 pm

Leave a Comment