libvirt

来自 ArchWiki

Libvirt 是一个软件集合,它提供了一种管理虚拟机和其他虚拟化功能的便捷方法,例如存储和网络接口管理。这些软件部分包括一个长期稳定的 C API、一个守护进程 (libvirtd) 和一个命令行实用程序 (virsh)。libvirt 的主要目标是提供一种管理多种不同虚拟化提供程序/hypervisor 的单一方法,例如 KVM/QEMUXenLXCOpenVZVirtualBox hypervisor以及其他)。

libvirt 的一些主要功能包括

  • VM 管理:各种域生命周期操作,例如启动、停止、暂停、保存、恢复和迁移。针对多种设备类型的热插拔操作,包括磁盘和网络接口、内存和 CPU。
  • 远程机器支持:所有 libvirt 功能都可以在运行 libvirt 守护进程的任何机器上访问,包括远程机器。支持多种网络传输方式进行远程连接,最简单的是 SSH,它不需要额外的显式配置。
  • 存储管理:运行 libvirt 守护进程的任何主机都可以用于管理各种类型的存储:创建各种格式(qcow2、vmdk、raw 等)的文件映像,挂载 NFS 共享,枚举现有的 LVM 卷组,创建新的 LVM 卷组和逻辑卷,分区原始磁盘设备,挂载 iSCSI 共享等等。
  • 网络接口管理:运行 libvirt 守护进程的任何主机都可以用于管理物理和逻辑网络接口。枚举现有接口,以及配置(和创建)接口、网桥、vlan 和 bond 设备。
  • 虚拟 NAT 和基于路由的网络:运行 libvirt 守护进程的任何主机都可以管理和创建虚拟网络。Libvirt 虚拟网络使用防火墙规则充当路由器,为 VM 提供对主机网络透明的访问。

安装

由于其守护进程/客户端架构,libvirt 只需要安装在将托管虚拟化系统的机器上。请注意,服务器和客户端可以是同一物理机器。

服务器

安装 libvirt 软件包,以及至少一个 hypervisor

  • 其他 支持的 hypervisor 包括 LXCVirtualBoxXen。有关安装说明,请参阅各自的文章。关于 libvirtd 安装说明
    • libvirt LXC 驱动程序不依赖于 lxc 提供的 LXC 用户空间工具,因此,如果计划使用该驱动程序,则无需安装该软件包。libvirtd 需要运行才能使用 libvirt-lxc 连接。
    • Xen 支持可用,但默认情况下不启用 (FS#27356)。您需要使用 ABS 来修改 libvirtPKGBUILD,并在构建时删除 -Ddriver_libxl=disabled 选项。

对于网络连接,请安装

其他可选依赖项可能会提供所需或扩展的功能,例如 dmidecode 用于 DMI 系统信息支持。在阅读 pacman 的 libvirt 输出后,作为依赖项 安装您可能需要的那些。

注意: 如果您正在使用 firewalld,从 libvirt 5.1.0 和 firewalld 0.7.0 开始,您不再需要将防火墙后端更改为 iptableslibvirt 现在在 firewalld 中安装一个名为“libvirt”的区域,并在那里管理其所需的网络规则。请参阅 libvirt 中的防火墙和网络过滤

客户端

客户端是用于管理和访问虚拟机的用户界面。

  • virsh — 用于管理和配置域的命令行程序。
https://libvirt.org/ || libvirt
  • Boxes — 简单的 GNOME 应用程序,用于访问虚拟系统。属于 gnome-extra 的一部分。
https://apps.gnome.org/Boxes/ || gnome-boxes
  • Libvirt Sandbox — 应用程序沙箱工具包。
https://sandbox.libvirt.org/ || libvirt-sandboxAUR
  • Virt Viewer — 简单的远程显示客户端。
https://gitlab.com/virt-viewer/virt-viewer || virt-viewer
  • Virt-manager — 通过 libvirt 以图形方式管理 KVM、Xen 或 LXC。
https://virt-manager.org/ || virt-manager
  • Cockpit — 基于 Web 的系统管理工具,带有用于管理虚拟机的插件。
https://cockpit-project.org/ || cockpit-machines

可以在此处找到与 libvirt 兼容的软件列表。

配置

Libvirt 可以通过两种模式(系统和会话)管理 QEMU 虚拟机[1][2]

  • 系统 URI 连接到以 root 身份运行的 libvirtd 守护进程,该守护进程在系统启动时启动。使用“系统”创建和运行的虚拟机通常以 root 身份启动,除非另有配置(例如在 /etc/libvirt/qemu.conf 中)。
  • 会话 URI 以本地用户身份启动 libvirtd 实例,并且所有 VM 都以本地用户权限运行。

关于它们的优缺点

  • 主机启动时的 VM 自动启动仅适用于“系统”,并且 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 套接字都可以独立配置其身份验证机制。目前有 nonepolkitsasl 可供选择。

使用 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 代理的问题,该代理可能无法正常工作。
提示: 如果您想配置无密码身份验证,请参阅 Polkit#绕过密码提示

您可以更改授权访问 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 用户。

守护进程

注意: Libvirt 正在从单个单片守护进程迁移到单独的模块化守护进程,目的是在将来删除单片守护进程。有关更多信息,请参阅 Libvirt 守护进程

启动 libvirtd.servicevirtlogd.service。可选地启用 libvirtd.service(这也将启用 virtlogd.socketvirtlockd.socket 单元,因此不需要也启用 virtlogd.service)。

另一种可能性是仅启动/启用 libvirtd.socketvirtlogd.socket 以进行按需套接字激活。

未加密的 TCP/IP 套接字

警告: 此方法用于帮助远程域,提高可信网络的连接速度。这是最不安全的连接方法。应将其用于测试或在安全、私有和可信的网络上使用。此处未启用 SASL,因此所有 TCP 流量都是明文。对于实际使用,始终启用 SASL。

编辑 /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"

使用虚拟机的主机名访问虚拟机

为了使主机能够访问非隔离的桥接网络上的 guest,请启用 libvirt 提供的 libvirt 和/或 libvirt_guest NSS 模块。有关这两个模块的比较和技术细节,请参阅 libvirt 文档

nsswitch.conf(5) 中添加所需的模块

/etc/nsswitch.conf
hosts: files libvirt libvirt_guest dns myhostname
注意: 虽然诸如 pingssh 之类的命令应与虚拟机主机名一起使用,但诸如 hostnslookup 之类的命令可能会失败或产生意外结果,因为它们依赖于 DNS。请改用 getent hosts <vm-hostname>

测试

要测试 libvirt 在系统级别是否正常工作

$ virsh -c qemu:///system

要测试 libvirt 对于用户会话是否正常工作

$ virsh -c qemu:///session

管理

Libvirt 管理主要通过三个工具完成:virt-manager (GUI)、virshguestfish(它是 libguestfs 的一部分)。

virsh

virsh 程序用于管理 guest (虚拟机),并且非常适合脚本编写和虚拟化管理。虽然大多数 virsh 命令由于用于与 hypervisor 通信的通道而需要 root 权限才能运行,但域的典型管理、创建和运行(如 VirtualBox 所做的那样)可以作为普通用户完成。

如果未传递任何命令(但允许选项),Virsh 包括可以进入的交互式终端:virsh。交互式终端支持 Tab 补全。

从命令行

$ 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
提示: 对于 LVM 存储池
  • 最好为存储池专门分配一个卷组。
  • 选择与池名称不同的 LVM 卷组,否则,当存储池被删除时,LVM 组也会被删除。

使用 virt-manager 创建新池

首先,连接到 hypervisor(例如 QEMU/KVM 系统或用户会话)。然后,右键单击连接并选择详细信息;选择存储选项卡,按下左下角的 + 按钮,然后按照向导操作。

存储卷

创建池后,可以在池内创建卷。如果构建新的域(虚拟机),则可以跳过此步骤,因为可以在域创建过程中创建卷。

使用 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 或使用 virt-install(作为 virt-install 软件包的一部分安装的命令行程序)完成。

创建新域通常涉及使用一些安装介质,例如来自存储池或光驱的 .iso

打印活动和非活动域

# virsh list --all
注意: SELinux 对 libvirt 具有内置豁免,允许访问 /var/lib/libvirt/images/ 中的卷。如果使用 SELinux 并且卷存在问题,请确保卷位于该目录中,或确保其他存储池已正确标记。

使用 virt-install 创建新域

本文或本节的事实准确性存在争议。

原因: /usr/share/libosinfo 不是由任何官方软件包提供的,包括 libosinfo。(在 Talk:Libvirt#Where_is_'/usr/share/libosinfo/db/oses/os.xml'? 中讨论)

对于极其详细的域(虚拟机)设置,#使用 virt-manager 创建新域更容易。但是,基本操作可以轻松地通过 virt-install 完成,并且仍然可以运行良好。最低规格为 --name--memory、guest 存储(--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/libosinfo/db/oses/os.xml 中查找。安装后,最好安装 Spice Guest Tools,其中包括 VirtIO 驱动程序。对于 Windows VirtIO 网络驱动程序,还有 virtio-winAUR。这些驱动程序通过 guest 的设备 .xml 配置文件部分中的 <model type='virtio' /> 引用。有关更多信息,请参见 QEMU 文章

导入现有卷

$ virt-install  \
  --name demo  \
  --memory 512 \
  --disk /home/user/VMs/mydisk.img \
  --import

使用 virt-manager 创建新域

首先,连接到 hypervisor(例如 QEMU/KVM 系统或用户会话),右键单击连接并选择新建,然后按照向导操作。

  • 第四步中,取消选择立即分配整个磁盘将使设置更快,并且可以节省临时磁盘空间;但是,随着时间的推移,它可能会导致卷碎片。
  • 第五步中,打开高级选项并确保虚拟化类型设置为 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.service systemd 服务在主机关闭时自动挂起/关闭正在运行的域。此服务将在主机启动时自动恢复/启动挂起/关闭的域。有关详细信息和服务选项,请参阅 libvirt-guests(8)

编辑域的 XML 配置

$ virsh edit domain

要了解更多关于 XML 配置的信息,请阅读 libvirt wiki 的 XML 格式 部分。

注意: 直接由 QEMU 启动的虚拟机不能通过 libvirt 工具进行管理。

网络

关于 libvirt 网络的全面概述

存在四种网络类型,可以创建这些网络以将域连接到:

  • bridge — 虚拟设备;直接与物理接口共享数据。如果主机具有静态网络,不需要连接其他域,域需要完整的入站和出站流量,并且域在系统级别上运行,则使用此类型。桥接必须在 libvirt 之外配置。请参阅网络桥接,了解如何添加桥接。创建后,需要在相应的访客机的 .xml 配置文件中指定它。
  • network — 虚拟网络;能够与其他域共享。Libvirt 提供了许多虚拟网络模式,例如 NAT 模式(网络地址转换)、路由模式和隔离模式。如果主机具有动态网络(例如 NetworkManager)或使用无线网络,则尤其建议使用虚拟网络。
  • macvtap — 直接连接到主机物理接口。这比 bridge 网络设置简单得多,唯一的缺点是主机无法通过此接口与域通信。Libvirt 可以轻松设置这种类型的网络。
  • user — 本地能力网络。仅在用户会话中使用此类型。

virsh 具有创建网络的能力,并为大多数用户提供了众多选项,但是,使用图形用户界面(如 virt-manager)创建网络连接更容易,或者在 使用 virt-install 创建 时这样做。

注意
  • libvirt 使用 dnsmasq 处理 DHCP 和 DNS,为每个虚拟网络启动一个单独的实例。它还添加了 iptables 规则以进行适当的路由,并启用了 ip_forward 内核参数。这也意味着,主机系统上运行 dnsmasq 对于支持 libvirt 要求不是必需的(并且可能会干扰 libvirt dnsmasq 实例)。
  • 如果默认网络无法启动,请确保已安装 iptables-nftdnsmasq,并且 iptables systemd 服务已启用。
$ systemctl start iptables.service
$ systemctl enable iptables.service
$ systemctl restart libvirtd.service
注意

如果要使用 iptables不是 nftables,则需要在配置文件中相应地指定:/etc/libvirt/network.conf

示例:

# default: #firewall_backend = "nftables"
firewall_backend = "iptables"

您可以通过以下方式获取 VM 的 IP 地址(如果它连接到 default 网络并通过 dhcp 接收 IP 地址):

$ virsh net-dhcp-leases default

命令(将 default 替换为 VM 连接的网络名称),或者如果 VM 运行了 qemu-guest-agent,则通过:

$ virsh domifaddr --source agent $vm

$vm 替换为实际的虚拟机名称(或域 ID)。

管理和修改您的网络

要修改您的虚拟网络,强烈建议阅读 libvirt wiki 中的 虚拟网络的基本命令行用法 指南。还建议阅读 libvirt 网络 wiki,以了解更多关于其用法的知识。

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

Macvtap

要设置 macvtap 网络,首先创建此文件:

macvtap.xml
<network>
  <name>macvtap-net</name>
  <forward mode='bridge'>
    <interface dev='eth0'/>
  </forward>
</network>

然后,定义并启用网络:

$ virsh net-define macvtap.xml
$ virsh net-autostart macvtap-net
$ virsh net-start macvtap-net

现在,网络 macvtap-net 可用,并且在重启后仍然持久存在。它通过 eth0 桥接到外部网络。

警告: 主机无法通过此网络与域通信。主机的网络不会受到影响,并且域可以与网络上的其他机器通信,但不能与主机自身通信。有关解决方法,请参阅 libvirt wiki

nftables 防火墙

当将 NAT 网络类型与简单的限制性 nftables 防火墙(例如,默认配置)结合使用时,您可能需要允许转发到/从虚拟网络接口(默认配置在此处丢弃数据包)以及从虚拟网络接口到主机的 DHCP 客户端的 DNS/DHCP 请求。简化的示例,假设 virbr0 作为 libvirt 桥接接口:

/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
  }
}

快照

快照在某个时间点获取域的磁盘、内存和设备状态,并将其保存以供将来使用。它们有许多用途,从保存操作系统映像的“干净”副本到在潜在的破坏性操作之前保存域的状态。快照使用唯一的名称进行标识。

快照保存在卷本身内,并且卷的格式必须为:qcow2 或 raw。快照使用增量,以便不占用像完整副本那样多的空间。

创建快照

本文或章节已过时。

原因: 某些数据似乎已过时。(在 Talk:Libvirt 中讨论)

一旦拍摄快照,它将被保存为新的块设备,并且原始快照将脱机。可以从快照中选择,也可以将快照合并到另一个快照中(即使在不关闭域的情况下)。

打印正在运行的域的卷(可以使用 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=truersync -S 复制原始映像,然后将原始映像合并回快照:

# virsh blockpull --domain domain --path /vms/domain.snapshot1

domain.snapshot1 成为新卷。完成此操作后,可以删除原始卷(domain.img 和快照元数据)。virsh blockcommit 的作用与 blockpull 相反,但它似乎目前正在开发中(包括 snapshot-revert feature,计划在明年某个时候发布)。

其他管理

连接到非默认的 hypervisor

$ virsh --connect xen:///
virsh # uri
xen:///

通过 SSH 连接到 QEMU hypervisor;记录日志的方式相同:

$ 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
注意: 如果您在连接到远程 RHEL 服务器(或任何其他非 Arch 的服务器)时遇到问题,请尝试 FS#30748FS#22068 中提到的两种解决方法。

连接到 VirtualBox hypervisor(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、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 用户执行

每次遇到触发点时,脚本都会运行。例如,守护程序脚本在系统的启动/停止周期中至少运行两次,分别在启动和关闭时运行。要在给定的点仅运行一个命令,您必须在脚本中实现条件。为此,libvirt 传递了可用于标识当前触发条件的参数。

根据 libvirt 文档,这些参数定义如下:

  • 参数 1:操作中涉及的对象的名称
  • 参数 2:正在执行的操作的名称
  • 参数 3:如果要命名子操作,则使用此参数
  • 参数 4:如果需要,额外的参数

如果其中一个参数不适用,则传递一个破折号。

注意: 如果在创建脚本后钩子不起作用,请尝试重启 libvirt 守护程序。

示例

要在每次启动 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

注意: QEMU/KVM 用户会话不支持 Virtio-FS。

此处的描述将使用巨页来启用共享文件夹的使用。使用 Virtio-FS 共享文件 列出了启用与访客机文件共享的受支持选项的概述。

首先,您需要启用巨页,这些巨页由虚拟机使用。

/etc/sysctl.d/40-hugepage.conf
vm.nr_hugepages = nr_hugepages

要确定所需的巨页数量,请检查巨页的大小:

$ grep Hugepagesize /proc/meminfo

巨页的数量为虚拟机内存大小 / 巨页大小。在此值上添加一些额外的页面。在此步骤之后,您必须重启,以便分配巨页。

现在,您必须准备虚拟机的配置:

# 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>
...
  <devices>
    ...
    <filesystem type='mount' accessmode='passthrough'>
      <driver type='virtiofs'/>
      <source dir='path to source folder on host'/>
      <target dir='mount_tag'/>
    </filesystem>
    ...
  </devices>
</domain>

有必要添加 NUMA 定义,以便可以将内存访问声明为共享。NUMA 的 id 和 cpus 值将由 virsh 插入。

现在应该可以在共享机器中挂载文件夹了:

# mount -t virtiofs mount_tag /mnt/mount/path

添加以下 fstab 条目以在启动时自动挂载文件夹:

/etc/fstab
...
mount_tag /mnt/mount/path virtiofs rw,noatime,_netdev 0 0

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=virtio9pnet_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 确保仅在需要时挂载共享,而不会在 vm 未启动时引起问题。user,credentials=/home/user/.config/my_vm.key,gid=1000,uid=984 使您能够在首次访问时动态挂载共享,而无需密码

UEFI 支持

Libvirt 可以通过 QEMU 和 OVMF 支持 UEFI 虚拟机。

安装 edk2-ovmf 软件包。

重启 libvirtd

现在您可以创建 UEFI 虚拟机了。通过 virt-manager 创建新的虚拟机。当您到达新建 VM 向导的最后一页时,执行以下操作:

  1. 单击安装前自定义配置,然后选择完成
  2. 概述屏幕中,将固件字段更改为:
    • 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(不带任何预先注册的证书)。
  3. 单击应用
  4. 单击开始安装

有关更多信息,请参阅 Fedora:Using UEFI with QEMU

技巧和窍门

在虚拟机内部使用整个物理磁盘设备

您可能有一个带有不同操作系统(例如 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-desktopopenssh 的非官方示例:

#! /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_sizephysical_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>

命令 QEMU

Libvirt 能够将 QEMU 命令行参数传递给运行 VM 的底层 QEMU 实例。当 libvirt 尚未提供 QEMU 功能 时,此功能非常有用。有关示例,请参阅完整的 Intel GVT-g 文章。

修改 VM XML 模式以用于 QEMU

这用于启用 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。如有必要,请更改它。

您可以省略延迟设置(以微秒为单位),但是使用默认值可能会导致爆裂声。

Hypervisor CPU 使用率

virt-manager 生成的默认 VM 配置可能会导致 QEMU 进程引起的 CPU 使用率相当高(10-20%)。如果您计划在无头模式下运行 VM,请考虑删除一些不必要的设备。

虚拟机无法在 virt-manager 上取消暂停

如果您使用的是磁盘映像格式(例如 qcow2),它具有指定的虚拟容量,但仅存储所需的容量,那么您需要在主机分区上留出空间以供映像增长。如果您在尝试启动 VM 时看到 I/O 相关错误,则可能是保存虚拟磁盘映像的主机分区已满。您可以在主机上运行 df -h 以验证有多少可用空间。

如果是这种情况,请参阅 系统维护#清理文件系统,了解释放空间的方法。

在 virt-manager 中,“重定向 USB 设备” 菜单项灰显

如果重定向 USB 设备菜单项灰显,请检查是否为 VM 配置了以下硬件:

  • 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 组所有:

$ sudo chown -R $USER:libvirt-qemu /path/to/virtual/machine

启动域时出错:请求的操作无效:网络 'default' 未激活

如果由于任何原因默认网络被停用,您将无法启动任何配置为使用该网络的访客虚拟机。您的第一次尝试可以是简单地尝试使用 virsh 启动网络:

# virsh net-start default

有关其他故障排除步骤,请参阅 [3]

另请参阅