libvirt
Libvirt 是一个软件集合,提供了一种管理虚拟机和其他虚拟化功能(如存储和网络接口管理)的便捷方式。这些软件包括一个长期稳定的 C API、一个守护进程 (libvirtd) 和一个命令行实用程序 (virsh)。libvirt 的主要目标是为管理多个不同的虚拟化提供商/Hypervisor 提供统一的接口,例如 KVM/QEMU、Xen、LXC、OpenVZ 或 VirtualBox Hypervisor(等等)。
libvirt 的一些主要功能包括:
- 虚拟机管理:各种域生命周期操作,如启动、停止、暂停、保存、恢复和迁移。支持多种设备类型的热插拔操作,包括磁盘和网络接口、内存和 CPU。
- 远程机器支持:所有 libvirt 功能都可以通过运行 libvirt 守护进程的任何机器(包括远程机器)进行访问。支持多种网络传输方式进行远程连接,其中最简单的是 SSH,它不需要额外的显式配置。
- 存储管理:任何运行 libvirt 守护进程的主机都可以用于管理各种类型的存储:创建各种格式的文件镜像(qcow2、vmdk、raw 等)、挂载 NFS 共享、枚举现有的 LVM 卷组、创建新的 LVM 卷组和逻辑卷、分区原始磁盘设备、挂载 iSCSI 共享,等等。
- 网络接口管理:任何运行 libvirt 守护进程的主机都可以用于管理物理和逻辑网络接口。枚举现有接口,以及配置(和创建)接口、桥接器、VLAN 和绑定设备。
- 虚拟 NAT 和基于路由的网络:任何运行 libvirt 守护进程的主机都可以管理和创建虚拟网络。Libvirt 虚拟网络使用防火墙规则充当路由器,为虚拟机提供对主机网络透明的访问。
安装
由于其守护进程/客户端架构,libvirt 仅需要安装在将托管虚拟化系统的机器上。请注意,服务器和客户端可以是同一台物理机。
服务器
安装 libvirt 包,以及至少一个 Hypervisor。
- libvirt 的 KVM/QEMU 驱动 是主要的 libvirt 驱动,如果 启用了 KVM,则可以使用完全虚拟化的、硬件加速的客户机。有关更多信息,请参阅 QEMU 文章。
- 其他 支持的 Hypervisor 包括 LXC、VirtualBox 和 Xen。有关安装说明,请参阅相应的文章。关于
libvirtd的安装请注意:
对于网络连接,请安装
- dnsmasq 用于 默认的 NAT/DHCP 网络。
- openbsd-netcat 用于通过 SSH 进行远程管理。
其他可选依赖项可能提供所需或扩展的功能,例如支持 DMI 系统信息的 dmidecode。在阅读 pacman 关于 libvirt 的输出后,安装您可能需要的依赖项。
libvirt 5.1.0 和 firewalld 0.7.0 开始,您不再需要将防火墙后端更改为 iptables。libvirt 现在会在 firewalld 中安装一个名为“libvirt”的区域,并在其中管理其所需的网络规则。请参阅 Libvirt 中的防火墙和网络过滤。客户端
客户端是用于管理和访问虚拟机的用户界面。
- virsh — 用于管理和配置域的命令行程序。
- Boxes — 简单的 GNOME 应用程序,用于访问虚拟系统。属于 gnome-extra。
- Libvirt Sandbox — 应用程序沙盒工具包。
- Virt Viewer — 简单的远程显示客户端。
- virt-manager — 通过 libvirt 图形化管理 KVM、Xen 或 LXC。
- Cockpit — 基于 Web 的系统管理工具,带有管理虚拟机的插件。
libvirt 兼容的软件列表可以在 此处找到。
配置
Libvirt 可以以两种模式管理 QEMU 虚拟机:系统模式和会话模式[1][2]
- system URI 连接到以 root 身份运行并在系统启动时启动的 libvirtd 守护进程。使用 'system' 创建和运行的虚拟机通常以 root 身份启动,除非另有配置(例如在
/etc/libvirt/qemu.conf中)。 - session URI 以您的本地用户身份启动一个 libvirtd 实例,并且所有虚拟机都以本地用户权限运行。
关于它们的优缺点:
- 虚拟机在主机启动时自动启动仅适用于 'system' 模式,并且 root libvirtd 实例具有使用桥接器或虚拟网络的正确权限。
qemu:///system通常是 virt-manager 等工具默认使用的。 qemu:///session有一个严重的缺点:由于 libvirtd 实例没有足够的权限,唯一开箱即用的网络选项是 qemu 的用户模式网络,它具有不明显的限制,因此不推荐使用(有关 qemu 网络选项的更多信息)。
qemu:///session的好处是权限问题消失了:磁盘镜像可以轻松地存储在 $HOME 中,串行 PTY 由用户拥有,等等。
对于系统级别的管理(即全局设置和镜像卷的位置),libvirt 最低要求 设置身份验证,并 启动守护进程。
对于用户会话管理,不需要守护进程设置和配置;但是,身份验证仅限于本地能力;前端将启动一个本地的 libvirtd 守护进程实例。
设置认证
来自 libvirt:连接认证
- libvirt 守护进程允许管理员独立地为每个网络套接字选择用于客户端连接的身份验证机制。这主要通过
/etc/libvirt/libvirtd.conf中的 libvirt 守护进程主配置文件进行控制。libvirt 套接字中的每个套接字都可以独立配置其身份验证机制。目前有none、polkit和sasl可供选择。
使用 libvirt 组
确保您的用户有权访问 libvirt 守护进程的最简单方法是将成员添加到 libvirt 用户组。
默认情况下,libvirt 组的成员拥有无密码访问 RW 守护进程套接字。
使用 polkit
由于 libvirt 在安装过程中会作为依赖项拉入 polkit,因此 polkit 被用作 unix_sock_auth 参数的默认值(来源)。然而,基于文件的权限仍然可用。
polkit 进行身份验证之前,可能需要重新启动系统才能正常工作。libvirt 守护进程在 /usr/share/polkit-1/actions/org.libvirt.unix.policy 中提供了两个 polkit 操作:
org.libvirt.unix.manage用于完全管理访问(RW 守护进程套接字),以及org.libvirt.unix.monitor用于仅监控访问(只读套接字)。
RW 守护进程套接字的默认策略要求进行管理员身份验证。这类似于 sudo 身份验证,但不需要客户端应用程序最终以 root 身份运行。默认策略仍然允许任何应用程序连接到 RO 套接字。
Arch 默认将 wheel 组中的任何人视为管理员:这在 /usr/share/polkit-1/rules.d/50-default.rules 中定义(请参阅 Polkit#管理员身份)。因此,如果您用户的 是 wheel 组的成员,则无需创建新组和规则文件:连接到 RW 套接字时(例如,通过 virt-manager),您将需要输入用户密码。
pkttyagent 代理的问题,该代理可能正常工作也可能不正常。您可以更改授权访问 RW 守护进程套接字的组。例如,要授权 mykvm 组,请创建以下文件:
/etc/polkit-1/rules.d/50-libvirt.rules
/* Allow users in mykvm group to manage the libvirt
daemon without authentication */
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.unix.manage" &&
subject.isInGroup("mykvm")) {
return polkit.Result.YES;
}
});
然后 添加您自己到 mykvm 组并重新登录。将 mykvm 替换为您喜欢的任何组,只需确保它存在并且您的用户是其成员(有关更多信息,请参阅 用户和组)。
不要忘记重新登录才能使组更改生效。
使用基于文件的权限进行身份验证
要为 libvirt 组中的用户定义基于文件的权限来管理虚拟机,请取消注释并定义:
/etc/libvirt/libvirtd.conf
#unix_sock_group = "libvirt" #unix_sock_ro_perms = "0777" # set to 0770 to deny non-group libvirt users #unix_sock_rw_perms = "0770" #auth_unix_ro = "none" #auth_unix_rw = "none"
虽然一些指南提到了更改某些 libvirt 目录的权限以简化管理,但请记住,权限会在软件包更新时丢失。要编辑这些系统目录,需要 root 用户。
守护进程
启动 libvirtd.service 和 virtlogd.service。可以选择 启用 libvirtd.service(这将同时启用 virtlogd.socket 和 virtlockd.socket 单元,因此 **无需** 启用 virtlogd.service)。
另一种选择是仅 启动/启用 libvirtd.socket 和 virtlogd.socket 以实现按需套接字激活。
取消加密 TCP/IP 套接字
编辑 /etc/libvirt/libvirtd.conf
/etc/libvirt/libvirtd.conf
listen_tls = 0 listen_tcp = 1 auth_tcp="none"
还需要通过编辑 /etc/conf.d/libvirtd 来以监听模式启动服务器。
/etc/conf.d/libvirtd
LIBVIRTD_ARGS="--listen"
通过主机名访问虚拟机
对于在非隔离、桥接网络上的客户机的主机访问,请启用 libvirt 提供的 libvirt 和/或 libvirt_guest NSS 模块。有关两个模块的比较和技术细节,请参阅 libvirt 文档。
在 nsswitch.conf(5) 中添加所需的模块。
/etc/nsswitch.conf
hosts: files libvirt libvirt_guest dns myhostname
ping 和 ssh 等命令应该可以使用虚拟机主机名正常工作,但 host 和 nslookup 等命令可能会失败或产生意外结果,因为它们依赖于 DNS。请改用 getent hosts vm-hostname。测试
要测试 libvirt 在系统级别是否正常工作
$ virsh -c qemu:///system
要测试 libvirt 在用户会话下是否正常工作
$ virsh -c qemu:///session
管理
Libvirt 的管理主要通过三种工具完成:virt-manager(GUI)、virsh 和 guestfish(它是 libguestfs 的一部分)。
LIBVIRT_DEFAULT_URI 环境变量中设置其 URI [3]。默认情况下,libvirt 对普通用户使用 qemu:///session,对 root 使用 qemu:///system。virsh
virsh 程序用于管理客户机域(虚拟机),非常适合脚本编写和虚拟化管理。虽然大多数 virsh 命令由于用于与 Hypervisor 通信的通道而需要 root 权限才能运行,但典型的域管理、创建和运行(例如使用 VirtualBox 所做的)可以作为普通用户完成。
virsh 程序包含一个交互式终端,如果未传递任何命令(但允许选项),则可以进入该终端:virsh。交互式终端支持选项卡补全。
从命令行
$ virsh [option] <command> [argument]...
从交互式终端
virsh # <command> [argument]...
可获得帮助。
$ virsh help [option*] or [group-keyword*]
存储池
存储池是存储卷的位置。libvirt 定义的卷可能是其他人定义的“虚拟磁盘”或“虚拟机镜像”。存储池的位置可以是目录、网络文件系统或分区(包括 LVM)。存储池可以激活或非激活,并分配空间。
在系统级别,默认会激活 /var/lib/libvirt/images/;在用户会话下,virt-manager 会创建 $XDG_DATA_HOME/images。
打印活动和非活动存储池。
$ virsh pool-list --all
使用 virsh 创建新存储池
如果要添加一个存储池,以下是命令形式的示例,添加一个目录和一个 LVM 卷:
$ virsh pool-define-as name type [source-host] [source-path] [source-dev] [source-name] [<target>] [--source-format format] $ virsh pool-define-as poolname dir - - - - /home/username/.local/libvirt/images $ virsh pool-define-as poolname fs - - /dev/vg0/images - mntpoint
上述命令定义了存储池的信息,用于构建它:
$ virsh pool-build poolname $ virsh pool-start poolname $ virsh pool-autostart poolname
要删除它:
$ virsh pool-undefine poolname
pool-create 和 pool-create-as 命令会创建一个临时存储池(可能还会创建其目标目录,具体取决于存储池类型)。临时存储池不会在重启后保留(尽管它创建的目录会保留)。为了创建持久的、可在重启后保留的存储池,请使用如上所述的 pool-define 或 pool-define-as 命令。- 将一个卷组专门用于存储池是一个好习惯。
- 选择一个与存储池名称不同的 LVM 卷组,否则当存储池被删除时 LVM 卷组也会被删除。
使用 virt-manager 创建新存储池
首先,连接到一个 Hypervisor(例如,QEMU/KVM system 或 user-session)。然后,右键单击一个连接并选择详细信息;选择存储选项卡,按下左下角的+按钮,然后按照向导操作。
存储卷
创建存储池后,即可在其中创建卷。如果要构建新域(虚拟机),可以跳过此步骤,因为可以在域创建过程中创建卷。
使用 virsh 创建新存储卷
创建卷、列出卷、调整大小和删除。
$ virsh vol-create-as poolname volumename 10GiB --format aw|bochs|raw|qcow|qcow2|vmdk $ virsh vol-upload --pool poolname volumename volumepath $ virsh vol-list poolname $ virsh vol-resize --pool poolname volumename 12GiB $ virsh vol-delete --pool poolname volumename $ virsh vol-dumpxml --pool poolname volumename # for details.
域
虚拟机称为域。如果从命令行工作,请使用 virsh 来列出、创建、暂停、关闭域等。virt-viewer 可用于查看使用 virsh 启动的域。域的创建通常通过 virt-manager(GUI)或 virt-install(作为 virt-install 包安装的命令行程序)来完成。
创建新域通常涉及使用一些安装介质,例如存储池中的 .iso 文件或光驱。
打印活动和非活动域。
# virsh list --all
/var/lib/libvirt/images/ 中的卷。如果使用 SELinux 并且卷存在问题,请确保卷位于该目录中,或确保其他存储池已正确标记。使用 virt-install 创建新域
对于极其详细的域(虚拟机)设置,更容易 #使用 virt-manager 创建新域。但是,基本操作可以用 virt-install 轻松完成,并且效果仍然很好。最低规格是 --name、--memory、客户机存储(--disk、--filesystem 或 --nodisks)和安装方法(通常是 .iso 或 CD)。有关更多详细信息和未列出的选项,请参阅 virt-install(1)。
Arch Linux 安装(两 GiB,qcow2 格式卷创建;用户网络)
$ virt-install \ --name arch-linux_testing \ --memory 1024 \ --vcpus=2,maxvcpus=4 \ --cpu host \ --cdrom $HOME/Downloads/arch-linux_install.iso \ --disk size=2,format=qcow2 \ --network user \ --virt-type kvm
Fedora 测试(Xen Hypervisor,非默认存储池,不初始查看)
$ virt-install \ --connect xen:/// \ --name fedora-testing \ --memory 2048 \ --vcpus=2 \ --cpu=host \ --cdrom /tmp/fedora20_x84-64.iso \ --os-type=linux --os-variant=fedora20 \ --disk pool=testing,size=4 \ --network bridge=br0 \ --graphics=vnc \ --noautoconsole $ virt-viewer --connect xen:/// fedora-testing
Windows
$ virt-install \ --name=windows7 \ --memory 2048 \ --cdrom /dev/sr0 \ --os-variant=win7 \ --disk /mnt/storage/domains/windows7.qcow2,size=20GiB \ --network network=vm-net \ --graphics spice
osinfo-query --fields=name,short-id,version os 以获取 --os-variant 的参数;这将有助于定义域的一些规范。但是,--memory 和 --disk 需要手动输入;您可以查看相应的 /usr/share/osinfo/os/version.xml 文件以获取这些规范。安装后,很可能最好安装 Spice Guest Tools,其中包含 VirtIO 驱动。对于 Windows VirtIO 网络驱动程序,还有一个 virtio-winAUR。这些驱动程序在客户机设备的 .xml 配置部分的 <model type='virtio' /> 中被引用。有关更多信息,您还可以查看 QEMU 文章。导入现有卷。
$ virt-install \ --name demo \ --memory 512 \ --disk /home/user/VMs/mydisk.img \ --import
使用 virt-manager 创建新域
首先,连接到 Hypervisor(例如,QEMU/KVM system 或 user session),右键单击一个连接并选择新建,然后按照向导操作。
- 在第四步,取消选择立即分配整个磁盘将使设置更快,并且可以在短期内节省磁盘空间;然而,它可能会随着时间的推移导致卷碎片化。
- 在第五步,打开高级选项并确保Virt 类型设置为kvm(这通常是首选方法)。如果需要额外的硬件设置,请选择安装前自定义配置选项。
管理域
启动域。
$ virsh start domain $ virt-viewer --connect qemu:///session domain
优雅地尝试关闭域;强制关闭域。
$ virsh shutdown domain $ virsh destroy domain
域在 libvirtd 启动时自动启动。
$ virsh autostart domain $ virsh autostart domain --disable
域在主机关闭时关闭。
- 运行中的域可以使用
libvirt-guests.servicesystemd 服务在主机关闭时自动暂停/关闭。同一服务将在主机启动时自动恢复/启动暂停/关闭的域。有关详细信息和服务选项,请参阅 libvirt-guests(8)。
编辑域的 XML 配置。
$ virsh edit domain
要了解更多关于 XML 配置的信息,请阅读 libvirt Wiki 的 XML 格式部分。
Windows 要求
最近的 Windows 客户端和服务器版本对机器有特定要求。从 Windows 11 开始,有必要将域配置为 UEFI 模式,因为它不支持 BIOS 模式。Windows Server 仍然可以在非 UEFI 环境中安装;但是,Microsoft 建议至少为 Windows Server 2022 及更高版本使用 UEFI 模式。有关如何实现这一点,请参阅 #UEFI 支持。
此外,Windows 11 要求向域提供可信平台模块。同样,对于 Windows Server,这仍然是可选的,但建议使用。请注意,TPM 版本 1.2 从 Windows 11 开始不再受支持,并且域必须设置为 TPM 版本 2.0。可以使用 TPM 模拟器,如本文 #TPM 支持中所述。
最后,Windows 建议使用安全启动,libvirt 可以提供一个合适的环境。有关如何使用 virt-firmware 在域的固件存储中注册 Microsoft 密钥,请参阅本文 #UEFI 支持 和 KVM#安全启动。或者,也可以使用 此指南手动完成相同的事情。安全启动并非严格要求,也可以在域安装完成后进行部署。
最近的 Windows 版本,尤其是 Windows 11 和 Windows Server 2025,包含一项名为 基于虚拟化的安全性 (VBS) 的安全功能。这项技术利用硬件虚拟化本身来隔离内核的部分。如果域支持嵌套虚拟化,可以使用 QEMU/KVM 在 libvirt 域中运行 Windows,请参阅 #嵌套虚拟化 以了解如何启用它。
网络
虚拟网络
虚拟网络用于将域连接到内部或外部网络。桥接设备用于定义虚拟网络。此外,转发模式用于定义域能够访问的内部或外部网络。
转发模式
以下是一些常见的转发模式:
| 模式 | 描述 |
|---|---|
| 桥接 | 虚拟网络与主机在同一网络段。 |
| NAT | 虚拟网络使用主机的网络堆栈,使用 NAT,且入站连接受到限制。 |
| 路由 | 虚拟网络使用主机的网络堆栈,且入站连接受到限制。 |
| 开源 | 虚拟网络使用主机的网络堆栈。 |
| 隔离 | 虚拟网络无法访问其他任何网络。 |
使用 iptables
如果将使用 iptables 而 **不是** nftables,则必须在配置文件 /etc/libvirt/network.conf 中相应地进行指定。
例如:
# default: #firewall_backend = "nftables" firewall_backend = "iptables"
获取域 IP 地址
如果使用 默认 网络并通过 DHCP 分配地址
$ virsh net-dhcp-leases default
如果域正在使用 qemu-guest-agent
$ virsh domifaddr --source agent domain
使用 nftables
当使用 NAT 网络类型与简单的 nftables 防火墙结合使用时,您可能需要允许与虚拟网络接口的双向转发,并允许来自虚拟网络接口到主机的 DHCP 客户端的 DNS/DHCP 请求。
nftables.conf 的相关部分如下:
/etc/nftables.conf
# ...
table inet filter {
chain input {
type filter hook input priority filter
policy drop
# ...
iifname virbr0 udp dport {53, 67} accept comment "allow VM dhcp/dns requests to host"
# ...
}
chain forward {
type filter hook forward priority filter
policy drop
iifname virbr0 accept
oifname virbr0 accept
}
}
添加 IPv6 地址
通过任何配置工具添加 IPv6 地址时,您很可能会收到以下错误:
Check the host setup: enabling IPv6 forwarding with RA routes without accept_ra set to 2 is likely to cause routes loss. Interfaces to look at: eth0
通过运行以下命令修复此问题(将 eth0 替换为您的物理接口名称):
# sysctl net.ipv6.conf.eth0.accept_ra=2
端口转发到域
有关如何执行此操作的详细信息,请参阅 libvirt 的 NAT 转发 文档。
快照
快照会捕获域在某个时间点的磁盘、内存和设备状态,并将其保存以供将来使用。它们有许多用途,从保存操作系统映像的“干净”副本到在潜在的破坏性操作之前保存域的状态。快照通过唯一的名称进行标识。
快照保存在卷本身内,并且卷的格式必须是:qcow2 或 raw。快照使用增量以避免占用与完整副本一样多的空间。
创建快照
一旦创建了快照,它就会保存为一个新的块设备,而原始快照会被脱机。可以从快照中选择,也可以将快照合并到另一个快照中(即使在不关闭域的情况下也可以)。
打印正在运行的域的卷(可以通过 virsh list 打印正在运行的域)
# virsh domblklist domain
Target Source ------------------------------------------------ vda /vms/domain.img
查看卷的物理属性
# qemu-img info /vms/domain.img
image: /vms/domain.img file format: qcow2 virtual size: 50G (53687091200 bytes) disk size: 2.1G cluster_size: 65536
创建仅磁盘的快照(--atomic 选项将在快照创建失败时阻止卷被修改)
# virsh snapshot-create-as domain snapshot1 --disk-only --atomic
列出快照
# virsh snapshot-list domain
Name Creation Time State ------------------------------------------------------------ snapshot1 2012-10-21 17:12:57 -0700 disk-snapshot
之后可以复制原始映像,使用 cp --sparse=true 或 rsync -S,然后将原始映像合并回快照。
# virsh blockpull --domain domain --path /vms/domain.snapshot1
domain.snapshot1 成为一个新的卷。完成后,原始卷(domain.img 和快照元数据)可以被删除。virsh blockcommit 的作用与 blockpull 相反,但它似乎目前仍处于开发阶段(包括 snapshot-revert feature,计划在明年某个时候发布。
其他管理
列出系统模式下的虚拟机
$ virsh --connect qemu:///system list --all
连接到非默认的虚拟机监视器
$ virsh --connect xen:/// virsh # uri xen:///
通过 SSH 连接到 QEMU 虚拟机监视器;以及相同的日志记录。
$ virsh --connect qemu+ssh://username@host/system $ LIBVIRT_DEBUG=1 virsh --connect qemu+ssh://username@host/system
通过 SSH 连接图形控制台
$ virt-viewer --connect qemu+ssh://username@host/system domain $ virt-manager --connect qemu+ssh://username@host/system domain
连接到系统的 VirtualBox 虚拟机监视器(libvirt 中对 VirtualBox 的支持尚不稳定,可能导致 libvirtd 崩溃)
$ virsh --connect vbox:///system
列出并转储网络配置
$ virsh -c qemu:///system net-list --all $ virsh -c qemu:///system net-dumpxml default
钩子
钩子是在 libvirt 守护进程启动和运行时触发的脚本。它们可用于执行启动客户机所需的命令,例如设置网络或预留内存。
存在以下钩子:
- daemon - 触发时机:start, shutdown, reload
- qemu - 触发时机:prepare, start, started, stopped, release, migrate, restore, reconnect, attach
- lxc - 触发时机:prepare, start, started, stopped, release, reconnect
- libxl - 触发时机:prepare, start, started, stopped, release, migrate, reconnect
- network - 触发时机:start, started, stopped, port-created, updated, port-deleted
有关每个钩子和触发器的详细信息,请参阅 libvirt 文档。
创建钩子
钩子由位于 /etc/libvirt/hooks 的脚本表示。如果该文件夹不存在,则需要创建它。每个钩子由该文件夹中同名脚本(例如 /etc/libvirt/hooks/qemu)或子文件夹(例如 /etc/libvirt/hooks/qemu.d/)表示。后者可以包含不同的脚本,所有脚本在触发点都会运行。脚本的运行方式与其他脚本相同,因此它们需要以要使用的命令解释器的声明(例如 #!/bin/bash)开头,并由 libvirt 用户 可执行。
每次满足触发点时,都会运行脚本。例如,在启动/停止系统的周期中,daemon 脚本至少会运行两次:启动时和关机时。要仅在给定点运行命令,您必须在脚本中实现条件。为此,libvirt 会传递参数,这些参数可用于识别当前触发条件。
根据 libvirt 文档,这些参数定义如下:
- 参数 1:操作所涉及对象的名称
- 参数 2:正在执行的操作的名称
- 参数 3:如果需要命名子操作,则使用
- 参数 4:如有需要,附加参数
如果参数不适用,则传入一个破折号。
qemu 钩子为 virtqemud)。示例
要每次启动 qemu 客户机时运行命令,并在分配任何资源之前运行,您可以使用 qemu 钩子。此时,libvirt 运行钩子的方式如下:/etc/libvirt/hooks/qemu <guest_name> prepare begin - 脚本可能如下所示:
/etc/libvirt/hooks/qemu
#!/bin/bash guest_name="$1" libvirt_task="$2" if [ "$libvirt_task" = "prepare" ]; then <run some important code here> fi
如果客户机已停止,将运行相同的脚本,但此时守护进程将像这样启动命令:/etc/libvirt/hooks/qemu <guest_name> stopped end -
共享主机和客户机之间的数据
Virtio-FS
使用 Virtio-FS 共享文件 列出了启用与客户机进行文件共享的支持选项的概述。
设置内存后端
在使用 virtiofs 之前必须分配内存后端。memfd 和文件后备内存后端可在系统会话和非特权 QEMU/KVM 用户会话中使用。Hugepages 仅支持系统会话。
memfd
要使用 memfd 内存后端,需要添加以下域 XML 元素:
# virsh edit name_of_virtual_machine
<domain>
...
<memoryBacking>
<source type='memfd'/>
<access mode='shared'/>
</memoryBacking>
...
</domain>
文件后备
添加以下域 XML 元素:
# virsh edit name_of_virtual_machine
<domain>
...
<memoryBacking>
<access mode='shared'/>
</memoryBacking>
...
</domain>
您可以在 /etc/libvirt/qemu.conf 中的 memory_backing_dir 选项或(如果您正在运行用户会话)在 $XDG_CONFIG_HOME/libvirt/qemu.conf 中配置后备文件的存储位置。
memory_backing_dir = "/dev/shm/"
hugepage
首先,您需要 启用 huge pages,供虚拟机使用。
/etc/sysctl.d/40-hugepage.conf
vm.nr_hugepages = nr_hugepages
要确定所需的 hugepages 数量,请检查 hugepages 的大小。
$ grep Hugepagesize /proc/meminfo
hugepages 的数量是 虚拟机内存大小 / Hugepagesize。在此基础上添加一些额外的页面。此步骤后需要重启,以便分配 hugepages。
现在您需要准备虚拟机的配置。
# virsh edit name_of_virtual_machine
<domain>
...
<memoryBacking>
<hugepages/>
</memoryBacking>
...
<cpu ...>
<numa>
<cell memory='memory size of virtual machine' unit='KiB' memAccess='shared'/>
</numa>
</cpu>
...
</domain>
必须添加 NUMA 定义,以便可以将内存访问声明为共享。NUMA 的 id 和 cpus 值将由 virsh 插入。
配置文件系统直通
添加以下域 XML 元素:
# virsh edit name_of_virtual_machine
<domain>
...
<devices>
...
<filesystem type='mount' accessmode='passthrough'>
<driver type='virtiofs'/>
<source dir='path/to/folder/on/host'/>
<target dir='mount_tag'/>
</filesystem>
...
</devices>
</domain>
将 path/to/folder/on/host 替换为您想共享的目录,将 mount_tag 替换为用于在客户机中标识共享文件系统的任意字符串。
现在应该可以在共享的机器中挂载该文件夹了。
# mount -t virtiofs mount_tag /mnt/mount/path
将以下 fstab 条目添加到启动时自动挂载该文件夹:
/etc/fstab
... mount_tag /mnt/mount/path virtiofs rw,noatime 0 0
在非特权模式下映射用户/组 ID
默认情况下,客户机中的 root 用户(ID 0)映射到主机上的当前用户。其他 ID 映射到 subuid(5) 和 subgid(5) 中指定的从属用户 ID。
您也可以使用 idmap 标签手动配置此映射。
# virsh edit name_of_virtual_machine
<domain>
...
<devices>
...
<filesystem type='mount' accessmode='passthrough'>
<idmap>
<uid start="2000" target="1000" count="1"/>
<gid start="2000" target="1000" count="1"/>
</idmap>
</filesystem>
...
</devices>
</domain>
9p
可以使用 9P 协议 共享文件系统目录。详细信息请参阅 QEMU 的 9psetup 文档。
按如下方式配置虚拟机:
<domain>
...
<devices>
...
<filesystem type="mount" accessmode="mapped">
<source dir="/path/on/host"/>
<target dir="mount_tag"/>
</filesystem>
</devices>
</domain>
启动客户机并通过以下命令从客户机 挂载共享目录:
# mount -t 9p -o trans=virtio,version=9p2000.L mount_tag /path/to/mount_point/on/guest
有关更多挂载选项,请参阅 https://docs.linuxkernel.org.cn/filesystems/9p.html。
要在启动时挂载它,请将其添加到客户机的 fstab 中。
/etc/fstab
... mount_tag /path/to/mount_point/on/guest 9p trans=virtio,version=9p2000.L 0 0
9p 传输的模块(例如 trans=virtio 的 9pnet_virtio)不会自动加载,因此从 /etc/fstab 挂载文件系统会失败,您会遇到类似 9pnet: Could not find request transport: virtio 的错误。解决方法是 在启动时预加载模块。
/etc/modules-load.d/9pnet_virtio.conf
9pnet_virtio
Samba / SMB
在客户机和主机之间共享数据的另一种简单方法是使用 smb 协议。虽然性能和延迟可能不如其他描述的方式,但它足以完成简单任务,例如在客户机之间传输图像或文档等简单文件。
smb 服务器可以直接设置在主机或客户机上,例如使用 Samba,无需专用文件服务器。Windows 客户机在安装后立即具有创建 smb 共享的功能(Microsoft 支持页面)。
在 Linux 下访问共享的一种可能方法(无论是从主机还是客户机,具体取决于您安装服务器的位置)是在 fstab 中创建一个条目。需要 samba 包。
/etc/fstab
#Accessing a samba share on my vm from the host //my_vm/my_share /home/archuser/my_vm cifs _netdev,noauto,nofail,user,credentials=/home/archuser/.config/my_vm.key,gid=1000,uid=984 0 0
_netdev,noauto,nofail 可确保共享仅在需要时挂载,而不会在虚拟机未启动时造成问题。user,credentials=/home/user/.config/my_vm.key,gid=1000,uid=984 可让您在首次访问共享时动态挂载共享,而无需密码。
UEFI 支持
Libvirt 可以通过 QEMU 和 OVMF 支持 UEFI 虚拟机。
安装 edk2-ovmf 包。
重启 libvirtd。
现在您可以创建 UEFI 虚拟机了。通过 virt-manager 创建新虚拟机。当您到达 新建虚拟机 向导的最后一页时,请执行以下操作:
- 点击 在安装前自定义配置,然后选择 完成。
- 在 概览 屏幕上,将 固件 字段更改为:
- UEFI x86_64: /usr/share/edk2/x64/OVMF_CODE.4m.fd,用于 x64 UEFI,无安全启动支持;
- UEFI x86_64: /usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd,用于 x64 UEFI,带安全启动支持(无预注册证书)。
- 点击 应用。
- 点击 开始安装。
有关更多信息,请参阅 Fedora:Using UEFI with QEMU。
有关注册密钥,可以使用 virt-firmware,请参阅 KVM#Secure Boot。
TPM 支持
QEMU 可以向客户机提供一个 可信平台模块。这可以是直通设备,即在虚拟机中使用物理 TPM,也可以是模拟器。要使用模拟器,必须安装 swtpm 包。可以向客户机提供 TPM 版本 1.2 或 2.0,但 2.0 要求域使用 UEFI。
最简单的形式,为客户机提供一个可用的 TPM 2.0 模拟器,域规范中的以下块将起作用:
<tpm model='tpm-crb'> <backend type='emulator' version='2.0'/> <alias name='tpm0'/> </tpm>
有关其他信息和选项,请参阅 libvirt 文档 此处。
Hyper-V 增强
QEMU 支持各种 Hyper-V 兼容的增强功能,可提高 Windows 客户机的性能并添加一些附加功能,请参阅 QEMU 文档。
这些增强功能也可以通过 libvirt 激活,具体取决于存在的 QEMU 和 libvirt 版本。上游文档列出了当前支持的增强功能,可在 libvirt 文档的此部分 中找到。通常,所有这些都可以启用,但这会对使用的 QEMU 和 libvirt 版本提出要求,如果需要域迁移,这可能是一个问题。
技巧与提示
在虚拟机中使用整个物理磁盘设备
您可能有一个带有不同操作系统(如 Windows)的第二个磁盘,并希望能够在虚拟机中启动它。由于磁盘访问是原始的,磁盘在虚拟机中的性能会相当好。
Windows 虚拟机启动先决条件
在尝试在虚拟机中启动该磁盘上的操作系统之前,请确保已安装 virtio 驱动程序。对于 Win 7,请使用版本 0.1.173-4。较新 virtio 构建中的一些单个驱动程序可能可在 Win 7 上使用,但您必须通过设备管理器手动安装它们。对于 Win 10,您可以使用最新的 virtio 构建。
设置 Windows 磁盘接口驱动程序
尝试启动虚拟机时,您可能会遇到 0x0000007B 蓝屏。这意味着 Windows 在启动早期阶段无法访问驱动器,因为其所需的磁盘接口驱动程序未加载/设置为手动启动。
解决方法是 启用这些驱动程序在启动时启动。
在 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services 中,找到 aliide, amdide, atapi, cmdide, iastor (可能不存在), iastorV, intelide, LSI_SAS, msahci, pciide 和 viaide 文件夹。在每个文件夹中,将它们的“start”值全部设置为 0,以在启动时启用它们。如果您的驱动器是 PCIe NVMe 驱动器,也请启用该驱动程序(如果存在)。
查找磁盘的唯一路径
运行 ls /dev/disk/by-id/:在这里选择您想插入虚拟机的驱动器的 ID,例如 ata-TS512GMTS930L_C199211383。现在将此 ID 添加到 /dev/disk/by-id/,以便得到 /dev/disk/by-id/ata-TS512GMTS930L_C199211383。这是该磁盘的唯一路径。
在 QEMU CLI 中添加磁盘
在 QEMU CLI 中,这可能看起来像 -drive file=/dev/disk/by-id/ata-TS512GMTS930L_C199211383,format=raw,media=disk。
只需将 file= 修改为驱动器的唯一路径即可。
在 libvirt 中添加磁盘
在 libvirt XML 中,这会转换为:
$ virsh edit vmname
...
<disk type="block" device="disk">
<driver name="qemu" type="raw" cache="none" io="native"/>
<source dev="/dev/disk/by-id/ata-TS512GMTS930L_C199211383"/>
<target dev="sda" bus="sata"/>
<address type="drive" controller="0" bus="0" target="0" unit="0"/>
</disk>
...
只需将 "source dev" 修改为驱动器的唯一路径即可。
在 virt-manager 中添加磁盘
创建虚拟机时,选择“导入现有驱动器”并粘贴该唯一路径。如果您已有虚拟机,则添加设备、存储,然后选择或创建自定义存储。现在粘贴唯一路径。
Python 连接代码
libvirt-python 包在 /usr/lib/python3.x/site-packages/libvirt.py 中提供了 Python API。
通用示例在 /usr/share/doc/libvirt-python-your_libvirt_version/examples/ 中给出。
使用 qemu-desktop 和 openssh 的非官方示例
#! /usr/bin/env python3
import socket
import sys
import libvirt
conn = libvirt.open("qemu+ssh://xxx/system")
print("Trying to find node on xxx")
domains = conn.listDomainsID()
for domainID in domains:
domConnect = conn.lookupByID(domainID)
if domConnect.name() == 'xxx-node':
print("Found shared node on xxx with ID {}".format(domainID))
domServ = domConnect
break
高级格式 4K 原生磁盘
要将磁盘转换为 高级格式 4Kn 磁盘,其物理和逻辑扇区大小都需要设置为 4 KiB。对于 virtio-blk 和 virtio-scsi,这可以通过使用 <blockio> 元素设置 logical_block_size 和 physical_block_size 选项来完成。例如:
# virsh edit name_of_virtual_machine
<domain>
...
<devices>
...
<disk type='file' device='disk'>
..
<blockio logical_block_size='4096' physical_block_size='4096'/>
</disk>
...
</devices>
</domain>
嵌套虚拟化
libvirt 在运行 QEMU/KVM 时可以为域提供嵌套虚拟化。要实现此目的,必须对 KVM 进行适当配置,请参阅 KVM#Nested virtualization。
在 libvirt 配置中要做的唯一更改是将域的 CPU 模型设置为 `host-model` 或 `host-passthrough`。
命令 QEMU
libvirt 能够将 QEMU 命令行参数传递给运行虚拟机的底层 QEMU 实例。当 libvirt 尚不提供 QEMU 功能时,此功能非常有用。例如,请参阅整个 Intel GVT-g 文章。
修改 QEMU 的虚拟机 XML 架构
这用于启用 QEMU 特定元素。更改:
$ virsh edit vmname
<domain type='kvm'>
更改为
$ virsh edit vmname
<domain xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0' type='kvm'>
QEMU 命令行参数
在 libvirt 中,需要单独提供用空格分隔的 QEMU 命令行参数。
插入它们的正确位置是 <domain> 元素的末尾,即在关闭 </domain> 标签之前。
-display gtk,gl=es,zoom-to-fit=off
变为:
$ virsh edit vmname
...
</devices>
<qemu:commandline>
<qemu:arg value="-display"/>
<qemu:arg value="gtk,gl=es,zoom-to-fit=off"/>
</qemu:commandline>
</domain>
故障排除
系统实例上的 PulseAudio
PulseAudio 守护进程通常在您的常规用户帐户下运行,并且仅接受来自同一用户的连接。如果 QEMU 通过 libvirt 以 root 身份运行,这可能会有问题。要以常规用户身份运行 QEMU,请编辑 /etc/libvirt/qemu.conf 并将 user 选项设置为您的用户名。
user = "dave"
您还需要告知 QEMU 使用 PulseAudio 后端并识别要连接的服务器。使用 virsh edit 将以下部分添加到您的域配置中。
<audio id="1" type="pulseaudio" serverName="/run/user/1000/pulse/native">
<input latency="20000"/>
<output latency="20000"/>
</audio>
1000 是您的用户 ID。如果需要,请更改它。
您可以省略延迟设置(以微秒为单位),但使用默认值可能会导致爆音。
虚拟机监视器 CPU 使用率
virt-manager 生成的默认虚拟机配置可能导致 QEMU 进程占用相当高的 CPU(10-20%)。如果您计划在无头模式下运行虚拟机,请考虑删除一些不必要的设备。
虚拟机无法在 virt-manager 中取消暂停
如果您使用的磁盘映像格式(如 qcow2)具有指定的虚拟容量,但仅存储所需内容,则您需要在主机分区上有空间供映像增长。如果您在尝试启动虚拟机时看到与 I/O 相关的错误,则可能是保存虚拟磁盘映像的主机分区已满。您可以在主机上运行 df -h 来验证可用空间。
如果出现这种情况,请参阅 System maintenance#Clean the filesystem 以了解释放空间的方法。
virt-manager 中“重定向 USB 设备”呈灰色
如果 重定向 USB 设备 菜单项呈灰色,请检查虚拟机是否已配置以下硬件:
- USB 控制器。
- 一个或多个 USB 重定向器。
错误启动域:请求的操作无效
当您尝试打开虚拟机时,可能会弹出此错误。这是因为当您尝试打开现有虚拟机时,libvirt 会尝试搜索默认网络,但该网络不可用。要使其可用,您必须自动启动网络接口,以便每次重新启动计算机时,网络接口始终处于活动状态。请参阅 libvirt 网络页面。
使用以下命令查看网络接口的名称:
# virsh net-list --all
自动启动网络接口
# virsh net-autostart name_of_the_network
启动您的网络接口
# virsh net-start name_of_the_network
Virt Manager 错误“Virt Manager 没有搜索权限”
确保包含虚拟机文件和安装 ISO 的文件夹归 libvirt-qemu 组所有。
# chown -R $USER:libvirt-qemu /path/to/virtual/machine
错误启动域:请求的操作无效:网络 'default' 未激活
如果由于任何原因禁用了默认网络,则无法启动配置为使用该网络的任何客户机虚拟机。您的第一个尝试可以是简单地尝试使用 virsh 启动网络。
# virsh net-start default
有关其他故障排除步骤,请参阅 [4]。