在Proxmox VE中运行microVM的简便方法

Lobsters Hottest 工具

摘要

介绍了pve-microvm,这是一个Debian软件包,它将QEMU的microvm机器类型集成到Proxmox VE中,实现了低于300毫秒的启动时间和硬件隔离,开销极小,支持多种客户操作系统。

<p><a href="https://lobste.rs/s/fdmitg/running_microvms_proxmox_ve_easy_way">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/20 09:34

# 在Proxmox VE中轻松运行microVM 来源: https://taoofmac.com/space/blog/2026/06/18/1845 2026年6月18日 (https://taoofmac.com/space/blog/2026/06/18/1845)· 15 分钟阅读 ·\#containers \#homelab \#kvm \#microvm \#proxmox \#qemu \#virtualization 多年来我一直在运行一个混合的Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox)集群——四个节点性能差异巨大,从一台配备 2 GB RAM 的 Atom x5-Z8350(`z83ii` (https://taoofmac.com/space/blog/2017/12/03/2130),在多年忠实服役作为基础折磨设备后目前离线)到一台配备 128 GB RAM 的 i7-12700(`borg` (https://taoofmac.com/space/blog/2023/02/18/1845),我的主要家庭实验室服务器)。 今年,在编写`agentbox` (https://github.com/rcarmo/agentbox?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link)和围绕代理沙箱的各种炒作之间,我厌倦了 LXC 容器和完整虚拟机之间的永恒妥协,最终构建了`pve-microvm` (https://github.com/rcarmo/pve-microvm?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link)——一个 Debian 软件包,它将 QEMU 的`microvm`机器类型作为 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) VE 中的一等管理客户机添加。 这不是一个快速的黑客方案。嗯,第一个版本其实是,但它现在远不止于此,并且肯定超出了我的预期。 它现在附带一个自定义内核,修补了 Perl (https://taoofmac.com/space/dev/perl) 内部以提供 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) Web UI 集成,并且由于我对非主流操作系统的通常迷恋,最终(在撰写本文时)支持 21 种客户机操作系统类型,从 Debian 到 NetBSD 再到 Plan9 (https://taoofmac.com/space/os/plan9)。 是的,我完全自找麻烦地在 microVM 中运行 Plan9 (https://taoofmac.com/space/os/plan9),是的,它工作。 ## 寻找合适的平衡 (https://taoofmac.com/space/blog/2026/06/18/1845#finding-the-right-balance) 经过几轮集群清理和迁移,它现在是我日常运行 Gitea (https://taoofmac.com/space/apps/gitea)、Caddy 反向代理、迷你防火墙以及帮助我清理这篇文章的 AI 代理的主力。 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) 开箱即用提供两个主要选项: - LXC (https://taoofmac.com/space/os/linux/lxc) 容器启动迅速,共享主机内核,效率极高。但它们并不*隔离*——一个容器中的内核漏洞会危害所有容器。你不能运行不同的操作系统。你无法轻易地在其中嵌套 Docker 而不最终(最终)与`fuse-overlayfs`的体操作斗争。某些工作负载(任何需要自定义内核模块或`CAP_SYS_ADMIN`实际使用的情况)根本不适用。 - 完整虚拟机通过 KVM/VT-x 提供硬件隔离,但它们引导 SeaBIOS 或 OVMF,缓慢地走过 GRUB,然后打着哈欠从床上起身,探测一堆模拟的旧设备(IDE 控制器、VGA、USB 集线器、PCI 桥接器),通常需要 5-10 秒才能到达登录提示。每个都带有整个模拟芯片组驻留在内存中的开销。 我想要的是具有容器启动特性的虚拟机的安全边界。QEMU 的`microvm`机器类型——最初为 Firecracker 风格的工作负载开发——剥离了所有这些。没有 BIOS,没有 GRUB,没有旧设备。直接内核引导进入一个最小化的、仅`virtio`的环境。结果:完全网络化、带有 QEMU 代理的客户机在 300ms 内启动,运行在其自己的 KVM 硬件隔离边界内。 标准虚拟机、microVM 和 LXC 容器的隔离和启动特性比较标准虚拟机、microVM 和 LXC 容器的隔离和启动特性比较 现在,让我说清楚:我不是在生成数百个这样的东西。我有 Azure 来做这个 (https://github.com/rcarmo/azure-k3s-cluster?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link)——但我确实想运行 Gitea (https://taoofmac.com/space/apps/gitea) Actions 工作器,硬件资源非常有限,并且受够了某个特定虚拟机重复启动所需的时间... ## 它实际做什么 (https://taoofmac.com/space/blog/2026/06/18/1845#what-it-actually-does) `pve-microvm` 是一个单一的 `.deb`,在安装时修补 Proxmox 的 `qemu-server` Perl 模块。当你在 VM 配置中设置 `machine: microvm` 时,标准的 `config_to_command` 函数会委托给我的 `MicroVM.pm`,它构建一个(几乎)完全不同的 QEMU 命令行: ``` qemu-system-x86_64 -M microvm,x-option-roms=off,pit=off,pic=off,\ isa-serial=on,rtc=on,acpi=on,pcie=on \ -kernel /usr/share/pve-microvm/vmlinuz \ -initrd /usr/share/pve-microvm/initrd \ -append "console=ttyS0 root=/dev/vda rw quiet" \ -device virtio-blk-pci-non-transitional,drive=drive-scsi0 \ -device virtio-net-pci-non-transitional,netdev=net0 \ ... ``` 没有芯片组模拟。没有 PCI 桥接器。没有 VGA。客户机获得一个单一的串行控制台(PVE 的 `xterm.js` 原生连接到此控制台)、`virtio` 块设备和一个 `virtio` 网络接口。所有内容都通过 PCIe 传输,使用非过渡(仅现代)`virtio` 设备,而不是 `microvm` 最初设计的 MMIO 传输——原因我稍后会提到。 pve-microvm 如何与 Proxmox VE 内部集成pve-microvm 如何与 Proxmox VE 内部集成 该软件包附带: - 一个很小的(12MB)预构建 Linux 6.12.22 内核,从 `x86_64_defconfig` 编译,带有一个最小覆盖层——`virtio`、`vsock`、`virtiofs`、`9p`,以及 Docker 需要的模块(`overlay`、`veth`、`bridge`、`netfilter`、`BPF`),因为,嗯,我很务实。 - 一个 1 MB 的 `initrd`,探测 `virtio` 设备,通过标签或设备路径找到根文件系统,并在约 150ms 内执行 `switch_root` - `pve-microvm-template`——从 12 种支持的 OCI 基础镜像中构建根文件系统,可选 SSH、Docker 和客户机代理 - `pve-oci-import`——将 OCI 镜像直接拉入 PVE 管理的磁盘 - Web UI 扩展——一个“创建 μVM”按钮、机器类型下拉菜单、用于隐藏不相关设置的条件面板,以及资源树中的琥珀色闪电图标 - 一个 systemd 服务(`pve-microvm-early.service`),确保在引导时 `pvedaemon` 启动之前应用补丁——对于 `onboot=1` 的虚拟机至关重要 ### 启动序列 (https://taoofmac.com/space/blog/2026/06/18/1845#the-boot-sequence) 就像在空气动力学中一样,大部分速度来自消除所有非必要的东西。标准虚拟机的大部分启动时间都花在固件和引导加载程序上,所以 microVM 跳过了所有这些。 microVM 和标准虚拟机之间的启动时间线比较microVM 和标准虚拟机之间的启动时间线比较 SmolBSD(一个使用 `virtio-mmio` 传输的 NetBSD 客户机)在 31ms 内启动。一个带有 Docker 和 QEMU 代理的完整 Debian 在 8 秒内准备就绪——其中大部分时间是首次启动时 `apt` 软件包安装。后续启动始终达到 300ms 标记,即使在我简陋的硬件上也是如此。 当有人要求我添加 SmolBSD 支持时,我陷入了一个有趣的兔子洞: SmolBSD 可以使用 `virtio-mmio` 而 Linux 客户机不能,这是有原因的。QEMU `microvm` 机器类型可以通过两种传输方式承载其 `virtio` 设备:最初为它构建的裸机 MMIO 接口,或 PCIe。MMIO 是两者中较轻的——没有 PCIe 主机桥接器,没有 ACPI——这就是 NetBSD 客户机如何将自身缩减到 31 ms。 但在 QEMU 10.x 上,MMIO 路径(据我所知)对于 Linux 客户机存在设备探测错误:只有 `virtio-blk` 绑定,而网络、串行和气球设备由于某种原因从未被其驱动程序声明。NetBSD 正确探测 MMIO 并且非常满意;Linux(至少是我使用的内核)则不然。 因此,对于每个 Linux 客户机,我回退到使用非过渡(仅现代)`virtio` 设备的 PCIe,这可以可靠地绑定所有设备。代价是大约 50 ms 的额外启动时间——相比于 300 ms 的启动,我毫无怨言地接受。 我认为上述问题实际上是我的内核配置中的错误,但我没有时间(或者可能没有合适的硬件)来解决它——这是我希望更多人关注并贡献补丁 (https://github.com/rcarmo/pve-microvm?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link)的事情。 ### 一个内核,多个客户机 (https://taoofmac.com/space/blog/2026/06/18/1845#one-kernel-many-guests) 这个直接内核引导技巧有一个容易被忽视的故意后果:内核并不*在*客户机内部。它位于 Proxmox 主机的 `/usr/share/pve-microvm/vmlinuz`,客户机磁盘只包含一个根文件系统——用户空间,没有 `/boot`,没有 GRUB,没有每个客户机的内核软件包,没有自己的 `initramfs`。 这也意味着没有“引导安装 ISO 并点击完成”的路径,因此 `rootfs` 直接从 OCI 镜像构建,使用 `pve-microvm-template`(Debian、Alpine、Fedora、Rocky、Amazon Linux 等)。在奇怪的情况下,我们使用 `qm importdisk` 导入准备好的 ext4/raw 磁盘。你不是*安装*操作系统——而是*组装*一个根文件系统。 将内核与 `rootfs` 解耦是使这在规模上运行有趣的原因。节点上的每个 Linux microVM 都引导*相同*的 `vmlinuz`——一个内核,从标准的 `x86_64_defconfig` 构建一次,带有一个 `microvm` 覆盖层,因此你可以在一个地方审计和更新它:在主机上放置一个新的 `vmlinuz`,重启客户机,完成。没有客户机从 `apt` 升级中拉取损坏的内核,因为没有客户机*有*内核要升级,并且 `rootfs` 镜像保持微小且完全与内核无关。 容器风格的内核一致性,虚拟机风格的隔离。 ## 我正在运行什么 (https://taoofmac.com/space/blog/2026/06/18/1845#what-im-running) 在我的集群上,我现在已经有不少这样的东西。脑海中立刻浮现出四个: - `gitea`(VM 114,在 Intel N5105 上)——裸机 Gitea (https://taoofmac.com/space/apps/gitea),带 SQLite、Caddy HTTPS、本地行为运行器、Avahi 发现。2 核,2 GB RAM,32 GB 磁盘。约 3s 启动,主要是因为 Gitea (https://taoofmac.com/space/apps/gitea) 做了很多内务处理。 - `smith`(VM 9022,在我的 i7 上)——主要的 `piclaw` (https://github.com/rcarmo/piclaw?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link) 代理,管理系统集群,发布 `piclaw` (https://github.com/rcarmo/piclaw?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link) 并通常跟踪所有事情。2 核,6 GB RAM,48 GB 磁盘。内部运行 Docker,并且在集群中分布有 3 个较小的不稳定兄弟,它们不运行 Docker 但具有不同的角色(CI/CD、用于测试升级的擦除并重新安装代理实例等) - `exo`(VM 9021,在我的 i7 上)——用于跨多台机器运行 LLM 的分布式推理协调器。仅 CPU,2 GB 根分区。 - `virtualdsm`(VM 300,`tnas` (https://taoofmac.com/space/blog/2024/12/26/2330))——Synology DSM 在 microVM 内运行,带 Docker,位于 Terramaster NAS 硬件内。是的,我知道我很奇怪,但这是我的需要 (https://taoofmac.com/space/blog/2026/05/15/1330),当我的 Synology 出问题时,我还没有把它干掉。使用标准的 Debian 内核而不是我的自定义内核,因为 DSM 需要特定的模块路径。 我还有一个休眠的 9Front (Plan9 (https://taoofmac.com/space/os/plan9)) 实例,以及一小群 OpenWrt、OPNsense、OSv unikernels、gokrazy Go 设备,以及各种 Alpine/Fedora/Rocky/Amazon Linux 配置,作为标准 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) 备份归档。21 种客户机操作系统类型不是理论上的——每一种都已启动并验证,有时 `smith` 会去解冻一个来进行回归测试。 `z83ii` (https://taoofmac.com/space/blog/2017/12/03/2130)(那台古老的 Atom x5-Z8350,2GB RAM)作为基础测试平台非常宝贵,因为如果一个 microVM 可以在 2016 年的无风扇 Atom 上(总系统内存 2 GB)启动并有用,那么它在任何地方都能工作。而且它在开始变慢之前可以运行六个... ## 配置看起来什么样 (https://taoofmac.com/space/blog/2026/06/18/1845#what-a-config-looks-like) microVM 配置没有什么神奇之处——它是一个普通的 `qm` 客户机,带有特定的 `machine` 类型和一个内核命令行。以下是 `gitea`(上面的 VM 114)在 `/etc/pve/qemu-server/114.conf` 中的样子: ``` agent: 1 args: -kernel /usr/share/pve-microvm/vmlinuz -append "console=ttyS0 root=/dev/vda rw quiet" boot: order=scsi0 cores: 2 machine: microvm memory: 2048 name: gitea net0: virtio=BC:24:11:00:6E:01,bridge=vmbr0 onboot: 1 scsi0: local-lvm:vm-114-disk-0,size=32G serial0: socket tags: microvm vga: serial0 ``` 仅有的 microvm 特定行是 `machine: microvm`、携带内核及其 cmdline 的 `args`,以及通过 `xterm.js` 连接控制台的 `serial0: socket` / `vga: serial0`。其他所有内容——核心、内存、`vmbr0` 上的 virtio NIC、`local-lvm` 上的 `scsi0` 磁盘、`onboot`、客户机代理——正是你为任何 Proxmox VM 编写的。 请注意 `args` 中没有 `-initrd`:`MicroVM.pm` 在检测到附带内核时自动注入它,以及 `balloon`、`vsock` 和(如果配置了)`virtiofs` 设备。这就是重点——microVM 是一个正常的客户机,恰好引导主机提供的内核,而不是一个你必须学习新工具来管理的特殊对象。 ### 网络 (https://taoofmac.com/space/blog/2026/06/18/1845#networking) microVM 完全像任何其他 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) 客户机一样连接到网络。接口规范有点复杂(PCIe 总线上的 `virtio-net-pci-non-transitional` 设备),并且它落在你指向的任何 Linux 桥接器和 VLAN 上: ``` qm set 900 --net0 virtio,bridge=vmbr0 # 单个 NIC qm set 900 --net0 virtio,bridge=vmbr0,tag=100 # 标记到 VLAN 100 ``` 因为它是一个普通的 KVM 客户机,所以标准 PVE 防火墙适用——每 VM `nftables` 规则的工作方式与任何 VM 相同,这是当你运行不受信任的代码时真正重要的部分。 在客户机内部,网络由 `systemd-networkd` 而不是 `cloud-init` 处理:默认使用 DHCP(匹配 `Type=ether`,因此克隆时无需 MAC 固定),或者使用单行 `/etc/microvm-static-net` 用于静态地址。早期版本依赖 `cloud-init` 处理此问题,我发现它太脆弱;将其移至 `systemd-networkd` 使克隆可靠,我一半时间不用调试模板。 网络*隔离*,当前关于代理隔离的炒作另一个主要内容,是一个已解决的问题,我没有兴趣在软件包内部重新解决,因为我认为 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) 自己的 SDN (https://pve.proxmox.com/wiki/Software-Defined_Network?utm_source=taoofmac.com&utm_medium=web&utm_campaign=unsolicited_traffic&utm_content=external_link) 已经正确处理了它——一个简单的 VLAN 区域,每个信任域有一个单独的 VNet,使不受信任的客户机处于自己的网段,无法访问 LAN,如果我曾经在家用 LAN 上费心(嗯,我*想过*...但没时间),一个带有指定出口节点的 VXLAN 区域将让我通过单个防火墙瓶颈点引导出口流量。 microVM 只是落在我指向 `net0` 的任何 VNet 上,因此策略存在于 Proxmox (https://taoofmac.com/space/os/linux/distributions/proxmox) 中,而不是一个我需要照看的临时规则集。 还有一个非网络路径用于主机/客户机

相似文章

mvm - 一个快速的 Go 虚拟机

Lobsters Hottest

mvm 是一个快速、可移植的 Go 虚拟机,支持直接从源码运行 Go 程序、嵌入 Go 解释器,并包含 REPL、调试器和标准库。