使用 KVM 运行嵌套访客¶
嵌套访客是指在一个访客中运行另一个访客(可以是基于 KVM 或不同的管理程序)。一个直接的例子是 KVM 访客反过来在一个 KVM 访客上运行(本文档的其余部分都基于此示例)
.----------------. .----------------.
| | | |
| L2 | | L2 |
| (Nested Guest) | | (Nested Guest) |
| | | |
|----------------'--'----------------|
| |
| L1 (Guest Hypervisor) |
| KVM (/dev/kvm) |
| |
.------------------------------------------------------.
| L0 (Host Hypervisor) |
| KVM (/dev/kvm) |
|------------------------------------------------------|
| Hardware (with virtualization extensions) |
'------------------------------------------------------'
术语
L0 – 0 级;裸机主机,运行 KVM
L1 – 1 级访客;在 L0 上运行的 VM;也称为“访客管理程序”,因为它本身能够运行 KVM。
L2 – 2 级访客;在 L1 上运行的 VM,这是“嵌套访客”
注意
上述图表是根据 x86 架构建模的;s390x、ppc64 和其他架构的嵌套设计可能不同。
例如,s390x 始终在裸机上运行 LPAR(逻辑分区)管理程序,这又增加了一个层,导致嵌套设置中至少有四个级别——L0(裸机,运行 LPAR 管理程序)、L1(主机管理程序)、L2(访客管理程序)、L3(嵌套访客)。
本文档将对所有架构沿用三级术语(L0、L1 和 L2);并将主要关注 x86。
用例¶
嵌套 KVM 在多种场景中都非常有用,举例如下:
作为开发人员,您希望在不同的操作系统 (OS) 上测试您的软件。使用嵌套 KVM 可以让您租用足够大的“访客管理程序”(1 级访客),而不是从云提供商那里租用多个 VM。这反过来又允许您创建多个运行不同操作系统的嵌套访客(2 级访客),您可以在这些访客上开发和测试您的软件。
“访客管理程序”及其嵌套访客的实时迁移,用于负载均衡、灾难恢复等。
VM 镜像创建工具(例如
virt-install
等)通常运行自己的 VM,用户希望这些工具能在 VM 内部工作。某些操作系统在内部使用虚拟化来实现安全性(例如,让应用程序安全地隔离运行)。
启用“嵌套” (x86)¶
从 Linux 内核 v4.20 起,Intel 和 AMD 的 nested
KVM 参数默认启用。(尽管您的 Linux 发行版可能会覆盖此默认设置。)
如果您运行的是 v4.19 之前的 Linux 内核,要启用嵌套,请将 nested
KVM 模块参数设置为 Y
或 1
。要使此设置在重启后仍然有效,您可以将其添加到配置文件中,如下所示:
在裸机主机 (L0) 上,列出内核模块并确保 KVM 模块
$ lsmod | grep -i kvm kvm_intel 133627 0 kvm 435079 1 kvm_intel
显示
kvm_intel
模块的信息$ modinfo kvm_intel | grep -i nested parm: nested:bool
为了使嵌套 KVM 配置在重启后仍然有效,请将以下内容放置在
/etc/modprobed/kvm_intel.conf
中(如果文件不存在则创建)$ cat /etc/modprobe.d/kvm_intel.conf options kvm-intel nested=y
卸载并重新加载 KVM Intel 模块
$ sudo rmmod kvm-intel $ sudo modprobe kvm-intel
验证 KVM 的
nested
参数是否已启用$ cat /sys/module/kvm_intel/parameters/nested Y
对于 AMD 主机,过程与上述相同,只是模块名称是 kvm-amd
。
启动嵌套访客 (x86)¶
一旦您的裸机主机 (L0) 配置好嵌套功能,您应该能够使用以下命令启动 L1 访客:
$ qemu-kvm -cpu host [...]
上述命令会将主机 CPU 的能力原样传递给访客,或者为了更好的实时迁移兼容性,使用 QEMU 支持的命名 CPU 模型。例如:
$ qemu-kvm -cpu Haswell-noTSX-IBRS,vmx=on
然后,访客管理程序将随后能够以加速 KVM 的方式运行嵌套访客。
启用“嵌套” (s390x)¶
在主机管理程序 (L0) 上,在 s390x 上启用
nested
参数$ rmmod kvm $ modprobe kvm nested=1
注意
在 s390x 上,内核参数 hpage
与 nested
参数互斥——即,要启用 nested
,hpage
参数必须禁用。
访客管理程序 (L1) 必须提供
sie
CPU 功能——使用 QEMU,这可以通过使用“主机直通”(通过命令行-cpu host
)来完成。现在 KVM 模块可以加载到 L1(访客管理程序)中
$ modprobe kvm
使用嵌套 KVM 进行实时迁移¶
在 Linux 内核 5.3 和 QEMU 4.2.0 for Intel x86 系统中,以及更早版本的 s390x 系统中,将 L1 访客(其中包含一个实时嵌套访客)迁移到另一台裸机主机是可行的。
在 AMD 系统上,一旦 L1 访客启动了 L2 访客,L1 访客在 L2 访客关闭之前不应再进行迁移或保存(请参阅 QEMU 文档中的“savevm”/“loadvm”)。尝试在 L2 访客运行时迁移或保存-加载 L1 访客将导致未定义行为。您可能会在 dmesg
中看到 kernel BUG!
条目、内核“oops”或直接的内核崩溃。此类已迁移或加载的 L1 访客不再被视为稳定或安全,必须重新启动。仅配置为支持嵌套但未实际运行 L2 访客的 L1 访客迁移,即使在 AMD 系统上也应正常运行,但一旦访客启动,可能会失败。
迁移 L2 访客始终有望成功,因此以下所有场景即使在 AMD 系统上也应该有效:
将嵌套访客 (L2) 迁移到同一裸机主机上的另一个 L1 访客。
将嵌套访客 (L2) 迁移到不同裸机主机上的另一个 L1 访客。
将嵌套访客 (L2) 迁移到裸机主机。
报告嵌套设置中的错误¶
调试“嵌套”问题可能涉及筛选 L0、L1 和 L2 中的日志文件;这可能导致错误报告者和错误修复者之间繁琐的来回沟通。
说明您处于“嵌套”设置中。如果您正在运行任何类型的“嵌套”,请务必提及。不幸的是,这一点需要强调,因为在报告错误时,人们往往会忘记甚至提及他们正在使用嵌套虚拟化。
确保您实际正在 KVM 上运行 KVM。有时人们没有为他们的访客管理程序 (L1) 启用 KVM,这导致他们使用纯模拟或 QEMU 称之为“TCG”的方式运行,但他们认为他们正在运行嵌套 KVM。因此,这混淆了“嵌套虚拟化”(也可能意味着 KVM 上的 QEMU)和“嵌套 KVM”(KVM 上的 KVM)。
要收集的信息(通用)¶
以下不是详尽的列表,但是一个很好的起点
L0 中的内核、libvirt 和 QEMU 版本
L1 中的内核、libvirt 和 QEMU 版本
L1 的 QEMU 命令行 -- 使用 libvirt 时,您会在此处找到它:
/var/log/libvirt/qemu/instance.log
L2 的 QEMU 命令行 -- 如上所述,使用 libvirt 时,获取完整的 libvirt 生成的 QEMU 命令行
L0 中的
cat /sys/cpuinfo
L1 中的
cat /sys/cpuinfo
L0 中的
lscpu
L1 中的
lscpu
L0 中的完整
dmesg
输出L1 中的完整
dmesg
输出
x86 特定信息收集¶
以下两个命令 x86info
和 dmidecode
在大多数 Linux 发行版中都应该以相同的名称可用
L0 中
x86info -a
的输出L1 中
x86info -a
的输出L0 中
dmidecode
的输出L1 中
dmidecode
的输出
s390x 特定信息收集¶
除了前面提到的通用详情,还建议收集以下信息
L1 中的
/proc/sysinfo
;这还将包括 L0 中的信息