libvirt

来自 Arch Linux 中文维基

Libvirt 是一组软件的汇集,提供了管理虚拟机和其它虚拟化功能(如:存储和网络接口等)的便利途径。这些软件包括:一个长期稳定的 C 语言 API、一个守护进程(libvirtd)和一个命令行工具(virsh)。Libvirt 的主要目标是提供一个单一途径以管理多种不同虚拟化方案以及虚拟化主机,包括:KVM/QEMUXenLXCOpenVZVirtualBox hypervisors详见这里)。

Libvirt 的一些主要功能如下:

  • VM management(虚拟机管理):各种虚拟机生命周期的操作,如:启动、停止、暂停、保存、恢复和迁移等;多种不同类型设备的热插拔操作,包括磁盘、网络接口、内存、CPU等。
  • Remote machine support(支持远程连接):Libvirt 的所有功能都可以在运行着 libvirt 守护进程的机器上执行,包括远程机器。可以使用最简便且无需额外配置的 SSH 协议,也可以使用受支持的多种网络连接方式。
  • Storage management(存储管理):任何运行 libvirt 守护进程的主机都可以用于管理多种类型的存储:创建多种类型的文件镜像(qcow2,vmdk,raw,...),挂载 NFS 共享,枚举现有 LVM 卷组,创建新的 LVM 卷组和逻辑卷,对裸磁盘设备分区,挂载 iSCSI 共享,以及更多......
  • Network interface management(网络接口管理):任何运行 libvirt 守护进程的主机都可以用于管理物理的和逻辑的网络接口,枚举现有接口,配置(和创建)接口、桥接、VLAN、端口绑定。
  • Virtual NAT and Route based networking(虚拟 NAT 和基于路由的网络):任何运行 libvirt 守护进程的主机都可以管理和创建虚拟网络。Libvirt 虚拟网络使用防火墙规则实现一个路由器,为虚拟机提供到主机网络的透明访问。

安装[编辑 | 编辑源代码]

基于守护进程/客户端的架构的 libvirt 只需要安装在需要要实现虚拟化的机器上。注意,服务器和客户端可以是相同的物理机器。

服务端[编辑 | 编辑源代码]

安装 libvirt 以及至少一个虚拟运行环境(hypervisor):

  • 其他受支持的虚拟运行环境包括 LXCVirtualBoxXen。请参见它们各自的安装说明。有关 libvirtd 的安装备注:
    • Libvirt 的 LXC 驱动 并不依赖 lxc 提供的 LXC 用户空间工具。因此,无需安装该工具也能使用这个驱动。需要 libvirtd 处于运行状态才能使用 libvirt-lxc 连接。
    • Libvirt 能支持 Xen,但默认未内建支持(FS#27356)。需要用 ABS 编辑 libvirtPKGBUILD ,去掉 -Ddriver_libxl=disabled 选项后重新构建(built)libvirt。

对于网络连接,需要安装这些包:

Other optional dependencies may provide desired or extended features, such as dmidecode for DMI system info support. Install the ones you may need as dependencies after reading pacman's output for libvirt.

注意: If you are using firewalld, as of libvirt 5.1.0 and firewalld 0.7.0 you no longer need to change the firewall backend to iptables. libvirt now installs a zone called 'libvirt' in firewalld and manages its required network rules there. See Firewall and network filtering in libvirt.

客户端[编辑 | 编辑源代码]

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

  • virsh — 用于管理和配置域(虚拟机)的命令行程序。
https://libvirt.org/ || libvirt
  • GNOME Boxes — 简单的 GNOME 3 程序,可以访问远程虚拟系统。是 gnome-extra包组的一部分。
https://wiki.gnome.org/Apps/Boxes || gnome-boxes
  • Libvirt Sandbox — 应用程序沙箱工具包。
https://sandbox.libvirt.org/ || libvirt-sandboxAUR
  • Virt Viewer — 简单的远程显示客户端。
https://gitlab.com/virt-viewer/virt-viewer || virt-viewer
  • Qt VirtManager — 管理虚拟机的Qt程序。
https://github.com/F1ash/qt-virt-manager || qt-virt-managerAUR
  • Virt-manager — 用于图形化使用 libvirt 管理 KVM,Xen 或是 LXC。
https://virt-manager.org/ || virt-manager
  • Cockpit — 基于网页的系统管理工具,可通过插件管理虚拟机。
https://cockpit-project.org/ || cockpit-machines

兼容 libvirt 的软件列表见 这里.

配置[编辑 | 编辑源代码]

对于系统 级别的管理任务(如:全局配置和镜像 位置),libvirt 要求至少要设置授权启动守护进程

注意: 对于用户会话 级别的管理任务,守护进程的安装和设置不是必须的。授权总是仅限本地,前台程序将启动一个 libvirtd 守护进程的本地实例。

设置授权[编辑 | 编辑源代码]

来自 libvirt:连接授权

Libvirt 守护进程允许管理员分别为客户端连接的每个网络 socket 选择不同授权机制。这主要是通过 libvirt 守护进程的主配置文件 /etc/libvirt/libvirtd.conf 来实现的。每个 libvirt socket 可以有独立的授权机制配置。目前的可选项有 nonepolkitsasl

Using libvirt group[编辑 | 编辑源代码]

The easiest way to ensure your user has access to libvirt daemon is to add member to libvirt user group.

Members of the libvirt group have passwordless access to the RW daemon socket by default.

使用 polkit[编辑 | 编辑源代码]

Because libvirt pulls polkit as a dependency during installation, polkit is used as the default value for the unix_sock_auth parameter (source). File-based permissions remain nevertheless available.

注意: 为使 polkit 认证工作正常,应该重启一次系统。

libvirt 守护进程在 polkit 策略配置文件(/usr/share/polkit-1/actions/org.libvirt.unix.policy)中提供了两种 polkit 操作

  • org.libvirt.unix.manage 面向完全的管理访问(读写模式后台 socket),以及
  • org.libvirt.unix.monitor 面向仅监视察看访问(只读 socket)。

默认的面向读写模式后台 socket 的策略需要认证为管理员。这点类似于 sudo 认证,但它并不要求客户应用最终以 root 身份运行。默认策略下也仍然允许任何应用连接到只读 socket。

Arch Linux 默认 wheel 组的所有用户都是管理员身份:定义于 /etc/polkit-1/rules.d/50-default.rules(参阅:Polkit#管理员身份认证)。所以如果用户是 wheel 组的成员,就不必新建组和规则文件:只要连接到了读写模式 socket(例如通过 virt-manager)就会被提示输入该用户的口令。

注意: 口令提示依赖于系统上的身份认证组件。文本控制台默认的认证代理是 pkttyagent,它可能因工作不正常而导致各种问题。
提示:如果要配置无口令认证,参阅 Polkit#跳过口令提示

你可能想要修改授权以读写模式访问 socket 的组。例如,你想授权 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 is moving from a single monolithic daemon to separate modular daemons, with the intention to remove the monolithic daemon in the future. See Libvirt daemons for more infomation.

libvirtd.servicevirtlogd.service这两个服务单元都要启动。可以把 libvirtd.service 设置为启用,这时系统将同时启用 virtlogd.servicevirtlockd.socket 两个服务单元,因此后二者不必再设置为启用

非加密的 TCP/IP sockets[编辑 | 编辑源代码]

警告: 这种方法常用于在可信网络中快速连接远程域做协助。这是最不安全 的连接方式,应当仅仅用于测试或用于安全、私密和可信的网络环境。这时 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"

用主机名访问虚拟机[编辑 | 编辑源代码]

在非隔离的、桥接的网络中从宿主机访问客户机,可以通过启用 libvirt 提供的 libvirt 和/或 libvirt_guest NSS 模块来实现。For the comparison of the two modules and technical details, see libvirt documentation.

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(图形界面)、virshguestfish(它是 libguestfs 的一部分)。

virsh[编辑 | 编辑源代码]

Visrsh 用于管理客户(虚拟机),适用于脚本及虚拟环境管理工作。受限于与虚拟化环境通信的通道,绝大部分 virsh 命令需要管理员权限。尽管如此,一些典型的管理操作如域的创建、运行等也可以像 VirtualBox 那样以普通用户身份执行。

Virsh 允许带命令行选项执行。如果不带则进入其内置的交互式终端:virsh。交互式终端支持 tab 键命令补全。

从命令行执行:

$ virsh [可选项] <命令> [参数]...

在交互式终端里运行:

virsh # <命令> [参数]...

帮助也是可用的:

$ 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 卷组不同的名字。否则当存储池被删除时,该卷组也将被删除。

用 virt-manager 新建存储池[编辑 | 编辑源代码]

首先,连接到虚拟运行环境(例如 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 有内置策略使在 /var/lib/libvirt/images/ 中的卷可以被访问。如果你使用 SELinux 并且在卷方面有问题,确保卷位于该目录,或是其它存储池的标记正常。

用 virt-install 新建域[编辑 | 编辑源代码]

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

原因: /usr/share/libosinfo is not provided by any official packages, including libosinfo.(在 Talk:Libvirt#Where_is_'/usr/share/libosinfo/db/oses/os.xml'? 中讨论)


对于很详细的域(虚拟机)配置,可以#用 virt-manager 新建域更简单地完成。但是,基础配置同样可以用 virt-install 完成并且同样顺利运行。最小配置包括 --name--memory,存储(--disk--filesystem--nodisks)和安装介质(通常来说是 .iso 文件或 CD)。查看 virt-install(1) 得到未列出的选项和更多的详情。

安装 Arch Linux(创建了 2 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 testing (Xen, 非默认池,无默认控制台):

$ 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 获得。要使用 VirtIO,需要在虚拟机 .xml 配置中使用 <model type='virtio' />。更多的信息可以参考 QEMU 页面.

导入现有的卷:

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

用 virt-manager 新建域[编辑 | 编辑源代码]

首先,连接到虚拟运行环境(例如 QEMU/KVM system 或用户 session,在连接上右击并选择 新建,然后跟随向导完成。

  • 第四步中取消选中立即分配全部虚拟磁盘空间会加快创建过程并节省实际虚拟磁盘空间占用;然而,这将导致将来花费额外的磁盘整理时间。
  • 第五步中打开高级选项并确认虚拟化类型设为 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

参考 libvirt 维基的 XML 格式一节了解关于 XML 配置文件的信息。

注意: 直接被 QEMU 启动的虚拟机不被 libvirt 管理。

网络[编辑 | 编辑源代码]

这里是有关 libvirt 网络的的概述。

可将以下四种网络连接到域:

  • bridge — 这是一个虚拟设备,它通过一个物理接口直接共享数据。使用场景为:宿主机有 静态 网络、不需与其它域连接、要占用全部进出流量,并且域运行于 系统 层级。网桥必须要在 libvirt 外配置,详细操作可参考网桥。网桥创建后,需要将它指定到相应客户机的 .xml 配置文件中。
  • network — 这是一个虚拟网络,它可以与其它虚拟机共用。Libvirt 提供多种虚拟网络模式,例如 NAT(Network address translation,网络地址转换)模式,路由模式和隔离模式。使用场景为:宿主机有 动态 网络(例如:NetworkManager)或使用无线网络。
  • macvtap — 直接连接到宿主机的一个物理网络接口。相较桥接更加简单,代价是宿主机无法通过该接口与域通信。Libvirt 可以很方便地配置该类网络。
  • user — 本地网络,仅用于用户 会话

绝大多数用户都可以通过 virsh 的各种可选项创建具有各种功能的网络,一般来说通过 GUI 程序(像 virt-manager 之类)更方便,也可以按 #用 virt-install 新建域 所述实现。

注意:
  • libvirt 通过 dnsmasq 处理 DHCP 和 DNS 请求,为每个虚拟网络创建一个实例。它也会为特定的路由添加 iptables 规则并启用 ip_forward 内核参数。这也意味着宿主机上无需预先运行 dnsmasq(并可能干扰到 libvirt 的 dnsmasq 实例)。
  • 如果无法启动默认网络,请确保已安装 iptables-nftdnsmasq

通过以下命令获取虚拟机的 IP(假设它连接到 default 网络并通过 DHCP 获取 IP):

$ virsh net-dhcp-leases default

如果 VM 上运行有 qemu-guest-agent

$ virsh domifaddr --source agent $vm

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

管理并修改网络[编辑 | 编辑源代码]

修改网络前建议先阅读 libvirt 维基的用于虚拟网络的基本命令行用法一节。另外也建议通过 libvirt 网络维基了解用法。

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 维基绕过该限制。

快照[编辑 | 编辑源代码]

快照保存某一时刻域的磁盘、内存和设备状态以供将来使用。快照有很多用处,例如在进行可能的破坏性操作时保存一份干净的域状态。快照使用唯一名称进行标识。

快照保存在卷之中,卷必须为 qcow2 或 raw 格式。快照使用增量存储,所以并不会占用很多空间。

创建快照[编辑 | 编辑源代码]

本文内容或本节内容已经过期。

原因: Some of this data appears to be dated. (在Talk:Libvirt讨论)

Once a snapshot is taken it is saved as a new block device and the original snapshot is taken offline. Snapshots can be chosen from and also merged into another (even without shutting down the domain).

Print a running domain's volumes (running domains can be printed with virsh list):

# virsh domblklist domain
 Target     Source
 ------------------------------------------------
 vda        /vms/domain.img

To see a volume's physical properties:

# 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

Create a disk-only snapshot (the option --atomic will prevent the volume from being modified if snapshot creation fails):

# virsh snapshot-create-as domain snapshot1 --disk-only --atomic

List snapshots:

# virsh snapshot-list domain
 Name                 Creation Time             State
 ------------------------------------------------------------
 snapshot1           2012-10-21 17:12:57 -0700 disk-snapshot

One can then copy the original image with cp --sparse=true or rsync -S and then merge the original back into snapshot:

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

domain.snapshot1 becomes a new volume. After this is done the original volume (domain.img and snapshot metadata can be deleted. The virsh blockcommit would work opposite to blockpull but it seems to be currently under development (including snapshot-revert feature, scheduled to be released sometime next year.

其它管理操作[编辑 | 编辑源代码]

连接到非默认的虚拟运行环境:

$ 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
注意: 如果你在连接 RHEL 服务器(或其他不是 Arch 的服务器)时出现问题,可尝试这里提到的两个方案:FS#30748FS#22068

连接到 VirtualBox(libvirt 对 VirtualBox 的支持尚不稳定,可能会导致 libvirtd 崩溃):

$ virsh --connect vbox:///system

网络配置:

$ virsh -c qemu:///system net-list --all
$ virsh -c qemu:///system net-dumpxml default

Hooks[编辑 | 编辑源代码]

Hooks are scripts that are triggered by different events happening while starting and running the libvirt daemon. They can be used to execute commands needed in preparation to launch a guest like setup networks or reserve memory.

The following hooks exists:

  • daemon - occasions to trigger: start, shutdown, reload
  • qemu - occasions to trigger: prepare, prepare, start, started, stopped, release, migrate, restore, reconnect, attach
  • lxc - occasions to trigger: prepare, start, started, stopped, release, reconnect
  • libxl - occasions to trigger: prepare, start, started, stopped, release migrate, reconnect
  • network - occasions to trigger: start, started, stopped, port-created, updated, port-deleted

See the libvirt Documentation for details about each hook and trigger.

Create a hook[编辑 | 编辑源代码]

Hooks are represented by scripts located at /etc/libvirt/hooks. If the folder does not exist, you have to create it. Each hook is represented by a script in this folder with the same name (e.g. /etc/libvirt/hooks/qemu) or a subfolder (e.g. /etc/libvirt/hooks/qemu.d/). The later can contain different scripts, which are all run at the trigger points. The scripts are run like any other scripts, so they need to start whith the declaration of the command interpreter to use (e.g. #!/bin/bash). The script have to be executable by the libvirt user (chown +x /etc/libvirt/hooks/qemu).

Everytime a trigger point is met, the script is run. For example, the daemon script would run at least two times in a start/stop cycle of the system, at start and at shutdown. To run an command only at a given point, you have to implement conditions in the script. To do this, libvirt passes parameters which can be used to identify the current trigger condition.

According to the libvirt documentation these parameters are defined as follows:

  • Parameter 1: The name of the object involved in the operation
  • Parameter 2: The name of the operation being performed
  • Parameter 3: Used if a sub-operation is to be named
  • Parameter 4: An extra argument if needed

If one of the arguments is not applicable, a dash is passed.

注意: If the hooks are not working after creating your script, try restarting the libvirt daemon.

示例[编辑 | 编辑源代码]

To run an command everytime you start an qemu guest, before any ressources are allocated, you can use the qemu hook. At this point, libvirt runs the hooks like this: /etc/libvirt/hooks/qemu <guest_name> prepare begin - The script for this could like this:

/etc/libvirt/hooks/qemu
#!/bin/bash
guest_name="$1"
libvirt_task="$2"
if [ "$libvirt_task" = "prepare" ]; then
	<run some important code here>
fi

If the guest is stopped, the same script would be run, but this time the daemon would start the command like this: /etc/libvirt/hooks/qemu <guest_name> stopped end -

宿主机与虚拟机间共享数据[编辑 | 编辑源代码]

Virtio-FS[编辑 | 编辑源代码]

注意: Virtio-FS is not supported in QEMU/KVM user sessions.

The description here will use hugepages to enable the usage of shared folders. Sharing files with Virtio-FS lists an overview of the supported options to enable filesharing with the guest.

First you need to enable hugepages which are used by the virtual machine:

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

To determine the number of hugepages needed check the size of the hugepages:

$ grep Hugepagesize /proc/meminfo

The number of hugepages is memory size of virtual machine / Hugepagesize. Add to this value some additional pages. You have to reboot after this step, so that the hugepages are allocated.

Now you have to prepare the configuration of the virtual machine:

# 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>

It is necessary to add the NUMA definition so that the memory access can be declared as shared. id and cpus values for NUMA will be inserted by virsh.

It should now be possible to mount the folder in the shared machine:

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

Add the following fstab entry to mount the folder automatically at boot:

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

9p[编辑 | 编辑源代码]

File system directories can be shared using the 9P protocol. Details are available in QEMU's documentation of 9psetup.

Configure the virtual machine as follows:

<domain>
...
  <devices>
    ...
    <filesystem type="mount" accessmode="mapped">
      
<target dir="mount_tag"/> </filesystem> </devices> </domain>

Boot the guest and mount the shared directory from it using:

# mount -t 9p -o trans=virtio,version=9p2000.L mount_tag /path/to/mount_point/on/guest

See https://docs.kernel.org/filesystems/9p.html for more mount options.

To mount it at boot, add it to the guest's fstab:

/etc/fstab
...
mount_tag	/path/to/mount_point/on/guest	9p	trans=virtio,version=9p2000.L	0 0

The module for the 9p transport (i.e. 9pnet_virtio for trans=virtio) will not be automatically loaded, so mounting the file system from /etc/fstab will fail and you will encounter an error like 9pnet: Could not find request transport: virtio. The solution is to preload the module during boot:

/etc/modules-load.d/9pnet_virtio.conf
9pnet_virtio

Samba / SMB[编辑 | 编辑源代码]

An other easy way to share data between guest and host is to use the smb protocol. While performance and latency may not be as good as in the other described ways, its sufficient for simple tasks like transfering simple files like images or documents from and to the guest.

The smb server can be set up directly on either the host, or the guest, for example using Samba, eliminating the need for a dedicated file server. Windows guests have the ability to create smb shares included right after installation (Microsoft Supportpage).

One possible way to access the share under linux (either from the host, or from the guest, depending, where you have installed your server) is to create an entry in your fstab. The samba package is required.

/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 ensures that the share is only mounted when needed without causing issues if the vm is not booted. user,credentials=/home/user/.config/my_vm.key,gid=1000,uid=984 gives you the ability to mount the share on the fly while first accessing it, without needing a password.

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(无预置证书)。
  1. 点击应用
  • 点击开始安装

参考 Fedora:Using UEFI with QEMU 获得更多信息。

小技巧[编辑 | 编辑源代码]

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 原生硬盘[编辑 | 编辑源代码]

To turn a disk into an Advanced Format 4Kn disk, both its physical and logical sector size needs to be set to 4 KiB. For virtio-blk and virtio-scsi this can be done by setting the logical_block_size and physical_block_size options with the <blockio> element. For example:

# 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 is capable of passing on QEMU command line arguments to the underlying QEMU instance running the VM. This functionality is highly useful when libvirt does not provide QEMU features (yet). For examples, see the entire Intel GVT-g article.

modify VM XML schema for QEMU[编辑 | 编辑源代码]

This serves to enable QEMU-specific elements. Change

$ virsh edit vmname
<domain type='kvm'>

to

$ virsh edit vmname
<domain xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0' type='kvm'>

QEMU 命令行参数[编辑 | 编辑源代码]

In libvirt, QEMU command line arguments separated by whitespaces need to be provided separately.

The correct location to insert them is at the end of the <domain> element, i. e. right above the closing </domain> tag.

-display gtk,gl=es,zoom-to-fit=off

Becomes

$ 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 守护进程通常在你的普通用户下运行,并且只接受来自相同用户的连接。然而 libvirt 默认使用 root 运行 QEMU。为了让 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,如有必要可修改。

You can omit the latency settings (in microseconds) but using the defaults might result in crackling.

Hypervisor CPU use[编辑 | 编辑源代码]

Default VM configuration generated by virt-manager may cause rather high (10-20%) CPU use caused by the QEMU process. If you plan to run the VM in headless mode, consider removing some of the unnecessary devices.

Virtual machine cannot be un-paused on virt-manager[编辑 | 编辑源代码]

If you are using a disk image format such as qcow2 which has a specified virtual capacity, but only stores what is needed, then you need to have space on the host partition for the image to grow. If you see I/O related errors when attempting to start the VM, it's possible that the host partition holding the virtual disk image is full. You can run df -h on the host to verify how much free space is available.

If this is the case, see System maintenance#Clean the filesystem for ways to free up space.

Redirect USB Device is greyed out in virt-manager[编辑 | 编辑源代码]

If the Redirect USB Device menu item is greyed out, check that the following hardware is configured for the VM:

  • A USB Controller.
  • One or more USB Redirectors.

Error starting domain: Requested operation is not valid[编辑 | 编辑源代码]

When you try to open a virtual machine this error may pop up. This is because when you try to open a existing virtual machine libvirt tries to search for the default network which is not available. To make it available you have to autostart your network interface so that whenever your restart your computer your network interface is always active. See libvirt networking page.

Look at the name of your network interface with the following command:

# virsh net-list --all

To autostart your network interface:

# virsh net-autostart name_of_the_network

To start your network interface:

# virsh net-start name_of_the_network

Virt Manager Error 'Virt Manager doesn't have search permissions'[编辑 | 编辑源代码]

Ensure the folder containing your virtual machine files and installation ISO are owned by the libvirt-qemu group

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

参阅[编辑 | 编辑源代码]