Ubuntu Server 从 17.10 版本开始,正式用 Netplan 取代了传统的 /etc/network/interfaces 配置方式。很多运维人员在面对多网卡绑定和 VLAN 隔离场景时,习惯性地去找 ifcfg-bond 或者直接写 systemd-networkd 配置,结果发现路径不对,配置不生效。Netplan 的核心逻辑是通过 YAML 文件描述网络拓扑,后端交由 systemd-networkd 或 NetworkManager 执行。理解这一点后,配置 Bonding 和 VLAN 其实比传统方法更直观,因为它把物理接口、聚合逻辑、虚拟子接口的层级关系用缩进语法清晰地表达出来了。

确认后端渲染器

在开始写配置之前,必须确认系统当前使用的渲染器。Netplan 配置文件的顶层有一个 renderer 字段,它决定了配置由谁接管。Ubuntu Server 默认使用 networkd,桌面版可能使用 NetworkManager。对于服务器多网卡绑定场景,强烈建议使用 networkd,因为它的链路聚合和 VLAN 支持更稳定,且不受图形界面干扰。检查 /etc/netplan/ 目录下的 YAML 文件,通常是 00-installer-config.yaml 或 01-netcfg.yaml。如果 renderer 字段缺失或指向 NetworkManager,需要修改为 networkd。这个细节容易被忽略,一旦渲染器不匹配,Bond 接口可能无法正常创建,或者重启后配置丢失。

物理接口的准备工作

多网卡绑定要求参与聚合的物理网口处于未配置状态,即它们不能有 IP 地址,也不能被其他网络服务占用。在 Netplan 里,这意味着这些接口在 YAML 中必须标记为 optional 且不分配 addresses。很多人在这里犯错,直接给物理口配了地址,然后试图在同一个 YAML 里创建 Bond,结果后端渲染时产生冲突。正确做法是,物理接口只保留基本描述,让它们作为 Bond 的成员存在。例如,假设有两个千兆网口 enp3s0 和 enp4s0,配置中它们只出现在 ethernets 段落里,并且除了 dhcp4: no 之外不写任何地址信息。

配置 Bond 接口

Netplan 支持多种 Bond 模式,对应内核 bonding 驱动的标准模式。生产环境最常用的是 802.3ad(LACP 动态链路聚合)和 balance-rr(轮询负载均衡)。LACP 需要交换机配合配置端口聚合,balance-rr 则不需要交换机支持,但可能导致数据包乱序。在 YAML 中,Bond 接口定义在 bonds 段落下。一个典型的 LACP 配置如下:

network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      optional: true
    enp4s0:
      dhcp4: no
      optional: true
  bonds:
    bond0:
      interfaces:
        - enp3s0
        - enp4s0
      parameters:
        mode: 802.3ad
        lacp-rate: fast
        mii-monitor-interval: 100
      addresses:
        - 192.168.10.10/24
      routes:
        - to: default
          via: 192.168.10.1
      nameservers:
        addresses:
          - 223.5.5.5
          - 223.6.6.6

这里有几个关键点。optional: true 确保物理接口即使没有获得 IP 也不会被 systemd-networkd 视为失败而长时间等待,从而加快系统启动。lacp-rate 设为 fast 可以让 LACP 协商更快完成,对故障切换敏感的场景很重要。mii-monitor-interval 设置链路监测间隔,单位为毫秒,100 毫秒是比较均衡的值。addresses 和 routes 直接写在 bond0 下面,这意味着 Bond 接口本身承载业务 IP 和默认路由。这种写法结构清晰,一个 YAML 文件就完成了从物理层到网络层的完整定义。

VLAN 子接口的创建

在实际运维中,服务器往往需要同时访问多个 VLAN 网段,比如管理网、业务网、存储网彼此隔离。传统做法是在交换机端口上配置 Trunk,然后在服务器端为 Bond 接口创建 VLAN 子接口。Netplan 通过 vlans 段落原生支持这一需求。VLAN 子接口的命名通常遵循 parent.vlan-id 格式,例如 bond0.100 表示 Bond 接口上承载 VLAN 100 的子接口。配置时,需要在 vlans 段落中指定 link 指向父接口,并设置 id 为 VLAN 号。示例如下:

  vlans:
    bond0.100:
      id: 100
      link: bond0
      addresses:
        - 10.0.100.10/24
      routes:
        - to: 10.0.0.0/8
          via: 10.0.100.1
    bond0.200:
      id: 200
      link: bond0
      addresses:
        - 172.16.200.10/24

这段配置在 bond0 上创建了两个 VLAN 子接口,分别对应 VLAN 100 和 VLAN 200。它们拥有独立的 IP 地址和路由规则,彼此完全隔离。注意,父接口 bond0 本身也可以拥有 IP 地址,它承载的是 Native VLAN 的流量。如果交换机端口配置了 Native VLAN,那么不打标签的帧就会进入 bond0;打上 VLAN 100 标签的帧则进入 bond0.100。这种层级关系在 Netplan 的 YAML 缩进中表现得非常直观。

混合场景:Bond + VLAN + 桥接

虚拟化环境里经常出现更复杂的拓扑,比如在 Bond 上创建 VLAN 子接口,再在 VLAN 子接口上搭建 Linux Bridge 供虚拟机使用。Netplan 同样支持这种嵌套。假设需要在 VLAN 100 上运行 KVM 虚拟机,可以这样写:

  bridges:
    br-vlan100:
      interfaces:
        - bond0.100
      addresses:
        - 10.0.100.1/24
      parameters:
        stp: false
        forward-delay: 0

这里 br-vlan100 桥接了 bond0.100,虚拟机接入该桥即可获得 VLAN 100 网段的 IP。stp 关闭是因为大多数虚拟化场景下不需要生成树协议,forward-delay 设为 0 可以加快桥接就绪速度。需要注意的是,一旦 VLAN 子接口被桥接,它的 IP 地址应该配置在桥接口上,而不是 VLAN 子接口本身,否则会导致二层转发异常。Netplan 的依赖解析会自动处理接口的创建顺序,先有 bond0,再有 bond0.100,最后是 br-vlan100,运维人员不需要手动编写启动脚本。

验证与调试技巧

写完 YAML 文件后,不要立即重启网络服务,先用 netplan try 命令测试。这个命令会应用新配置并等待用户确认,如果 120 秒内没有确认,自动回滚到旧配置。这在远程维护时是救命的功能,一旦配置有误导致网络中断,系统会自动恢复,避免失联。确认无误后,按回车键确认应用。如果配置没有生效,检查 /var/log/syslog 中 systemd-networkd 的日志,常见错误包括缩进不一致、Bond 模式写错、物理接口名称不匹配等。YAML 对缩进极其敏感,必须使用空格而非制表符,且同一层级缩进空格数必须相同。

另一个实用命令是 networkctl status bond0,它会显示 systemd-networkd 视角下的接口状态、地址、路由和 DNS 信息。如果 Bond 成员口显示 degraded,说明某个物理链路有问题。cat /proc/net/bonding/bond0 可以查看内核 bonding 模块的详细状态,包括每个从接口的 MII 状态、LACP 协商结果、当前活跃口等。这些信息在排查交换机端配置问题时非常关键。

性能调优与注意事项

Bond 模式的选择直接影响吞吐量和故障切换行为。802.3ad 模式要求交换机支持 LACP,且所有成员口速率必须一致。如果交换机不支持 LACP,可以选择 balance-xor 模式,它根据传输层哈希分流,不需要交换机配合,但链路故障时会有少量丢包。active-backup 模式提供最简单的冗余,总带宽等于单链路带宽,适合对带宽要求不高但可靠性要求极高的场景。对于存储网络,建议使用 802.3ad 配合 layer3+4 哈希策略,可以在 /etc/modprobe.d/bonding.conf 中设置 xmit_hash_policy=layer3+4,使 TCP 流更均匀地分布到各成员链路上。

VLAN 子接口的 MTU 需要特别注意。如果物理网络支持巨型帧,比如存储网络常用 9000 字节 MTU,那么 Bond 接口和所有 VLAN 子接口都必须设置相同的 MTU 值。Netplan 中可以在 bonds 和 vlans 段落分别指定 mtu 参数。不一致的 MTU 会导致 TCP 三次握手正常但数据传输阶段出现黑洞,这种故障非常隐蔽,往往表现为大文件传输失败或 SSH 会话卡死。

还有一个生产环境的实战经验:当 Bond 接口承载大量 VLAN 时,内核需要处理大量带标签的帧,可能触发某些网卡驱动的硬件卸载限制。如果发现丢包或性能下降,可以用 ethtool -K 命令关闭特定卸载功能,比如关闭 TSO 或 GSO,让内核软件处理。这类问题在万兆网卡和低端交换机组合时偶有出现,排查思路是先确认物理层无误,再检查驱动参数。

配置文件的组织方式

Netplan 支持在 /etc/netplan/ 目录下放置多个 YAML 文件,它们会按字典序合并。对于复杂环境,建议将物理接口定义、Bond 定义、VLAN 定义拆分到不同文件,比如 00-physical.yaml、10-bonds.yaml、20-vlans.yaml。这样做的好处是职责清晰,修改某个 VLAN 时不影响物理链路配置。但要注意,同一接口不能在不同文件中重复定义,否则 Netplan 会报错。所有文件的后缀必须是 .yaml,权限应为 600,防止敏感网络信息泄露。

当系统需要从传统 ifupdown 迁移到 Netplan 时,可以手动编写对应 YAML,也可以利用 netplan migrate 命令自动转换。但自动转换生成的配置往往比较冗余,建议理解原理后手工重写,使配置更简洁。迁移完成后,记得卸载 ifupdown 包,避免两个网络管理系统同时运行导致冲突。

故障案例与解决思路

场景一:Bond 接口创建成功,但无法 ping 通网关。检查 bond0 的 addresses 和 routes 是否正确,再用 ip route show 确认默认路由是否指向 bond0。如果路由表里出现了两条默认路由,可能是 NetworkManager 残留配置干扰,需彻底禁用 NetworkManager 服务。场景二:VLAN 子接口收不到数据包。确认交换机端口已配置为 Trunk 模式并允许对应 VLAN 通过,同时检查服务器端是否加载了 8021q 内核模块。虽然 Netplan 会自动加载该模块,但某些精简版系统可能缺失。lsmod | grep 8021q 可以验证。场景三:重启后 Bond 成员口随机变化。这是因为 systemd 的网卡命名规则可能不稳定,建议在 /etc/systemd/network/ 下创建 .link 文件,基于 MAC 地址固定物理接口名称,或者在 Netplan 中使用 match 字段按 MAC 地址匹配接口,而不是依赖内核命名。

Netplan 的 YAML 配置方式将网络拓扑的层级关系表达得清晰明了,多网卡绑定和 VLAN 子接口的组合配置不再需要分散在多个配置文件和启动脚本中。掌握这些核心写法后,运维人员可以快速构建高可用、多网段隔离的服务器网络,无论是物理机还是云上虚拟机,这套方法论都适用。