前文我们对云计算的整体架构进行了介绍,并且了解到云计算的核心是虚拟化技术。这里的虚拟化技术包括计算虚拟化、网络虚拟化和存储虚拟化等技术。以基于Linux操作系统的虚拟化为例,通常在物理机上安装Linux操作系统和虚拟化软件,然后基于虚拟化软件创建虚拟机,并在虚拟机中按照操作系统。简而言之,虚拟化可以认为是通过软件虚拟出CPU、内存和硬盘等硬件,并在其上运行操作系统,具体如下图所示。

目前虚拟化技术的种类很多,主流的如开源的Qemu/KVM、微软的Hyper-V和VMware的vSphere等。其中Qemu/KVM是一种开源的虚拟化技术,很多公有云厂商使用的该技术,比如AWS、阿里和华为等。微软的Hyper-V是一种基于Windows操作系统的虚拟化技术,主要应用微软云当中。vSphere是一种商用闭源的虚拟化技术,主要用在VMware的产品中。
上述虚拟化技术当中,最耳熟能详的就是Qemu/KVM技术了,需要知道的是Qemu和KVM是两个不同的概念。KVM的全称是Kernel-based Virtual Machine,也就是基于内核的虚拟机,它本身只是一个内核模块,实现CPU和内存的虚拟化。Qemu是一个完整的虚拟化软件,可以通过软件实现CPU、内存和IO设备的虚拟化。由于最早Qemu基于软件实现CPU和内存的虚拟化,其性能损失比较严重。但现在Qemu实现了对KVM的融合,CPU和内存的虚拟化借助KVM,而IO设备的虚拟化基于virtio。实际上,对于KVM而言,Qemu更新是一个管理工具,通过Qemu实现虚拟机的创建和销毁等管理功能。
除了基于Qemu实现对KVM虚拟机的管理外,还有很多其它的工具,如libvirt和virt-manager等。其中libvirt是一个命令行和API的管理工具,而virt-manager则是一个图形化的虚拟机管理工具。上述软件之间的关系如下图所示。接下来我们简要介绍一下各个组件的基本功能。

KVM:前文已经简要介绍过这个组件,KVM其实就是Linux内核的一个模块,它可以利用硬件的虚拟化特性实现高效的CPU和内存虚拟化。
Qemu: 最早的Qemu通过软件的方式实现了计算机硬件的虚拟化,由于采用纯软件的虚拟化,其效率要低很多。目前的Qemu实现了对KVM的支持,并通过一个工具集提供了丰富的功能,如qemu-system-x86_64和qemu-img等。
libvirt: 用于管理虚拟化平台的工具集合,libvirt不仅仅可以管理Qemu-KVM虚拟化平台,还可以管理Xen、VMWare ESX和LXC等虚拟化平台。libvirt包含一个守护进程libvirtd和若干命令行工具,以及API。
virt-manager:一个基于libvirt的图形化虚拟机管理界面,类似Oracle的VirtualBox和VMWare的WorkStation。
Virsh CLI: 由于libvirt默认采用API的方式提供虚拟机的管理功能,使用起来不太方便。Virsh命令集提供了一套命令行的工具实现对虚拟机的管理,例如virsh install用于创建虚拟机,virsh list用于查看虚拟机列表等。
virt-view:virt-view是一个展示虚拟机图形化界面的工具,可以通过VNC和SPICE协议建立与虚拟机的连接,并展示虚拟机的图形化界面。
由于Qemu/KVM是开源免费的,我们可以基于Ubuntu系统快速的部署一个支持KVM虚拟化的环境,并创建一个虚拟机。我们只需要执行如下几步就可以安装一个虚拟机。
安装Qemu/KVM软件
我们的测试环境依然基于Ubuntu 22.04,通过apt命令可以安装所有需要的软件,命令具体如下所示。安装完软件之后需要重启一下(sudo reboot)。
sudo apt install -y qemu qemu-kvm libvirt-daemon libvirt-clients bridge-utils virt-manager cloud-image-utils libguestfs-tools |
下载操作系统镜像
当然,我们不是创建一个虚拟机就完事了,还要给这个虚拟机安装一个操作系统。我们可以给虚拟机安装任何操作系统,为了方便学习,我们依然安装一个Ubuntu操作系统,为了区别,虚拟机中版本为18.04。
wget https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img |
设置虚拟机登录密码
我们采用完全命令行的方式安装虚拟机,这里采用配置文件的方式来设置虚拟机的密码和其它登录信息。Qemu支持将一个文件挂载到虚拟机当中,我们通过这种方式来设置初始密码。
cat >user-data.txt < <EOF< span> </EOF<> #cloud-config password: 111111 chpasswd: { expire: False } ssh_pwauth: True EOF |
创建一个镜像文件
将密码文件user-data.txt转换为一个镜像文件user-data.img。
cloud-localds user-data.img user-data.txt |
创建一个启动盘
接下来我们需要创建一个启动盘,我们可以通过qemu的镜像工具qemu-img来创建一个启动镜像,具体命令如下。使用这个命令,我们通过下载的Ubuntu镜像创建了一个qcow2格式的镜像,大小是20G。
qemu-img create -b ubuntu-18.04-server-cloudimg-amd64.img -F qcow2 -f qcow2 ubuntu-vm-disk.qcow2 20G |
创建虚拟机
完成上述资源的创建,我们就具备了创建虚拟机的条件了。基于命令行,我们可以通过virsh-install创建一个虚拟机。如下是一个创建虚拟机的命令行实例,具体含义都比较明确,比如虚拟机名称、内存大小、虚拟CPU数量和使用的镜像等。其中选项graphics用于设置是否基于图形化的方式运行虚拟机,本实例为非图形化方式,也就是命令行方式运行虚拟机。
virt-install --name ubuntu-vm \ --virt-type kvm --memory 1024 --vcpus 1 \ --boot hd,menu=on \ --disk path=ubuntu-vm-disk.qcow2,device=disk \ --disk path=user-data.img,format=raw \ --graphics none \ --os-type Linux --os-variant ubuntu18.04 |
如果没有什么问题就可以在终端看到虚拟机的启动过程,具体如下所示。最终会显示虚拟机登录的提示信息。

如下是到最后显示的登录提示信息及登录后显示的信息。登录是需要输入用户名ubuntu及密码。密码是文件user-data.txt中设置的内容,本文为111111。

至此,一个虚拟机已经成功创建并运行起来了。可以看到通过qemu创建一个虚拟机非常简单。登录进去以后我们可以通过lsblk工具看一下虚拟机中的硬盘,可以看到有vda和vdb两个硬盘,其中vda是系统盘,大小是5GB;vdb大小是336KB,这个是我们前面创建的用于存储密码的硬盘。

大家可能在疑惑,为什么没有虚拟机安装的过程?这是因为前面经过转换的镜像其实已经是一个安装完成的系统盘了。我们可以基于iso格式的镜像创建一个虚拟机,具体命令如下。
# virt-install --name=ubuntu-vm2 \ --vcpus=1 \ --memory=1024 \ --cdrom=/tmp/debian-9.0.0-amd64-netinst.iso \ --disk size=5 \ --os-variant=debian8 |
此时会弹出来一个图形化的安装界面,这个图形界面就是virt-viewer,具体如下所示。可以看出这就是Ubuntu的安装向导。

另外,如果你的Linux操作系统是桌面版的,也就是有GUI界面,那么可以通过其中的virt-manager来创建虚拟机。使用virt-manager的方法就更简单了,跟使用Oracle的VirtualBox类似,如下是其界面。

登录与退出虚拟机
对于命令行的虚拟机,我们可以通过快捷键Ctrl + ]退出。并通过virsh命令重新进入虚拟机,具体命令如下所示。
virsh --connect qemu:///system console ubuntu-vm |
对于图形化的虚拟机,可以通过virt-viewer连接,具体命令如下。
virt-viewer --connect qemu:///system --wait linuxconfig-vm2 |
介绍了这么多虚拟机的知识,其实都是为了后面介绍存储相关的内容做准备。接下来,我们回到正题,虚拟机的存储路径到底是怎样的。
通过前文我们知道虚拟机中的硬盘名称分别是vda和vdb,而不是我们在物理机上看到的sda和sdb等名称。这是因为基于Qemu虚拟机操作系统中硬盘的驱动程序与物理机中驱动程序不同。关于驱动程序方面的内容,后文会详述,本节我们先聚焦在架构层面。
通过前面的安装过程我们也知道,虚拟机中的硬盘vda和vdb在宿主机上实际就是两个文件。如果我们把本节关于虚拟机的图放大,可以得到如下图所示的内容,这里展示了虚拟机块设备与宿主机之间数据传输的更多细节。

虚拟机也称为客户机,其上的操作系统称为客户机操作系统。基于我们前面部署的虚拟机,该虚拟机中块设备vd*是基于虚拟机特有块设备驱动(virio_blk.c)生成的,这个驱动称为前端驱动(front-end driver)。当虚拟机中的应用(APP)通过文件系统向硬盘发送写请求时,硬盘驱动会将数据放入一个环形缓冲区,同时通过PCI配置空间通知Qemu接收数据。在Qemu端也有对应的驱动,称为后端驱动(back-end driver),它接到通知后将环形缓冲区中的数据取出,并进行后续的操作。
Qemu支持多种不同类型的后端驱动,本文中的虚拟机硬盘基于文件实现。实际上,Qemu虚拟机可以支持如Ceph、iSCSI、NFS和GlusterFS等不同类型的后端驱动。这些后端驱动将数据持久化到不同的位置。
以文件驱动为例,文件驱动本质是对操作系统API的封装。当Qemu将数据从环形队列取出后调用文件驱动(file-posix.c)的接口,文件驱动调用POSIX兼容的API将数据传入宿主机的文件系统中,最终持久化到宿主机的硬盘当中。
本节我们首先大家了一个虚拟化平台,并创建了一个虚拟机。最后,我们简要的介绍了一下IO路径发生的变化。接下来我们将深入到客户机的驱动代码和宿主机的相关代码,介绍一下IO是如何被处理的。

计算机数据存储简史,从纸到云的变迁 基于Fuse的最简单的文件系统 代码覆盖率测试,聊聊gcov和lcov SAN存储的概念与基于iSCSI的操作实战 全面了解SSD,SSD关键术语全面解析 分布式虚拟文件系统,数据编排小能手 高性能的基础RAID0,实操与代码实现解析 网络文件系统,年近五十岁,老当益壮 弹性空间之道,逻辑卷管理(LVM)技术 计算机数据存储简史,从纸到云的变迁 基于树莓派和硬盘柜搭建一个几十TB的家用NAS Linux存储软件栈到底有多复杂,存储软件栈全景概览 分布式存储的软件架构与案例解析 数万客户端NFS服务的困境,聊聊自动挂载技术 深入了解一下SSD的相关内容 什么是文件系统,以Linux中的Ext4为例细聊一下 对象存储,从单机到分布式的演进 为什么都说NFS读写性能差,如何进行优化?SPDK块设备抽象层bdev对多种后端模块(驱动)的支持 计算机的存储体系与性能金字塔 Linux是如何将硬盘展示给用户的,从物理设备到通用块层 聊聊ZFS文件系统,一个免费开源的存储引擎 云计算的出现与存储系统形态的改变 分布式数据路由的基石,聊聊一致性哈希算法 如何创建一个比物理空间大的卷 ,聊聊自动精简配置 介绍一款免费开源的企业级存储软件 企业级磁盘阵列软件架构与功能概述 高性能存储的基础,了解一下内存的方方面面 介绍几个学习存储通信协议的利器 从电商系统认识数据与数据的存储





