在云计算领域我们经常能听到虚拟化(Virtualization)技术
,到底什么是虚拟化技术呢?关于虚拟化的定义,我们能看到这样的术语:
虚拟化是一个广义的术语,在计算机方面通常是指计算元件在虚拟的基础上而不是真实的基础上运行。虚拟化技术可以扩大硬件的容量,简化软件的重新配置过程。CPU的虚拟化技术可以单CPU模拟多CPU 并行,允许一个平台同时运行多个操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。
虚拟化技术一般来说包括:
CPU虚拟化
内存虚拟化
服务器虚拟化
存储虚拟化
网络虚拟化
应用虚拟化
虚拟化技术的目的是通过隐藏特定计算平台的物理特性,为用户提供抽象的、统一的、模拟的计算环境,通常是虚拟机。虚拟机可以通过是否在裸机上部署分为面向主机的虚拟机和面向裸机的虚拟机。面向主机的虚拟机是指在一台已经安装操作系统的主机上安装虚拟机管理(VMM)程序,如VMware、Xen;而面向裸机的虚拟机是指在裸机上直接安装虚拟机管理程序,所有的虚拟机调用都是直接由虚拟机管理程序来负责,没有了操作系统这一步,在效率上一般要高于面向主机的虚拟机。
从硬件虚拟化角度来看,虚拟化又可以分为三大类:
Full Virtualization(全虚拟化)
: 几乎是完整的模拟一套真实的硬件设备,大部分操作系统无需进行任何修改即可直接运行在全虚拟化环境中,例如KVM技术。Partial Virtualization(部分虚拟化)
: 仅仅提供了对关键性计算组件或者指令集的模型,操作系统可能需要做某些修改才能够运行在部分虚拟化环境中。Paravirtualization(半虚拟化)
: 不对硬件设备进行模拟,虚拟机拥有独立的运行环境,通过虚拟机管理程序共享底层的硬件资源。大部分操作系统需要进行修改才能运行在半虚拟化环境中。半虚拟化的性能要稍微高于全虚拟化,像Xen。并且,我们把最原始的宿主机(一般是物理机)称作host
,在host上用虚拟化技术创建出来的虚拟机称作guest
。基于这些背景,本文对kubevirt底层用到的三个虚拟化技术相关点qemu
、kvm
、libvirt
做简单说明和实践。
Note
下文相关命令都是在一台有足够资源的物理机上操作的,读者如果自己动手参考操作,注意检查自己的机器信息,以及修改相关配置匹配自己实际的资源信息
qemu是一个开源纯软件实现的虚拟化模拟器,它可以实现在一个操作系统上通过模拟硬件资源
运行一个完整的操作系统。qemu可模拟的硬件资源包括disk、network、VGA、PCI、USB、serial/parallel ports、cpu等。项目地址:https://github.com/qemu/qemu,先看看官方的说明:
QEMU is a generic and open source machine & userspace emulator and virtualizer.
QEMU is capable of emulating a complete machine in software without any need for hardware virtualization support. By using dynamic translation, it achieves very good performance. QEMU can also integrate with the Xen and KVM hypervisors to provide emulated hardware while allowing the hypervisor to manage the CPU. With hypervisor support, QEMU can achieve near native performance for CPUs. When QEMU emulates CPUs directly it is capable of running operating systems made for one machine (e.g. an ARMv7 board) on a different machine (e.g. an x86_64 PC board).
QEMU is also capable of providing userspace API virtualization for Linux and BSD kernel interfaces. This allows binaries compiled against one architecture ABI (e.g. the Linux PPC64 ABI) to be run on a host using a different architecture ABI (e.g. the Linux x86_64 ABI). This does not involve any hardware emulation, simply CPU and syscall emulation.
QEMU aims to fit into a variety of use cases. It can be invoked directly by users wishing to have full control over its behaviour and settings. It also aims to facilitate integration into higher level management layers, by providing a stable command line interface and monitor API. It is commonly invoked indirectly via the libvirt library when using open source applications such as oVirt, OpenStack and virt-manager.
qemu官方目前支持的CPU架构(CPU Architecture)和加速器(Accelerators)如下:
CPU Architecture | Accelerators |
---|---|
Arm | kvm (64 bit only), tcg, xen |
MIPS | kvm, tcg |
PPC | kvm, tcg |
RISC-V | tcg |
s390x | kvm, tcg |
SPARC | tcg |
x86 | hax, hvf (64 bit only), kvm, nvmm, tcg, whpx (64 bit only), xen |
qemu可以用yum install qemu
的方式安装,或者采用编译安装的方式安装,源码包和安装步骤可以参考qemu官网https://www.qemu.org/download/,相关步骤不再赘述,全编译时间比较长,可查找资料选择性编译。
安装完会有如下命令(输入qemu按tab键补全),本文仅需要用到qemu-img
和qemu-system-x86_64
两个命令:
# qemu-
qemu-aarch64 qemu-mips qemu-riscv64 qemu-system-microblaze qemu-system-sh4eb
qemu-aarch64_be qemu-mips64 qemu-s390x qemu-system-microblazeel qemu-system-sparc
qemu-alpha qemu-mips64el qemu-sh4 qemu-system-mips qemu-system-sparc64
qemu-arm qemu-mipsel qemu-sh4eb qemu-system-mips64 qemu-system-tricore
qemu-armeb qemu-mipsn32 qemu-sparc qemu-system-mips64el qemu-system-unicore32
qemu-cris qemu-mipsn32el qemu-sparc32plus qemu-system-mipsel qemu-system-x86_64
qemu-edid qemu-nbd qemu-sparc64 qemu-system-moxie qemu-system-xtensa
qemu-ga qemu-nios2 qemu-system-aarch64 qemu-system-nios2 qemu-system-xtensaeb
qemu-hppa qemu-or1k qemu-system-alpha qemu-system-or1k qemu-tilegx
qemu-i386 qemu-ppc qemu-system-arm qemu-system-ppc qemu-x86_64
qemu-img qemu-ppc64 qemu-system-cris qemu-system-ppc64 qemu-xtensa
qemu-io qemu-ppc64abi32 qemu-system-hppa qemu-system-riscv32 qemu-xtensaeb
qemu-m68k qemu-ppc64le qemu-system-i386 qemu-system-riscv64
qemu-microblaze qemu-pr-helper qemu-system-lm32 qemu-system-s390x
qemu-microblazeel qemu-riscv32 qemu-system-m68k qemu-system-sh4
查看版本号:
# qemu-img --version
qemu-img version 4.2.1
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
先查看host信息:
# uname -a
Linux mb-control1 5.4.131-1.el7.elrepo.x86_64 #1 SMP Sun Jul 11 08:52:19 EDT 2021 x86_64 x86_64 x86_64 GNU/Linux
创建虚拟机磁盘
# qemu-img create -f qcow2 archlinux.qcow2 4G
Formatting 'archlinux.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=65536 lazy_refcounts=off
# ls -al
total 204
drwxr-xr-x. 2 root root 4096 Sep 4 17:11 .
drwxr-xr-x. 22 root root 4096 Sep 4 17:02 ..
-rw-r--r--. 1 root root 197120 Sep 4 17:11 archlinux.qcow2
// 查看磁盘信息
# qemu-img info archlinux.qcow2
image: archlinux.qcow2
file format: qcow2
virtual size: 4 GiB (4294967296 bytes)
disk size: 196 KiB
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
创建一个4G大小的磁盘镜像,-f参数是指定镜像的格式,名称为archlinux.qcow2。
准备guest操作系统的iso文件
下载一个操作系统的iso文件,本文以archlinux为例,先去官网(https://archlinux.org/download/)里边找到中国区加速站,下载archlinux.iso文件,并上传到做验证的host机器上:
# ls -al
total 813596
drwxr-xr-x. 2 root root 4096 Sep 4 17:20 .
drwxr-xr-x. 22 root root 4096 Sep 4 17:02 ..
-rw-r--r--. 1 root root 197120 Sep 4 17:11 archlinux.qcow2
-rw-r--r--. 1 root root 832909312 Sep 4 17:17 archlinux-x86_64.iso
创建并访问qemu虚拟机
qemu虚拟机的访问方式可以参考https://blog.csdn.net/RichardYSteven/article/details/54807927,这里选取vnc的访问方式:
qemu-system-x86_64 archlinux.qcow2 \
-cdrom archlinux-x86_64.iso \
-m 4096 \
-vnc :1
解释下上述命令参数含义:
archlinux.qcow2
:指定虚拟机的磁盘-cdrom archlinux-x86_64.iso
:指定虚拟机镜像-m 4096
:指定虚拟机的内存大小为4G-vnc :1
:指定虚拟机vnc端口号,如果不指定vnc参数,默认vnc监听地址为127.0.0.1:5900,这里的“:1”表示监听端口为1+5900,即监听地址为":5901"查看虚拟机
我们先在host上查看虚拟机的信息:
# ps -ef|grep qemu
root 37484 26347 99 22:43 pts/4 00:08:14 qemu-system-x86_64 archlinux.qcow2 -cdrom archlinux-x86_64.iso -m 4096 -vnc :1
# netstat -ntlp|grep 37484
tcp 0 0 0.0.0.0:5901 0.0.0.0:* LISTEN 37484/qemu-system-x
tcp6 0 0 :::5901 :::* LISTEN 37484/qemu-system-x
再通过vnc viewer工具连接到虚拟机(连接地址是{hostIP:5901}):
通过上面guest信息,可以看到虚拟机内网络和操作系统和host的差异,于是qemu guest和host可以看做如下关系:
kvm的全称是Kernel-Based Virtual Machine,对应的是2007年加进linux 2.26.20的内核的kvm.ko模块。kvm必须在具备Intel VT(对应kvm-intel.ko)或AMD-V(对应kvm-amd.ko)功能的x86平台上运行,是一种全虚拟化
的解决方案。
kvm的功能包括:
kvm可以看作是qemu可执行文件的一个分支,两个团队都积极努力将差异降至最低,并且在减少差异方面取得了进展,最终目标是qemu可以在任何地方运行。当前qemu团队更专注于硬件仿真和可移植性,而kvm团队则专注于内核模块以及与其余用户空间代码的接口。
qemu虚拟机是可以独立运行的,但是由于qemu完全是软件模拟硬件,在速度上比真正的硬件要差不少。为了解决速度问题,qemu允许使用kvm作为加速器,以便可以使用物理CPU虚拟化扩展。当qemu独立运行时,qemu模拟cpu、内存和硬件资源;当kvm和qemu协同工作时,kvm负责cpu和内存的访问,而qemu则模拟其它硬件资源。
再补充两个概念:
Type-1 hypervisor
Type-1 is a native or bare metal hypervisor that’s running directly on the host’s hardware
Type-2 hypervisor
:Type-2 is a hosted hypervisor, which means that it runs on a conventional operating system just as other computer programs would
基于上述概念,也可以这么理解qemu和kvm:qemu是在用户空间中运行并执行虚拟硬件仿真的Type-2 hypervisor,而kvm是在内核空间中运行的Type-1 hypevisor。
更详细内容可参考qemu官网架构图:
要使用kvm,需要先检查一下cpu是否支持虚拟化,可用如下命令查看:
# cat /proc/cpuinfo | grep -E "(svm|vmx)"
其中svm表示Secure Virtual Machine,是AMD的虚拟化技术AMD-V;vmx则是intel的虚拟化技术Intel-VT。
再看看kvm内核模块是否已加载:
# lsmod | grep kvm
kvm_intel 282624 0
kvm 663552 1 kvm_intel
irqbypass 16384 1 kvm
最后检查下kvm对外暴露的接口/dev/kvm:
# ls /dev/kvm -al
crw-------. 1 root root 10, 232 Sep 7 22:12 /dev/kvm
如果内核加载了kvm模块,qemu会通过ioctl /dev/kvm与其交互。
libvirt源码在gitlab上:https://gitlab.com/libvirt/libvirt,github上也有代码mirror:https://github.com/libvirt/libvirt。
广义的libvirt应该包含多个语言版本的libvirt sdk
和libvirtd
等内容,本文仅限于libvirtd。libvirtd是一个守护进程,本质上是对不同的hypervisor(如qemu、Xen、LXC等)操作做了封装,并且对外提供了统一的api接口,可以把libvirt看做是一个统一抽象层。
本文访问libvirt的客户端使用的是virsh——一个命令行工具,下文安装libvirt的时候会一起安装好。
通过上述内容,我们能知道virsh、libvirtd、qemu、kvm有如下的关系:
libvirt可以源码编译安装,源码可去libvirt官网下载合适的版本:https://libvirt.org/sources/。也可以使用yum install的方式安装,这也是本文的安装方法:
# yum install libvirt virt-install -y
# systemctl enable libvirtd
# ps -ef|grep libvirt
root 24825 20264 0 22:12 pts/0 00:00:00 grep --color=auto libvirt
# systemctl start libvirtd
# ps -ef|grep libvirt
root 26552 1 0 22:12 ? 00:00:01 /usr/sbin/libvirtd
nobody 27562 1 0 22:12 ? 00:00:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
root 27563 27562 0 22:12 ? 00:00:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
root 72300 20264 0 22:16 pts/0 00:00:00 grep --color=auto libvirt
# virsh --version
4.5.0
libvirtd相关配置文件默路径在/etc/libvirt:
# ls /etc/libvirt/ -al
total 104
drwx------. 5 root root 4096 Sep 7 22:12 .
drwxr-xr-x. 129 root root 12288 Sep 8 00:13 ..
-rw-r--r--. 1 root root 450 Apr 28 2021 libvirt-admin.conf
-rw-r--r--. 1 root root 547 Apr 28 2021 libvirt.conf
-rw-r--r--. 1 root root 16529 Apr 28 2021 libvirtd.conf
-rw-r--r--. 1 root root 1175 Apr 28 2021 lxc.conf
drwx------. 2 root root 4096 Sep 7 22:12 nwfilter
drwx------. 3 root root 4096 Sep 7 22:07 qemu
-rw-r--r--. 1 root root 30306 Apr 28 2021 qemu.conf
-rw-r--r--. 1 root root 2169 Apr 28 2021 qemu-lockd.conf
drwx------. 2 root root 4096 Sep 7 22:12 secrets
-rw-r--r--. 1 root root 3202 Apr 28 2021 virtlockd.conf
-rw-r--r--. 1 root root 3247 Apr 28 2021 virtlogd.conf
我们基于前文的内容创建一个2C4G的虚拟机,这里用到的命令行工具是virt-install,virt-install会连接libvirtd:
# virt-install --name nuczzz \
--connect qemu:///system \
--ram=4096 \
--vcpus=2 \
--disk path=archlinux.qcow2 \
--cdrom=archlinux-x86_64.iso \
--vnc --vnclisten=0.0.0.0 --vncport=5902 \
--network bridge=virbr0,model=virtio \
--noautoconsole
相关参数释义:
-–name:指定虚拟机的名称
–-connect:指定虚拟机连接方式
–-ram:指定内存大小
–-vcpus:指定cpu的逻辑核数
–-disk:指定磁盘路径(即上文创建的虚拟磁盘)
–-cdrom:指定镜像
--vnc:指定vnc相关配置,vnc客户端可用该配置连接虚拟机
–-network:指定虚拟机配置信息
--noautoconsole:启动时不需要console界面
查看虚拟机相关信息:
// 查看虚拟机列表
# virsh list
Id Name State
----------------------------------------------------
4 nuczzz running
// 查看虚拟机对应的qemu进程信息
# ps -ef|grep qemu
root 21402 17013 0 19:13 pts/1 00:00:00 grep --color=auto qemu
root 68536 1 49 19:10 ? 00:01:28 /usr/local/bin/qemu-system-x86_64 -name guest=nuczzz,debug-threads=on -S -object secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-4-nuczzz/master-key.aes -machine pc-i440fx-4.2,accel=kvm,usb=off,dump-guest-core=off -cpu Skylake-Server-IBRS,ss=on,vmx=on,hypervisor=on,tsc_adjust=on,clflushopt=on,umip=on,pku=on,avx512vnni=on,md-clear=on,stibp=on,ssbd=on,xsaves=on,ibpb=on,hle=off,rtm=off -m 4096 -realtime mlock=off -smp 2,sockets=2,cores=1,threads=1 -uuid 1293c4e6-ca78-4657-b140-86c56bfd0d75 -no-user-config -nodefaults -chardev socket,id=charmonitor,fd=25,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=delay -no-hpet -no-reboot -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -boot strict=on -device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x4.0x7 -device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4 -device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x4.0x1 -device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x4.0x2 -drive file=/root/nuczzz/vm/archlinux.qcow2,format=qcow2,if=none,id=drive-ide0-0-0 -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=2 -drive file=/root/nuczzz/vm/archlinux-x86_64.iso,format=raw,if=none,id=drive-ide0-0-1,readonly=on -device ide-cd,bus=ide.0,unit=1,drive=drive-ide0-0-1,id=ide0-0-1,bootindex=1 -netdev tap,fd=28,id=hostnet0,vhost=on,vhostfd=29 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:fa:35:f6,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -vnc 0.0.0.0:2 -device cirrus-vga,id=video0,bus=pci.0,addr=0x2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 -msg timestamp=on
// 查看虚拟机qemu进程监听的端口号(即vnc端口号)
# netstat -ntlp|grep 68536
tcp 0 0 0.0.0.0:5902 0.0.0.0:* LISTEN 68536/qemu-system-x
// 宿主机上查看虚拟机网络信息
# brctl show
bridge name bridge id STP enabled interfaces
virbr0 8000.52540065466f yes virbr0-nic
vnet0
# ip link show vnet0
13245: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UNKNOWN mode DEFAULT group default qlen 1000
link/ether fe:54:00:87:cd:f1 brd ff:ff:ff:ff:ff:ff
查看虚拟机cpu物理核信息:
查看虚拟机cpu逻辑核信息:
查看虚拟机内存信息:
查看虚拟机网络信息:
到这里一台通过libvirt+qemu+kvm虚拟机就创建好了(通过上面ps qemu进程信息中的accel=kvm可以看出使用了kvm加速),我们可以用virsh命令来管理虚拟机,virsh常用的命令如下:
virsh list: 查看虚拟机列表
virsh start vm_name: 启动名称为vm_name的虚拟机
virsh suspend vm_name: 挂起虚拟机
virsh resume vm_name: 恢复被挂起的虚拟机
virsh autostart vm_name: 开机启动虚拟机,以及在虚拟服务libvirt启动时启动虚拟机
virsh auto start --disable vm_name: 关闭开机启动虚拟机
virsh shutdown vm_name: 关闭虚拟机(需要ACPID服务的支持,ACPI是Advanced Configuration and PowerInterface缩写,高级配置和电源管理接口)
virsh reboot vm_name: 重启持久虚拟机
virsh reset vm_name: 强制重启虚拟机
virsh destroy vm_name: 强制关闭虚拟机,这种方式是从virsh list列表中将虚拟机删
除,仍然可以start起来
virsh net-start default: 启动默认的网络
virsh net-autostart default: 自启动默认网络
如果想彻底删除虚拟机,可以使用如下命令:
1、关闭虚拟机:virsh destroy vm_name
2、删除定义:virsh undefine vm_name
本文简单地介绍了一些虚拟化技术的术语,以及kvm、qemu、libvirt和virsh/virt-install简单实践,还有很多虚拟化的内容未提到,例如cpu/内存/IO虚拟化的原理和qemu虚拟机网络、存储的实现等。仅仅希望本文浅显的知识能作为kubevirt原理学习和虚拟化技术学习的基础,也敬请期待后续相关的文章。
微信公众号卡巴斯同步发布,欢迎大家关注。