嵌套虚拟化
嵌套虚拟化让一台虚拟机(下面叫"里面这台的宿主 guest",简称 L1)自己也能运行虚拟机:在 Linux guest 里跑 KVM,在 Windows 里开 Hyper-V 和 WSL2。keelOS 默认不开,要在每台虚拟机上单独打开。这一章讲打开以后能做什么、不能做什么、会带来哪些限制。
1. 能用什么
下面这些是在 keelOS 上实际测过的:
- Linux guest 里的 KVM:Debian 里装
qemu-system-x86,里面再起虚拟机(L2),起停反复多次都正常。 - Windows 10 里的 Hyper-V:装上 Hyper-V 重启后 hypervisor 正常启动,在里面建第 2 代虚拟机并启动 Linux。
- Windows 10 里的 WSL2:
wsl --import … --version 2导入发行版,反复启停 10 次都成功。
还没有逐项测过、但原理上依赖同样的 KVM 或 Hyper-V 能力的:Firecracker 这类基于 KVM 的 microVM(放在 Linux guest 里)、Docker Desktop(依赖 WSL2 或 Hyper-V)。遇到问题请把现象告诉我们。
2. 还不支持什么
- AMD 主机:只有跑在 hyp 上的 Intel 主机能用。AMD 主机上这个开关是灰的,旁边写着原因。
- Windows 的 VBS、内存完整性(HVCI):Windows 在开了嵌套的 guest 里能起来 Hyper-V;HVCI 还不能用(要更多 CPU 和 IOMMU 功能)。Windows 11 和 Windows Server 还没有测过。
- 热迁移、在存储池之间热搬家:开了嵌套的虚拟机暂时不行(挂起和 reload 可以,见 §3;冷迁移没有专门测过)。
- PCI 直通:不能和嵌套同时用。有直通设备的虚拟机,开关是灰的;开了嵌套的虚拟机,添加 PCI 设备的按钮是灰的。
- keelOS 的 Hyper-V 增强:Windows 模板平时会给 guest 一套 Hyper-V 增强来提高性能。开了嵌套的 Windows guest 里跑的是它自己的 Hyper-V,这套增强默认不给;手工写
"hyperv": true会被拒绝。 - kcell:不能开嵌套。
3. 挂起、reload 和升级
主机把开了嵌套的虚拟机的 CPU 状态(包括"它正在运行里面的哪台虚拟机")一起存进检查点:
- 挂起、恢复和别的虚拟机一样。 恢复以后,L1 里的 KVM、Hyper-V、WSL2 和里面正在跑的虚拟机接着跑,不用重启。
- 主机 reload 时它被挂起、reload 之后恢复,和别的虚拟机一样。列表里它的 reload 动作显示"挂起"。
- 例外:新版本还在试用时(升级以后、点 确认升级 之前,见升级一章)。那时主机按旧版本的格式写检查点,旧格式装不下这些状态,所以:它不能挂起;它运行的时候主机的 reload、重启、切换槽会被拒绝,页面(系统 → 升级、系统 → 维护)列出这台虚拟机,旁边有 关闭 … 按钮;列表里 reload 动作显示"root reload 时关机(嵌套虚拟化)",
keel vm list显示poweroff (nested)。确认升级以后这些限制就没有了。 - 切换到读不了这种检查点的旧版本槽会被拒绝(先关掉它)。
4. 怎么打开
网页:
- 在 虚拟机 里点要改的虚拟机,点 编辑(新建时在向导的最后一步、或"自定义"的设备一节)。
- 在 设备 一节勾上 允许在这台虚拟机里再开虚拟机(嵌套虚拟化),下面一行小字写着上面的限制。
- 保存。设置在虚拟机下次冷启动时生效:运行中的虚拟机要关机再开。

如果开关是灰的,旁边会写原因:主机没跑在 keelOS 的 hyp 上、主机是 AMD 的 CPU、主机的 hypervisor 模块太旧(升级 keelOS),或者这台虚拟机有 PCI 直通设备。
命令行:新建时加 --nested,已有的虚拟机在 config.json 里写 "nested": true:
keel vm create --alias lab --vcpus 4 --ram 8G --disk 60G --nested
keel vm list 的 RELOAD 一列对这样的虚拟机显示 suspend(试用期间是 poweroff (nested),见 §3)。
5. 用的时候
- 给 L1 足够的 CPU 和内存:里面的虚拟机要从 L1 的内存里出。Windows 装好 Hyper-V 以后,Windows 自己变成 Hyper-V 的"根分区"。
- Windows:装完 Hyper-V 要重启一次;重启后
systeminfo会写"已检测到虚拟机监控程序",这是正常的。 - 性能:L2(里面的虚拟机)每退出一次要在 root 和 hyp 之间来回约 16 次,量到的量级是几十微秒(测试机上约 32 微秒)一次。缺页多的负载(编译、fork 密集)靠嵌套 EPT 变快很多(测试机上,fork 密集的负载比不用嵌套 EPT 时快 22 倍,缺页密集的快 44 倍);退出多的负载(I/O 和中断多的)每次退出都有这个代价,会比在 L1 里直接跑慢。拿它做实验、开发、测试环境是合适的,不要当生产虚拟化的底层。
6. 排查
- 保存时提示
nested virtualization and passthrough devices cannot be combined:先去掉 PCI 设备,或把嵌套关掉。 - 保存时提示
… the Hyper-V enlightenments cannot be combined yet:config.json 里有"hyperv": true,删掉它。 - 主机 reload 或升级被拒绝,提示
runs with nested virtualization … shut it down first:新版本还在试用(或主机的 vmm 模块太旧),关掉列出的虚拟机,或者先确认升级。 - L1 里
kvm_intel加载后没有ept=Y:确认主机的 vmm 模块是新的(系统 → 升级 里看版本)。
细节和测试记录在设计文档 docs/69。