服务器启动慢排查:systemd-networkd-wait-online 等空网口 2 分钟的根因与 netplan optional 修复

九月 09, 2026 [Linux 与系统] #systemd #kunpeng #arm64

一、现象

鲲鹏 920 推理服务器(Ubuntu 22.04,ACPI 启动,网卡 4× 25G)重启后,ssh 轮询要等 2~4 分钟才通。量一下到底慢在哪:

$ systemd-analyze time
Startup finished in 19.274s (kernel) + 2min 35.437s (userspace) = 2min 54.712s
graphical.target reached after 2min 34.379s in userspace

$ systemd-analyze blame | head
2min 141ms systemd-networkd-wait-online.service   ← 主犯:恰好 120s 超时 + 启动偏移
   30.368s snapd.seeded.service                    ← 次犯:LXD snap 激活链
   30.291s snap.lxd.activate.service
   30.270s snapd.service

注:kernel 19.3s 是这台机器的硬件底数(ACPI 设备多、PCIe/固件初始化慢,Run /init 要到 10.8s),不是这里要解决的问题。

二、根因:netplan 给没插线的口也配了 DHCP

$ networkctl list
IDX LINK     TYPE     OPERATIONAL SETUP
  2 enp2s0f0 ether    routable    configured    ← 唯一在用的口(静态 IP)
  3 enp2s0f1 ether    no-carrier  configuring   ← 没插线,永远 configuring
  4 enp2s0f2 ether    no-carrier  configuring
  5 enp2s0f3 ether    no-carrier  configuring

netplan 配置(subiquity 装机生成)把 4 个口全配了:

network:
  ethernets:
    enp2s0f0:            # 静态 192.168.6.8/22,实际在用
      addresses: [...]
    enp2s0f1:            # dhcp4: true,但没插网线
      dhcp4: true
    enp2s0f2:            # 同上
      dhcp4: true
    enp2s0f3:            # 同上
      dhcp4: true

机制:systemd-networkd-wait-online 默认等所有被管理接口 online(systemd 249 行为);无载波口(NO-CARRIER)在 networkd 里永远停在 configuring → 等到 120s 超时 → network-online.target 延后 → graphical.target 晚到 2 分钟。多网口服务器只要有一个口没插线/没配好就会踩中。

三、修复:netplan optional: true

给这些"可能有线、可能没有"的口加 optional(渲染成 networkd 的 RequiredForOnline=no,wait-online 不再等它们;将来插线 DHCP 照常工作):

    enp2s0f1:
      dhcp4: true
      optional: true     # ← 与 dhcp4 同级(6 空格缩进)
    enp2s0f2:
      dhcp4: true
      optional: true
    enp2s0f3:
      dhcp4: true
      optional: true
sudo chmod 600 /etc/netplan/00-installer-config.yaml   # netplan 警告权限过宽
sudo netplan generate    # 语法/渲染检查(只生成不应用)
sudo netplan apply

验证渲染结果(optional 是否生效看这里):

$ cat /run/systemd/network/10-netplan-enp2s0f1.network
[Match]
Name=enp2s0f1

[Link]
RequiredForOnline=no     # ← 有此行 = wait-online 不再等它

$ grep -c RequiredForOnline /run/systemd/network/10-netplan-enp2s0f0.network
0                          # 在用的口保持 required(0 行)

四、结果

指标修复前修复后
总启动2min 54.7s1min 2.6s
userspace2min 35s43.2s
networkd-wait-online2min 141ms8.5s(f0 一 online 就退出)

剩余大头:snapd.seeded/snap.lxd.activate ~30s(不用 LXD 可 sudo snap disable lxd),未处理。

五、操作坑记录

  1. netplan try 在非交互环境会白等:ssh 无 tty 无法按回车确认,15s 超时后自动 Reverting.,改动不生效。非交互请用 netplan generate(校验)+ netplan apply(应用)。
  2. 判断文件是否被回滚别用 grep -A1:只显示匹配行后 1 行,容易误判"optional 丢了",导致重复追加产生重复键。改完直接 cat 全文核对。
  3. sed 追加不幂等:重复执行会叠行。稳妥写法是先删后加(sed -i '/^ optional: true$/d' 再 append)。
  4. gateway4 已废弃的警告可忽略(新语法用 routes:)。
  5. apply 瞬间 enp2s0f0 的 IP 会短暂消失(networkd 重载),ssh 若恰好断开属正常,等几秒重连即可——建议在串口/SOL 会话里做网络变更。

六、wait-online 其他解法对比(合并自旧笔记)

除 netplan optional: true 外,还有几个常见做法,按"是否动全局行为"排列(本案例最终选 optional,因为它最精准:只声明"这几个口不需要等",不动 wait-online 对其它接口/服务的语义):

① --any:任意一个接口 online 即返回(2025-10-30 旧笔记方案)

sudo tee /etc/systemd/system/systemd-networkd-wait-online.service.d/any.conf <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any
EOF
sudo systemctl daemon-reload

适用:服务器出口只有一条主链路、其它口爱配不配。代价:任何口(哪怕是 docker0/备用口)先 online 就放行,可能"网没真正通"就继续启动。

② 缩短超时 + 指定等待接口(2025-11-23 旧笔记方案)

sudo systemctl edit systemd-networkd-wait-online.service
# [Service]
# TimeoutStartSec=5
# ExecStart=
# ExecStart=/lib/systemd/systemd-networkd-wait-online --interface=eth0 --interface=eth1
# 排除不想等的口:
# ExecStart=/lib/systemd/systemd-networkd-wait-online --exclude=vpn0

wait-online 的 120s 来自 service 自身的 TimeoutStartSec(Ubuntu 249 unit 默认 120),缩短它 + --interface 显式点名要等的口。代价:仍可能因点名口没插线而等满新超时;--exclude 对新装口不免疫。

③ disable / mask:完全不等待

sudo systemctl disable systemd-networkd-wait-online.service --now   # 或 mask

最粗暴。依赖 network-online.target 的服务(部分 docker/cloud-init/挂载场景)可能在网络就绪前启动——2025-11-23 旧笔记自己都提醒:接口一直起不来时,disable 只是把问题藏起来,先按第七节诊断根源。

为什么本案例用 optional 而不是上面几种:这台机器 4 个口是"常态只插 1 个、偶尔插 2-3 个",不是"永远不用"。optional: true 让没插线的口随时可以被 networkd 管理(插线即 DHCP),又不阻塞开机;wait-online 的默认语义(等所有"必需"接口)对其他服务保持不变。三种旧方案要么改全局语义(--any)、要么点名维护(--interface)、要么彻底关掉(disable),都不如"按接口声明必需性"干净。

七、排查命令清单(复用)

systemd-analyze time && systemd-analyze blame | head -10   # 定位耗时 service
networkctl list                                             # 看被管理接口状态(no-carrier + configuring = 嫌疑)
cat /etc/netplan/*.yaml                                     # 谁配了它
ip -br link                                                 # 物理层是否真的没插线
cat /run/systemd/network/10-netplan-<iface>.network         # optional 是否渲染成 RequiredForOnline=no
sudo journalctl -b -u systemd-networkd-wait-online          # 确认它的等待行为