背景与需求
在特定的运维场景下,我们有时需要对系统环境进行极其严格的控制。最近我就遇到了这样一个需求:
- 固定内核版本:业务要求必须使用特定版本的 Linux 内核(
5.15.0-60-generic),不能随意升级。
- 一次性网络配置:Ubuntu 安装后,默认的
/etc/netplan/00-installer-config.yaml 配置文件容易被 cloud-init 等工具覆盖重写。为了避免后续每次手动调整的麻烦,我希望在系统安装阶段就能将静态 IP 地址一步配置到位。
- 交付形式:最终交付物是一个基于 KVM 的虚拟机,并且需要配置为桥接(Bridge)模式接入网络。
常规方法的困境
一开始,我尝试了常规的 virt-install 流程:先创建虚拟机但不启动,然后通过 virsh edit 修改其 XML 定义,将网络模式从默认的 NAT 改为桥接,最后再启动并开始安装。
这个方法在只配置静态 IP 时是可行的。但当引入“禁止内核升级”这个新条件时,问题就出现了:即便在 Ubuntu 安装器中选择“不更新”或“不安装更新”,安装程序依然会尝试连接网络仓库,并很可能在安装基础系统时引入更新的内核包,导致最终装出来的系统内核版本不符合要求。
我也咨询了一些 AI 助手,但给出的思路大多不尽如人意。核心难点在于:物理机可以通过拔网线实现完全离线安装,但宿主机本身还运行着其他服务,不能为了安装一个虚拟机而切断整个网络。如何在虚拟化环境下,精准地“阻断”安装程序访问外部软件源,成了一个需要巧妙解决的挑战。
解决方案:创造性的网络配置
经过一番思考,我找到了一个看似矛盾实则有效的办法:在虚拟机安装阶段,将其网络模式设置为 NAT,但为其配置一个未来桥接模式下才会使用的静态 IP 地址。
这么做的逻辑是这样的:
- 安装阶段(NAT模式 + 桥接IP):虚拟机通过虚拟 NAT 网络启动安装程序。此时,安装程序会应用我们预设的 Netplan 配置(其中包含桥接网络的静态IP)。由于这个 IP 地址在当前的 NAT 网络环境中是无效且无法路由的,因此安装程序实际上处于“网络不通”的状态。这完美地阻止了它访问外部 Ubuntu 软件源,从而确保了内核版本不会被更新。
- 安装完成后:系统安装完毕,我们再将虚拟机的网络模式从 NAT 永久修改为桥接。此时,之前配置好的静态 IP 地址就能在真实的桥接网络环境中正常生效,实现了“安装时配置,一次到位”的目标。
这个思路的核心是“形式合规,实质控制”——让安装程序以为自己有网络配置,但实际上这个配置在安装阶段是无效的,从而巧妙地约束了它的行为。
我把这个想法反馈给 AI,它给出了一个相当有趣的评价。

操作要点与结果
在实操中,使用 virsh console <虚拟机名> 连接并采用基本的文本模式(basic text)进行安装,过程非常清晰直观。当安装程序尝试获取软件包时,你会看到类似下图的输出,由于网络不通,它会报告解析失败或连接超时,这正是我们想要的效果——安装被限制在了本地光盘介质。
(原配图为安装程序因网络不通报错的截图,包含非技术性水印,根据优化规则已删除)
最终,安装程序仅从本地光盘(CDROM)读取包,跳过了所有在线仓库。安装完成的系统,其 /etc/netplan/ 下的配置文件已经是我们预先写好的、带有桥接静态IP的版本。之后,我们只需要在宿主机上用 virsh edit 将虚拟机的网络定义从 network‘default’’(NAT)改成 bridge‘br0’’(你的桥接接口),重启虚拟机网络或直接重启虚拟机,一切就会按计划运行:内核是锁定的 5.15.0-60-generic,IP 也是预先配置好的固定地址。
这种方法省去了安装后手动修改网络配置、防止被覆盖的步骤,尤其适用于需要批量部署或固定内核版本进行兼容性测试的自动化场景。如果你也在寻找一种优雅的方式来控制 Ubuntu 安装过程的行为,不妨试试这个“创造性约束”的思路。更多类似的系统管理与虚拟化技巧,欢迎在云栈社区交流讨论。
|