Ubuntu中安装使用QEMU/KVM/virt-manager运行虚拟机

时间:2024-03-02 16:38:01

本文为原创,原文发布于个人博客网站:Ubuntu中安装使用QEMU/KVM/virt-manager运行虚拟机

有时候我们需要在同一台计算机中使用多种不同操作系统环境,基于已有的同一堆硬件资源来获得不同操作系统各自的便利性。对此,常用的解决方案主要有:

  1. 在物理机器中安装使用双系统
  2. 在宿主系统中安装使用虚拟机

第一种在物理机器中安装使用双系统的方式能充分发挥硬件资源的最佳性能,但在切换使用不同操作系统时需要重新启动计算机后再选择切换进入到其他操作系统,相信不只我一个人觉得这样的体验很烦人。

第二种方式首先在物理机器中安装某个操作系统作为宿主系统,然后再在宿主系统中使用虚拟机相关技术和工具虚拟出新的机器以安装和使用其他操作系统环境,虽然在虚拟机中运行的操作系统在性能上比不上第一种方式,在某些场景下(如玩视频游戏以及进行视频渲染等)可能不给力,但这已经足够满足本人的有限需求,而且更为重要的是不需要重启计算机来切换进入不同操作系统,还要啥自行车。因此,个人选择基于这种方式来解决多操作系统的使用问题。

虚拟机工具

要在宿主系统中安装使用虚拟机,首先我们需要对虚拟机管理工具做好选型。较为流行的且本人较早接触的虚拟机管理工具主要有VMWare Workstation PlayerVirtualBox,它们都提供了丰富的虚拟机运行管理功能和直观便捷的可视化操作界面,但其对系统资源的占用较高,都只支持在x86架构下运行使用,并且都被商业公司所控制(既使VirtualBox是开源的),前者由VMWare公司提供(2023年11月已被Broadcom收购),后者由Oracle公司提供。是否存在比VMWare Workstation Player和VirtualBox功能更强大,资源占用更友好,以及*开源的虚拟机管理工具呢?

QEMU

随着眼界的不断拓展,终于发现了功能更为灵活强大并且不受商业机构控制的开源虚拟机工具QEMU(Quick Emulator),准确地说QEMU是模拟器,其除了能提供虚拟机(virtualizer)功能外,更为强大的是能在已有芯片架构的基础上模拟和运行其它架构的系统和应用,即模拟器(Emulator)功能,比如在AMD64/X86_64机器上模拟运行aarch64/ARM64架构的系统和应用。在这里,我们只关注使用其虚拟机功能,类似VMWare Workstation Player和VirtualBox,QEMU属于Type-2 Hypervisor,提供了基于软件来虚拟化硬件设备资源以创建虚拟机的能力,此外其占用更少的系统资源从而更加高效,而且还支持在非X86架构机器上运行。

KVM

直接使用QEMU已经可以创建出虚拟机以安装使用隔离于宿主系统的独立操作系统,但其性能受到了较大限制,我们还需要结合使用另一种技术和工具即KVM(Kernel-based Virtual Machine)。KVM即基于内核的虚拟机技术,属于Type-1 Hypervisor,能直接基于机器硬件提供虚拟化能力,比如通过优化管理虚拟化CPU与物理CPU间的映射,加速指令在虚拟化CPU的执行。KVM作为内核模块已经被整合到Linux内核中,但需要物理CPU支持硬件虚拟化的扩展能力,如Intel VT,AMD-V等。QEMU支持与KVM结合使用,以利用其虚拟化加速能力优化虚拟机的运行效率。

virt-manager+libvirt

QEMU本身只提供了命令行工具去创建、运行和管理虚拟机,这对我们一般用户尤其是习惯使用图形化界面的用户来说不太友好,幸运的是我们可以借助开源可视化虚拟机管理应用virt-manager来帮助我们通过图形化界面创建、运行和管理虚拟机。virt-manager主要被用来连接管理QEMU/KVM虚拟机,但也支持管理XenLXC(Linux容器),并且同时支持管理本地和远程虚拟机。通过它我们可以创建、配置及监控虚拟机,此外其内置了基于VNCSPICE协议的窗口查看器以方便我们通过图形化访问使用虚拟机。

virt-manager本身只是一种面向我们终端用户的操作前端,其真正地与QEMU虚拟机管理程序交互还需要利用libvirt所提供的后台服务。libvirt是一个软件包工具集,提供了一种统一的方式去操作访问多种不同的虚拟化管理程序,包括QEMU、KVM、Xen、LXC、 VMWare ESX以及 VirtualBox等。libvirt提供了一个后台服务libvirtd,该后台服务负责与具体的虚拟机管理程序交互,virt-manager通过与该后台服务进行通信交互来发起对虚拟机的管理操作。我们除了可以使用virt-manager可视化工具之外,还能使用另一个命令行工具virsh与libvirtd交互,不过对于喜欢图形化交互的我们来说,virt-manager无疑是更好的选择。

至此,对所选型的上述虚拟机工具之间的关系进行梳理,可以得到如下所示的交互关系。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/blog-qemu-2024-03-01.drawio.png

下面将基于上述虚拟机工具来实践创建和运行虚拟机。

环境

余下内容将介绍如何在Ubuntu Linux X86_64/AMD64宿主环境中基于QEMU/KVM/virt-manager来创建虚拟机,并在其中安装运行Manjaro Linux操作系统。

这里简单介绍一下个人进行后续操作的主要软硬件环境:

  • CPU: 13th Gen Intel(R) Core(TM) i7-13700KF
  • MotherBoard: ASUS TUF GAMING B760M-PLUS
  • OS: Ubuntu 22.04.4 LTS 6.5.0-15-generic

在进行后续操作前需要确保已经在BIOS中开启了CPU硬件虚拟化功能,进行后续操作前得确保物理CPU支持该功能,针对不同主板及BIOS应参考其具体的操作方式进行开启,比如华硕ASUS主板可以参考这里进行操作。

安装相关工具包

验证环境

首先在宿主操作系统中验证一下物理CPU是否支持并开启了硬件虚拟化功能,可运行以下命令:

$ egrep -c '(vmx|svm)' /proc/cpuinfo

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-10-31%2017-33-38.png

其中,“vmx”是Intel平台下虚拟化术语,而“svm”是AMD平台下的虚拟化术语,若命令运行后输出数字大于0则说明物理CPU支持且已开启虚拟化功能。

然后验证一下宿主系统是否支持KVM,可运行以下命令

$ sudo apt install cpu-checker -y
$ kvm-ok

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-10-31%2017-31-45.png

若上述命令输出类似KVM acceleration can be used 的内容则说明系统支持KVM,否则无法基于KVM进行加速。

安装工具包

可运行以下命令安装所需虚拟机相关工具包:

$ sudo apt install qemu-system qemu-utils virt-manager \
	libvirt-clients libvirt-daemon-system -y

其中:

  • qemu-system: 提供QEMU的全系统虚拟化功能,包括对CPU以及其它设备的虚拟化功能。并且包含了对所支持CPU架构的所有模拟功能包,如qemu-system-x86,qemu-system-arm及qemu-system-mips等。
  • qemu-utils: 提供QEMU相关的一些工具命令,如磁盘管理工具qemu-img等。
  • virt-manager: 提供了可视化管理界面与libvirtd后台服务交互来管理虚拟机。
  • libvirt-clients: 提供了命令行工具与libvirtd后台服务交互来管理虚拟机,建议安装,比如若使用virt-manager管理虚拟机运行失败可利用该命令行工具来帮助找出错误。
  • libvirt-daemon-system: 提供了libvirtd后台服务及相关配置文件等。

安装完成后,验证libvirtd服务是否正常运行

$ systemctl status libvirtd

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-10-31%2017-40-53.png

若未正常运行,需要手动开启,运行命令:

$ sudo systemctl start libvirtd
$ sudo systemctl enable libvirtd
$ systemctl status libvirtd

确认libvirtd 服务已正常运行后,将当前用户加入到相关用户组

$ sudo usermod -aG kvm $USER
$ sudo usermod -aG libvirt $USER
$ sudo usermod -aG libvirt-qemu $USER

这里需要重启宿主系统后重新登录。

启动可视化工具Virtual Machine Manager

$ virt-manager

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-10-31%2017-58-47.png

创建使用虚拟机

  • 点击可视化工具菜单栏的创建虚拟机图标按钮,创建新虚拟机。
  • 安装选项选择Local install media(ISO image or CDROM)
  • 目标系统架构Architecture options可按需选择,这里我选择与自己宿主机器一致的默认架构X86_64,选择其他架构将无法使用KVM加速,性能较差(有模拟其它架构来进行开发和跑测试的能力就已经可以知足了)。
  • 点击Forward按钮继续。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2011-12-19.png

  • 点击Browse 按钮选择系统镜像文件。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-23-15.png

  • 点击Browse Local按钮选择本地镜像文件。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-20-11.png

  • 我选择了manjaro-gnome-23.0.4-minimal-231015-linux65.iso 镜像文件(相应镜像文件需要提前下载到本地)以便在虚拟机中安装使用Manjaro。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-30-01.png

  • 如果没有成功自动识别该镜像对应的操作系统并显示None detected,此时需要取消Automatically detect from the installation media / source 选项,并手动输入manjaro ,在弹出的选择框中选中Manjaro 选项。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-30-36.png

  • 点击Forward按钮继续。
  • 此时,弹出了消息框,提醒我们没有读取该镜像文件的权限,让我们修正该问题,选择Yes 按钮,后续在虚拟机中安装系统时才能成功读取该镜像文件的内容。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-36-10.png

  • 输入配置虚拟机内存大小及虚拟CPU核数,我这里配置了8G内存和4核CPU,确认后点击Forward 按钮继续。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-41-16.png

  • 输入配置虚拟机磁盘大小,点击Forward 按钮继续。这里创建的磁盘所保存的默认路径为/var/lib/libvirt/images ,其格式为qcow2

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-45-40.png

  • 确认虚拟机配置信息,在这里也可更改虚拟机名称Name这里虚拟机的网络设置为默认的NAT模式,点击Finish 按钮完成设置。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-48-26.png

  • 此时,将自动启动运行虚拟机可视化窗口,在该窗口中按照该系统安装流程完成安装即可。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-52-00.png

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2013-14-51.png

若创建虚拟机时,宿主机系统中有运行其它虚拟机管理程序启动的虚拟机实例,如VirtualBox, 可能会出现KVM资源被占用而无法启动虚拟机的错误,如:failed to initialize kvm: Device or resource busy,如下图所示。这时需要关闭相应虚拟机管理程序运行的虚拟机实例后再次进行尝试。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-02%2009-52-17.png

  • 成功创建虚拟机后,可以发现Virtual Machine Manager窗口中多了一个可管理的虚拟机manjaro ,选中该虚拟机右键可弹出管理菜单,以对该虚拟机进行启动、停机、保存、恢复以及重启等操作;双击该虚拟机可进入更详细的配置管理界面。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202023-11-01%2012-55-36.png

共享粘贴板

在虚拟机中安装好操作系统后,宿主机系统和虚拟机系统之间可能还无法共享粘贴板内容。此时我们需要在虚拟机操作系统中安装相应的“增强功能”软件包spice vd_agent,比如我的虚拟机系统为Manjaro/Arch Linux,可运行命令进行安装:

$ sudo pacman -S spice-vdagent

对于其它操作系统需要安装相应版本的spice vd_agent软件包。

分辨率自适应

虚拟机窗口大小被调整后其操作系统分辨率可能无法随之调整,这同样需要spice vd_agent的支持,在虚拟机系统中安装好spice vd_agent后,在virt-manager应用窗口中找到菜单View > Scale Display 选中其中的Auto resize VM with window 选项,虚拟机系统即可随窗口大小自适应调整分辨率。

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/Screenshot%20from%202024-02-28%2000-08-25.png

共享文件夹

虚拟机系统需要能够访问宿主机系统中的特定目录和文件,这里介绍两种解决方法,分别基于virtiofsSamba

virtiofs

libvirt提供了文件系统virtiofs 来帮助虚拟机系统访问宿主机系统的文件夹及文件。我们可以使用virt-manager 来进行设置,在virt-manager 操作界面中:

  • 首先确保虚拟机处于关闭状态;
  • 在虚拟机配置界面选择Memory 并选中Enable shared memory ,点击Apply 按钮保存设置;

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/blog-qemu-share-folder-1-2024-02-28_16-14.png

  • 然后点击Add Hardware 按钮,在弹出窗口中左侧选择文件系统Filesystem ;右侧选择Drivervirtiofs ;填写Source Path ,即宿主机系统欲向虚拟机共享的目录的绝对路径,可直接填写或点击Browse... 按钮进行选择;填写Target Path ,其并非是共享目录在虚拟机系统中的路径,而是文件系统在虚拟机系统中的名称,相当于是一种别名,这里可以填一个自认为合适的名称,我这里填写了share-folder ,后续操作需要使用该名称;点击Finish 按钮完成添加共享文件系统;

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/blog-qemu-share-folder-2-2024-02-28_16-21.png

  • 最后启动虚拟机系统,进入操作系统后运行挂载命令将之前添加的文件系统挂载到虚拟机系统中,成功以后便可以在虚拟机系统中访问宿主机的共享文件夹,如:
// 首先创建一个本地目录用于挂载共享文件系统,如:
$ mkdir ~/share
// 挂载共享文件系统到该目录
$ sudo mount -t virtiosf share-folder ~/share
// 查看是否挂载成功
$ ls ~/share

https://cdn.jsdelivr.net/gh/beaclnd92/imgs/img-repo/blog-qemu-share-folder-3-2024-02-28_17-36.png

Samba

除了上述基于virtiofs 的方式外,还可以基于Samba 协议由宿主系统向虚拟机系统共享目录和文件,这对跨系统及跨网络共享文件的支持更友好。

首先需要在宿主系统中安装和运行Samba 服务,如运行命令:

$ sudo apt install samba

编辑Samba 服务配置文件,默认为/etc/samba/smb.conf ,在文件末尾添加如下配置内容:

# []中的名称为samba服务下的自定义共享名,客户端连接时需要在路径中使用该名称进行连接
[sambashare]
   comment = Samba on Ubuntu
   # 要共享的宿主系统目录的绝对路径,根据具体情况进行配置
   path = /home/share
   read only = no
   browsable = yes

保存修改后的配置文件后,运行命令重启Samba 服务:

$ sudo systemctl restart smbd

设置Samba服务用户密码,其用户名需是系统中已经存在的用户,由于Samba服务默认没有使用系统用户的密码,需要专门进行设置:

// 这里使用当前系统用户
$ sudo smbpasswd -a $USER

之后,便可以利用Samba协议在虚拟机系统访问宿主系统共享的目录和文件,比如在虚拟机系统内通过桌面环境的文件浏览器连接访问服务地址,如输入地址:

smb://192.168.122.1/sambashare

然后根据提示输入Samba服务用户名和密码

其中ip地址192.168.122.1libvirt为虚拟机创建的默认虚拟网络的网关地址,该地址指向了宿主机,更具体地说是libvirt在宿主机系统中所创建的桥接网络接口virbr0 ,虚拟机默认使用该接口以NAT模式分配网段192.168.122.0/24 内的ip地址,可参考其官方文档

除了使用文件浏览器等客户端访问Samba共享目录外,在Linux系统下还可以使用挂载命令mountSamba共享目录挂载到本地,但这需要安装工具cifs-utils ,例如在虚拟机系统中运行以下命令:

// 安装cifs-utils工具
$ sudo pacman -S cifs-utils
// 手动加载cifs内核模块
$ sudo modprobe cifs
// 挂载Samba共享目录
$ sudo mount --mkdir -t cifs //192.168.122.1/sambashare ~/share -o username=Tom,password=Tom,workgroup=workgroup,iocharset=utf8,uid=$USER,gid=$USER

上述挂载命令mount中使用的参数usernamepassword的值需要对应改为正确的之前在宿主系统设置的Samba服务用户名和密码。

端口转发

我们有时候会在虚拟机系统中运行某些网络服务,并希望宿主系统以及宿主机器所在局域网内的其他机器能够访问到虚拟机系统中的这些服务。

libvirt 在宿主机系统中默认会创建一个虚拟网络default以及作为其网关的虚拟桥接网络接口virbr0 ,而每个虚拟机默认会以NAT模式连接该接口并被分配一个该虚拟网络中的ip地址。在虚拟机系统内可以根据宿主机ip地址访问宿主机系统,而在宿主系统中也可以根据某个虚拟机系统被分配到的ip地址访问该虚拟机系统。因此若只是希望能从宿主机器中访问虚拟机系统内的网络服务,可以直接基于虚拟机ip地址和具体服务端口号进行访问,但如果是从宿主机器所在局域网的其他机器*问虚拟机系统内的服务,在默认NAT模式下则需要在宿主机器上进行端口转发,即在宿主机系统中使用一个端口作为代理来访问虚拟机系统中的服务端口。当然也可以修改虚拟机网络配置,将默认的NAT 模式改为Bridged 模式使得虚拟机系统可以直接连接到宿主机所在局域网,相应操作也可以参考其官方文档。但个人不太喜欢这样的设置,因此这里只讨论默认NAT 模式下的解决方法。

针对宿主机系统到虚拟机系统的端口转发,VirtualBox等虚拟机管理工具提供了很便捷易用的操作界面,但不幸的是virt-manager以及libvirt 却没有这样的功能,只能靠我们来自行设置,比如基于iptablesnftables 等工具在宿主机系统中配置端口转发的网络规则,可参考其官方文档。个人在进行尝试后发现这样的设置非常麻烦,因此放弃了这种方式,在探索后发现了另一种更方便的解决方案,即隧道协议Tunneling,通过在宿主机器和虚拟机之间建立通信隧道来实现端口转发。

下面介绍两种隧道端口转发的实现方式,分别基于工具ncatSSH

ncat

该方式较简单,首先在宿主机系统安装ncat工具,运行命令:

$ sudo apt install ncat

成功安装后,运行命令与虚拟机系统建立端口隧道:

$ ncat -k -l -p 3001 -c "ncat 192.168.122.226 3000"

上述命令将在宿主机系统监听端口3001 并且将请求连接转发到ip地址为192.168.122.226 的虚拟机系统的3000 端口(虚拟机系统内该端口需要有服务在监听)。

SSH

下面介绍基于SSH隧道的方式。

首先确保宿主机系统中安装了ssh客户端和服务端,比如在宿主机系统中运行命令:

$ sudo apt install openssh-client openssh-server
$ sudo systemctl start sshd
$ sudo systemctl enable sshd

接着在宿主机系统运行命令:

$ ssh -g -L 3001:192.168.122.226:3000 -N $USER@localhost

然后根据提示输入当前系统用户的登录密码。

成功运行后上述命令将在宿主机本地监听端口3001 并可接收来自局域网中其它机器的连接请求,这些请求会被转发到ip地址为192.168.122.226 的虚拟机系统的3000 端口。注意上述命令中的参数-N $USER@localhost 表示以宿主机本身为跳板服务器连接ip地址为192.168.122.226 的虚拟机,并且使用宿主机当前用户的身份。

总结

本文介绍了如何基于QEMU、KVM、virt-manager等开源工具在Ubuntu中安装和运行虚拟机。首先概述了使用多操作系统的需求和主要解决方案,包括安装使用双系统和虚拟机。然后简要介绍了使用虚拟机方案所选型工具的技术背景。接着详细地讲解了如何在Ubuntu Linux X86_64/AMD64宿主环境中基于QEMU/KVM/virt-manager来创建虚拟机,并在其中安装运行Manjaro Linux操作系统。主要包括了如何安装相关工具包并创建使用虚拟机,此外还介绍了如何为虚拟机解决共享粘贴板、自适应分辨率、共享文件夹和端口转发的问题。

希望以上分享内容能对有相关需求和问题的朋友有所帮助。

参考链接

  1. https://en.wikipedia.org/wiki/QEMU
  2. https://en.wikipedia.org/wiki/Hypervisor
  3. https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine
  4. https://afrozahmad.com/blog/qemu-vs-kvm/
  5. https://virt-manager.org/
  6. https://wiki.archlinux.org/title/libvirt
  7. https://christitus.com/vm-setup-in-linux/
  8. https://www.tecmint.com/install-qemu-kvm-ubuntu-create-virtual-machines/
  9. https://ubuntu.com/blog/kvm-hyphervisor
  10. https://www.reddit.com/r/archlinux/comments/payy5u/arch_guest_resolution_not_auto_resizing/
  11. https://wiki.archlinux.org/title/QEMU
  12. https://ubuntu.com/tutorials/install-and-configure-samba#2-installing-samba
  13. https://wiki.archlinux.org/title/samba
  14. https://www.baeldung.com/linux/create-tunnel-local-ports
  15. https://www.ssh.com/academy/ssh/tunneling-example

©️ 版权声明:本文为作者beaclnd的原创文章,遵循版权协议署名-非商业性使用-禁止演绎 4.0 (CC BY-NC-ND 4.0) ,若转载请附上原文出处链接和本声明。