Contents

VMware ESXi Ubuntu 虚拟机库依赖缺失导致服务启动失败

Ubuntu 从 20.04 升级到 24.04 后,libcurl 与 libnghttp2 版本不匹配,导致 NetworkManager 启动时符号解析失败而崩溃,大量依赖网络的服务连锁失败。本文记录通过离线方式修复库依赖缺失、恢复系统服务的完整排查与解决过程。

目录


1. 问题现象

VMware ESXi 平台上的 Ubuntu 虚拟机开机后无法进入图形桌面环境,停留在命令行界面。

具体表现:

  • 系统可以正常引导,内核加载无异常
  • 文件系统检查通过,无损坏
  • 但大量系统服务启动失败,特别是 NetworkManager 服务反复崩溃重启
  • 无法使用网络功能,无法正常登录桌面

通过 journalctl -xb 查看启动日志,可以观察到大量服务报 Failed 状态,其中核心报错为:

NetworkManager: symbol lookup error:
/lib/x86_64-linux-gnu/libcurl-gnutls.so.4: undefined symbol:
nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation

2. 原因分析

2.1 直接原因

NetworkManager 在启动时加载 libcurl-gnutls.so.4(来自 libcurl 8.5.0),而该库在运行时需要解析 libnghttp2.so.14 中的符号 nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation

但系统中安装的 libnghttp2-14 版本(1.40.0)过低,该符号在 nghttp2 1.57 版本中才引入,导致动态链接器无法解析该符号,NetworkManager 进程启动失败并以退出码 127 退出。

2.2 根本原因

该虚拟机此前从 Ubuntu 20.04 升级到 Ubuntu 24.04。升级过程中,libcurl 相关包被升级到了 8.5.0(Ubuntu 24.04 版本),但 libnghttp2-14 没有同步升级,仍停留在 1.40.0(Ubuntu 20.04 版本)。

同时旧版的 libcurl4(7.68.0)未被正确清理,残留在系统中处于未配置状态(dpkg 状态为 iU),造成了包管理层面的版本混乱。

2.3 版本依赖关系

NetworkManager
    └── 依赖 libcurl-gnutls.so.4 (libcurl 8.5.0)
            └── 依赖 libnghttp2.so.14 中的符号
                    nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation
                    └── 该符号需要 nghttp2 >= 1.57
                            └── 系统中安装的是 1.40.0 ← 版本过低!

2.4 连锁影响

NetworkManager 崩溃后导致以下依赖它的服务连锁失败:

服务影响
NetworkManager-wait-online网络等待超时
SSSD 系列 socket 服务nss、pam、ssh、sudo 等身份认证不可用
gnome-shell同样因 libsoup-3.0.so.0 缺少 nghttp2 符号而崩溃
pipewire-pulsecups音频、打印等服务不可用

3. 解决方案

本方案需要在能联网的机器上提前下载 .deb 包,通过离线方式导入虚拟机。

3.1 第一步:确认问题包的版本信息

在虚拟机中执行以下命令,确认相关包的安装状态:

# 查看 libcurl 和 libnghttp2 的版本与状态
dpkg -l | grep -E "curl|nghttp2"

确认 libnghttp2-14 的版本号(例如 1.40.0),以及是否存在 iU(未配置)状态的残留包。

3.2 第二步:下载正确版本的 .deb 包

在能联网的机器上(物理机、其他虚拟机等),下载与系统版本匹配的 libnghttp2-14 包。

关键:版本必须 >= 1.59.0,否则仍然缺少所需的符号。

以 Ubuntu 24.04 (Noble) 为例,下载地址:

http://archive.ubuntu.com/ubuntu/pool/main/n/nghttp2/libnghttp2-14_1.59.0-1ubuntu0.3_amd64.deb

可访问 http://archive.ubuntu.com/ubuntu/pool/main/n/nghttp2/ 查看所有可用版本,选择 amd64 架构、ubuntu0.3 后缀的版本(表示 24.04 的安全更新版本)。

3.3 第三步:将 .deb 包传入虚拟机

由于虚拟机网络不可用,需要通过离线方式传入文件。推荐以下两种方法:

方法 A:VMware 共享文件夹

  1. 在 VMware 中右键虚拟机 → 设置 → 选项 → 共享文件夹 → 始终启用
  2. 添加一个 Windows 本地目录作为共享目录
  3. 将 .deb 文件放入该共享目录
  4. 在虚拟机中挂载并复制:
mkdir -p /mnt/hgfs
mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other
cp /mnt/hgfs/<共享目录名>/libnghttp2-14_*.deb /tmp/

方法 B:自建 ISO 镜像

  1. 使用 ImgBurn、7-Zip 等工具将 .deb 文件打包为 ISO 镜像
  2. 在 VMware 中将该 ISO 挂载到虚拟机的虚拟光驱
  3. 在虚拟机中挂载光驱并复制:
mount /dev/sr0 /mnt/cdrom
cp /mnt/cdrom/libnghttp2-14_*.deb /tmp/

3.4 第四步:安装更新版本的 libnghttp2-14

# 安装(会自动覆盖旧版本)
dpkg -i /tmp/libnghttp2-14_1.59.0-1ubuntu0.3_amd64.deb

# 确认版本已更新
dpkg -l | grep nghttp2

3.5 第五步:清理残留的旧版 libcurl4 包

检查 dpkg -l 输出中是否有状态为 iU 的 libcurl 相关包。如果有,强制移除:

dpkg --purge --force-all libcurl4

3.6 第六步:验证并启动服务

# 确认所需符号已存在于库文件中
nm -D /lib/x86_64-linux-gnu/libnghttp2.so.14 | grep nghttp2_option_set_no_rfc9113

# 重置失败状态并启动 NetworkManager
systemctl reset-failed NetworkManager
systemctl start NetworkManager

# 确认服务正常运行
systemctl status NetworkManager

NetworkManager 正常启动后,其他依赖它的服务(GNOME 桌面、SSSD、音频等)会自动恢复。

3.7 第七步:重启验证

reboot

重启后确认系统能正常进入图形桌面,所有服务正常运行。


4. 经验总结

经验说明
大版本升级后务必检查包状态执行 dpkg -l | grep iU 检查是否有未配置的残留包,及时清理
离线环境提前准备关键依赖包在有网络时下载好常用依赖包的 .deb 文件备用,避免故障时无法获取
升级时确保依赖链完整libcurl、nghttp2、libsoup 等库之间存在强依赖关系,升级时需要确保版本配套

本文章已被查看 0