虚拟化是指对资源的逻辑抽象、隔离、再分配、管理的一个过程,通常对虚拟化的理解有广义狭义之分。
广义包括平台虚拟化、应用程序虚拟化、存储虚拟化、网络虚拟化、设备虚拟化等等。狭义的虚拟化专门指计算机上模拟运行多个操作系统平台。
虚拟化的目的是通过对硬件资源的抽象和管理,实现资源的高效利用、灵活性、隔离和安全性,从而提供更高效、可靠和可扩展的计算环境。
维基百科云计算定义:云计算是一种通过因特网以服务的方式提供动态可伸缩的虚拟化的资源的计算模式。
云计算是建立在虚拟化技术的基础上,通过互联网提供按需的计算资源和服务。云计算提供了虚拟化技术的更高层次的抽象和服务,如虚拟机实例、容器服务、函数计算等。它提供了多租户环境、自动化管理和弹性扩展等特性,使用户可以根据实际需求快速获取和释放计算资源。
虚拟化技术为云计算提供了基础的资源池和资源管理能力,使云计算可以实现资源的共享和动态分配。而云计算为虚拟化技术提供了更广阔的应用场景和服务,使其得以更好地应用于实际业务和服务交付。
KVM全称是Kernel-based Virtual Machine,即基于内核的虚拟机,是采用硬件辅助虚拟化技术的全虚拟化解决方案。
对于I/O设备(如硬盘、网卡等),KVM即支持QEMU仿真的全虚,也支持virtio方式的半虚。KVM从诞生开始就定位于基于硬件虚拟化支持的全虚实现,由于其在Linux内核2.6版本后被集成,通过内核加载模式使得Linux内核变成一个事实上的Hypervisor(虚拟机管理器,也叫VMM),但是硬件管理还是由Linux Kernel来完成。
Hypervisor和VMM:
可以把hypervisor和VMM(virtual machine monitor)理解为同一样东西,它们都是用于监控和控制虚拟机操作系统。在创建虚拟机的过程中,会虚拟出一整套的硬件资源,例如硬盘、内存、CPU、网络设备等,这些工作都是由hypervisor负责,除此之外,它还负责虚拟系统运行过程的资源分配和虚拟机的生命周期管理等。
一个KVM客户机就对应一个Linux进程,每个vCPU对应这个进程下的一个线程,还有单独处理I/O的线程,属于同一个进程组。所以,宿主机上Linux Kernel可以像调度普通Linux进程一样调度KVM虚拟机,这种机制使得Linux Kernel的进程优化和调度功能优化等策略,都能用于KVM虚拟机。
比如:通过进程权限限定功能可以限制KVM客户机的权限和优先级等。
由于KVM嵌入Linux内核中,除了硬件辅助虚拟化(如VT-d)的硬件设备能被虚拟机看见外,其他的I/O设备都是QEMU模拟出来的,所以QEMU是KVM天生的好基友。
可以说KVM就是在硬件辅助虚拟化技术之上构建起来的VMM。但并非要求所有硬件虚拟化技术都支持才能运行KVM虚拟化,KVM对硬件最低的依赖是CPU的硬件虚拟化支持(比如:Intel的VT-x技术和AMD的AMD-V技术),而其他的内存和I/O的硬件虚拟化支持,会让整个KVM虚拟化下的性能得到更多的提升。
所以在虚拟机部署KVM功能时,首先就是要查看宿主机Host(也就是主机上的虚拟机,这里是在VMware Workstations的虚拟机打开CPU虚拟化功能。)
然后在Linux系统中可以通过如下命令确定支持VT-x功能:
如果什么输出都没有,那说明你的系统并没有支持虚拟化的处理,不能使用KVM。
"vmx" 是Intel CPU的虚拟化技术标识,"svm"是AMD CPU的虚拟化技术标识。
安装KVM及相关的工具:
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
- qemu-kvm:KVM虚拟化的基本包
- libvirt-daemon-system:libvirt守护程序,提供API和管理虚拟化功能
- libvirt-clients:包含用于与libvirt守护程序通信的客户端实用程序
- bridge-utils:用于创建和管理网络桥接的工具集
- virt-manager:用于管理虚拟机的图形化工具
确认libvirtd服务已启动并运行:
sudo systemctl start libvirtdsudo systemctl status libvirtd#确保在系统启动时自动启动sudo systemctl enable libvirtd
通过virt-manger(图形化工具)来创建或者管理虚拟机:
或者通过virsh(命令行工具)来创建或者管理虚拟机:
下面是一些常用的virsh命令:
virsh list:列出当前运行的虚拟机
virsh start
virsh shutdown
virsh reboot
virsh create
virsh destroy
virsh undefine
virsh console
virsh dominfo
virsh domstate
接下来分析一下kvm的Makefile:
可以看出kvm的Makefile主要生成三个模块:kvm.o和kvm-intel.o、kvm-amd.o。
kvm.o是kvm的核心模块,kvm基本只实现硬件辅助虚拟化相关部分,而不支持的用Qemu来模拟实现。
kvm-intel.o是intel平台架构虚拟化模块,平台相关;
kvm-amd.o是amd架构虚拟化模块,平台相关;
KVM是在硬件虚拟化支持下的全虚拟化技术,所以它能在相应硬件上运行几乎所有的操作系统,KVM虚拟化的核心主要由以下两个模块组成:
1)KVM内核模块,它属于标准Linux内核的一部分,是一个专门提供虚拟化功能的模块,主要负责CPU和内存的虚拟化,包括:客户机的创建、虚拟内存的分配、CPU执行模式的切换、vCPU寄存器的访问、vCPU的执行。
2)QEMU用户态工具,它是一个普通的Linux进程,为客户机提供设备模拟的功能,包括模拟BIOS、PCI/PCIE总线、磁盘、网卡、显卡、声卡、键盘、鼠标等。同时它通过ioctl系统调用与内核态的KVM模块进行交互。
如上图中,在KVM虚拟化架构下,每个客户机就是一个QEMU进程,在一个宿主机上有多少个虚拟机就会有多少个QEMU进程。客户机中的每一个虚拟CPU对应QEMU进程中的一个执行线程,一个宿主机Host中只有一个KVM内核模块,所有虚拟机都与这个内核模块进行交互。
KVM内核模块:
VM内核模块是KVM虚拟化的核心模块,它在内核中由两部分组成:一个是处理器架构无关的部分,用lsmod命令中可以看到,叫作kvm模块;另一个是处理器架构相关的部分,在Intel平台上就是kvm_intel这个内核模块。
如下图所示,KVM的主要功能是初始化CPU硬件,打开虚拟化模式,然后将虚拟机运行在虚拟环境下,并对虚拟机的运行提供一定的支持。
以Intel CPU架构服务器为例,KVM打开并初始化硬件以支持虚拟机运行的过程如下:
Step1:在被内核加载的时候,KVM模块会先初始化内部的数据结构。
Step2:做好准备之后,KVM模块检测系统当前的CPU,然后打开CPU控制寄存器CR4中的虚拟化模式开关,并通过执行VMXON指令将宿主操作系统(包括KVM模块本身)置于CPU虚拟化模式中的根模式root operation,详细参见本站计算虚拟化之CPU虚拟化一文。
Step3:KVM模块创建特殊设备文件/dev/kvm并等待来自用户空间的命令。
Step4:后续虚拟机的创建和运行,其本质上就是是一个用户空间的QEMU和内核空间的KVM模块相互配合的过程。
这里面的/dev/kvm这个设备比较关键,它可以被当作一个标准的字符设备,用来缓存用户空间与内核空间切换的上下文,也就是ioctl调用上下文,是KVM模块与用户空间QEMU的通信接口。
QEMU用户态设备模拟
QEMU原本就是一个著名的开源虚拟机软件项目,既是一个功能完整的虚拟机监控器,也在QEMU-KVM的软件栈中承担设备模拟的工作。
QEMU最初实现的虚拟机是一个纯软件的实现,也就是我们常说的通过二进制翻译来实现虚拟机的CPU指令模拟,所以性能比较低。
但是,其优点是跨平台,甚至可以支持客户机与宿主机并不是同一个架构,比如在x86平台上运行ARM客户机。同时,QEMU能与主流的Hypervisor完美契合,包括:Xen、KVM、Hyper-v,以及VMware各种Hypervisor等,为上述这些Hypervisor提供虚拟化I/O设备。
而QEMU与KVM密不可分的原因,就是我们常说的QEMU-KVM软件协议栈。虚拟机运行期间,QEMU会通过KVM内核模块提供的系统调用ioctl进入内核,由KVM内核模块负责将虚拟机置于处理器的特殊模式下运行。
一旦遇到虚拟机进行I/O操作时,KVM内核模块会从上次的系统调用ioctl的出口处返回QEMU,由QEMU来负责解析和模拟这些设备。除此之外,虚拟机的配置和创建,虚拟机运行依赖的虚拟设备,虚拟机运行时的用户操作环境和交互,以及一些针对虚拟机的特殊技术,比如动态迁移,都是由QEMU自己实现的。
总之,KVM本身不执行任何模拟,需要用户空间应用程序QEMU通过 /dev/kvm 接口设置一个客户机虚拟服务器的地址空间,向它提供模拟的I/O,KVM模块实现处理器的虚拟化和内存虚拟化。在硬件虚拟化技术的支持下,内核的 KVM模块与QEMU的设备模拟协同工作,构成一套和物理计算机系统完全一致的虚拟化计算机软硬件系统。
bcc程序中提供了一个例子用来监控kvm相关事件。
源码:
kvm_hypercall.py
https://github.com/iovisor/bcc/blob/master/examples/tracing/kvm_hypercall.py
运行结果如下:
这个程序使用了kvm相关的以下几个tracepoint静态跟踪点:
kvm_entry:当虚拟机的vCPU(虚拟中央处理单元)从主机CPU切换到虚拟机CPU并开始执行虚拟指令时,触发kvm_entry跟踪点,vcpu_id用于标识特定的虚拟CPU。
kvm_exit:当虚拟机的vCPU执行完一段虚拟指令并从虚拟机CPU切换回主机CPU时,触发kvm_exit跟踪点,exit_reason表示虚拟cpu推出到主机cpu的具体原因。
kvm_hypercall:用于跟踪虚拟机中的超级调用(hypercall)。当虚拟机的Guest OS需要执行一些更高权限的操作(如:页表的更新、对物理资源的访问等)时,由于自身在非特权域无法完成这些操作,于是便通过超级调用交给Hypervisor来完成这些操作,其中nr代表超级调用号。
kvm_exit中的exit_reason:上图中的12,18,32分别代表访问任务优先级寄存器(TP),操作系统特定事件,处理器处于AP复位保持状态。
hypercall_nr(超级调用号):5号超级调用表示请求Hypervisor程序将处于休眠状态的 vCPU 唤醒。
来源:Linux内核之旅
作者:南帅波