虚拟化技术入门科普

云计算已经成为了服务器端的潮流,通过它,我们可以有效支持弹性计算、隔离兼容等一系列的需求,计算力可以像水电一样为人们所使用,而虚拟化技术正是云计算中最重要的技术。

虚拟化技术一般可以被分为两类,分别是虚拟机(VM,Virtual Machine)技术以及容器(Container)技术。

虚拟机

虚拟机是指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。物理机与虚拟机之间通过虚拟机管理程序(VMM,Virtual Machine Monitor,又称Hypervisor)与虚拟机操作系统进行分割,虚拟机管理程序对底层硬件环境与指令提供了模拟或调度,使得虚拟机中的操作系统以为自身运行在物理机上,从而可以在一个物理机(宿主机)上安装多个虚拟机系统,而且每个虚拟机可以运行与原物理机完全不同的操作系统,进而提供了良好的安全隔离与异构支持。主流的虚拟化支撑软件包括Xen、Linux内核的KVM、微软的Hyper-V与私有的VMWare等。

虚拟机技术栈一般是这样的:

+--------------------+
|     Application    | /应用程序
+--------------------+
|       Guest OS     | /虚拟机操作系统
+--------------------+
|    VMM/Hypervisor  | /虚拟机管理程序
+--------------------+
|       Host OS      | /宿主机操作系统
+--------------------+
|       Hardware     | /物理机硬件平台
+--------------------+

虚拟机技术一般可以分为全虚拟化(Full Virtualization)、半虚拟化(Para Virtualization)以及硬件辅助的虚拟机。我们知道,在Intel处理器中划分了四个特权级别ring 0 ~ ring 3,其中ring 0是最高级别,ring 3是最低级别,一般操作系统内核运行在ring 0上,这样就能运行处理器的所有指令,但是应用程序则运行在ring 3上,有部分指令(特权指令)是运行不了的。要解决虚拟机运行的问题,关键就是要让虚拟机操作系统以为自己仍然运行在物理机上,其内核仍然能运行在ring 0上。

全虚拟化

全虚拟化的典型代表是早期的VMWare,虚拟化管理程序在运行的时候对捕获虚拟机操作系统的特权指令,并进行二进制翻译,使得虚拟机操作系统以为自己运行在物理机上。这种方法的好处是不用修改虚拟机操作系统,但坏处就是性能比较差。

半虚拟化

半虚拟化的典型代表是早期的Xen,它在虚拟化管理程序中添加了一些接口函数,然后修改虚拟机操作系统,在特权指令等需要修改的地方修改虚拟机操作系统的代码(打补丁)以便支持虚拟化。这种方法的好处是性能明显更好,但是坏处就是需要给虚拟机操作系统打补丁。

硬件辅助的虚拟化

硬件辅助的虚拟化指的是在处理器中直接加入虚拟化指令支持(比如Intel的VT-x或者AMD的SVM),处理器引入了新的虚拟化模式,例如在Intel处理器上是VMX root模式与VMX non-root模式,两种模式都支持ring 0 ~ ring 3,虚拟机管理程序运行在VMX root模式下,而虚拟机操作系统则运行在VMX non-root模式下。运行在VMX root模式下的虚拟机管理程序通过显式调用VMLAUNCH或VMRESUME指令切换到VMX non-root模式,硬件自动加载虚拟机操作系统的上下文,于是虚拟机操作系统获得运行,这种转换称为VM entry。虚拟机操作系统运行过程中遇到需要虚拟机管理程序处理的事件,例如外部中断或缺页异常,或者主动调用VMCALL指令调用虚拟机管理程序的服务的时候(与系统调用类似),硬件自动挂起虚拟机操作系统,切换到VMX root模式,恢复虚拟机管理程序的运行,这种转换称为VM exit。VMX root模式下软件的行为与在没有VT-x技术的处理器上的行为基本一致;而VMX non-root模式则有很大不同,最主要的区别是此时运行某些指令或遇到某些事件时,会发生VM exit。

由于硬件辅助的虚拟化性能已经很好,而且也不需要修改虚拟机操作系统的代码,因此现在主流的虚拟机软件都是基于硬件辅助的虚拟化技术来开发的。在Linux平台上,就是基于内核的KVM与用户态的虚拟机管理程序qemu的结合。

下面是KVM-qemu的技术栈:

+-----------------+
|   Application   |
+-----------------+  IO   +----------+
|    Guest OS     |---->  |   qemu   |
+-----------------+       +----------+
|      vCPU       |             |
+-----------------+             |
         |                      | 
         ↓                      ↓
+---+-----------------------------+---+
|   |             KVM             |   |
|   +-----------------------------+   |
|             Linux Kernel            |
+-------------------------------------+
|          Physical Hardware          |
+-------------------------------------+

可以看到虚拟机操作系统的虚拟处理器将对应的指令传给内核的KVM模块,KVM模式实际上还需要使用具体架构的KVM模块,例如kvm-intel.ko进行具体的虚拟处理器与虚拟化内存的指令处理。对于设备的访问则是通过虚拟机操作系统通过对应的驱动(例如他virtio)转给了qemu,由qemu通过ioctl系统调用转给KVM内核模块进行处理。

在常见的虚拟机使用场景下不会直接使用qemu虚拟机管理程序对虚拟机进行管理,而是通过封装库libvirt提供的接口函数管理虚拟机。

libvirt封装了多个虚拟机管理程序,除了qemu之外,还有之前提及的Xen、VMWare的esx、BSD虚拟机管理程序bhyve、用户态Linux等。使用libvirt的客户端软件包括virsh、OpenStack、oVirt、virt-manager等等。客户端程序可以通过URI访问对应的虚拟机,其格式为:

  • driver[+transport]://[username@][hostname][:port]/[path][?extraparameters]

例如:

  • qemu+ssh://root@remoteserver.yourdomain.com/system

虚拟机技术一般被用于IaaS模式下。它的优点是安全隔离性好,虚拟机可以与宿主机安装不同的操作系统,因此异构性好。但是它的缺点就是性能和管理性不好,在性能上,它需要启动一个完整的虚拟机操作系统,对于应用程序来说其实很多是不必要的。管理性不好是因为对于虚拟机来说,现在还没有一套较完善的规范与相应的参考实现。

容器

容器技术是通过操作系统提供的隔离技术,将应用程序的运行环境隔离出来,使得应用程序的部署维护更方便,应用程序的运行互不干扰。容器相关技术最早出现在1979年UNIX操作系统上的chroot实现中,在本世纪,Linux操作系统内核中添加了Control Groups与namespace等功能后,形成了以Docker为主的容器技术生态圈,在近几年发展极其迅猛。主流的容器支撑技术包括Docker(现改名为Moby,社区版为Docker-ce)、rkt以及podman等。

在容器技术中,namespace主要提供了容器与宿主机之间的隔离,这些隔离包括文件系统隔离、进程隔离等,而cgroups主要提供了资源的配合管理,例如限定某个容器只能使用多少处理器资源、内存资源等。在Docker启动一个实例之前,会通过Linux的namespace为进程创建隔离的文件系统等命名空间,然后通过cgroups设置进程配额,最后再创建相应的容器实例。

容器技术一般被用在PaaS模式下,对于应用软件的部署非常快捷。它的优点是性能比虚拟机更好,而且管理性也比较好。这是因为在容器领域,已经有了包括OCI、Kubernetes CRI等一系列规范,而且有了runc、runv等一系列参考实现。

新的发展

虚拟机技术可以提供良好的安全隔离以异构操作系统支持,但性能开销大,部署与管理复杂,而容器技术则刚好相反。因此,国外虚拟化社区与公司提出了多种技术,希望能结合高安全与高性能,使得虚拟化技术同时拥有容器的运行性能与标准化支持,以及虚拟机的安全隔离与异构支持。

虚拟机管理程序优化

虚拟机管理程序(VMM)的优化主要方向包括:

  • 优化虚拟机管理程序,现在的qemu支持二进制翻译,也同时支持kvm与xen,还有很多通用设备的模拟,但其实在虚拟机环境下,对二进制翻译、xen以及大部分设备的模拟支持都是没有意义的;
  • 优化启动步骤,正常的物理机启动时需要经过BIOS、启动器(bootloader)、内核实模式(kernel real-mode)与内核保护模式(kernel protected-mode)之后才创建init进程,但是在虚拟机里面,其实可以直接进入保护模式,从而大大提高启动速度;
  • 优化虚拟机操作系统,通用服务器操作系统对于单个应用来说实在太庞大了,可以优化掉很多与应用无关的软件,从而减少虚拟机运行的程序和占用的内存;
  • 使用rust等内存安全、类型安全与并发安全的语言开发虚拟机管理程序,不仅可以更安全,而且因为更安全可以减少不必要的参数动态转换与动态检查的代码,从而提高性能;

英特尔公司于2009年开始基于主流虚拟机管理程序qemu的代码基,开发了专为云平台优化的虚拟机管理程序nemu。nemu仅支持带有虚拟化特性的x86_64与ARM64处理器,并去掉了与云服务无关的特性,因此可以得到更高的性能。现在仍在持续开发中,但是并未有规模实际应用。

英特尔公司于2014年开始,在qemu 2.7的基础上开发了qemu-lite,对qemu的功能进行了大量裁剪,对虚拟机内核的启动参数进行了定制,对虚拟服务器(vCPU)的初始化进行并行化优化处理,成功地将x86_64架构下的虚拟机启动时间从1.3秒优化到了0.4秒,并通过内核设备驱动优化与KSM技术降低了虚拟机的内存开销。qemu-lite被使用到了英特尔公司的Clear Linux系统上,后续也被Kata Container所用。目前,此软件已不再更新维护。

谷歌公司于2017年开发了crosvm虚拟机管理程序,以支持Chromium OS与Chrome OS上Linux应用程序的运行,它使用rust作为开发语言,可以提供较好的语言安全性,并通过内建安全性提高虚拟机的运行性能。其实从CVE漏洞上就可以看出,qemu主要的安全问题都和溢出攻击相关,而使用rust这种内存安全与并发安全的语言可以从根本上解决溢出的问题。

但是crosvm主要是面向Chrome OS推出的,更面向桌面操作系统,因此不太适合在服务器环境里使用。因此亚马逊的团队参考crosvm实现了一个面向服务器的虚拟机管理程序firecracker,它已经在亚马逊的云上得到了应用,号称内存开销低于5M,启动时间低于200毫秒。

容器宿主机操作系统优化

CoreOS团队(后被红帽公司并购,继而与红帽公司一起被IBM并购)于2013年发布了CoreOS容器操作系统,它基于ChromeOS开发,专门面向容器部署与管理进行开发,精简掉了与其无关的大量软件,使得宿主机操作系统的体积大大减小。而且CoreOS提出的双系统分区轮流切换升级,同时支持系统回滚的特性也很有用。

红帽公司于2014年发布了红帽原子(Redhat Atomic)项目,它是面向容器,在Fedora与CentOS等红帽操作系统上集成的一整套面向容器的支撑环境,能有效支持容器的全生命周期管理。

RancherOS是Rancher Labs于2015年发布的容器操作系统,它旨在提供一种在生产环境中大规模运行 Docker 的最小最简单的方式。它只包含运行 Docker 必须的软件,其初始版本大的二进制下载包不超过五十兆。在RancherOS中,一切软件都是容器(包括init),因此软件的维护更为简单。

Clear Linux是Intel在2015年推出的面向云的操作系统,它主要的特性是性能优化,包括对软件进行了精细的性能剖析和调整,使用了qemu-lite提供了更轻量化的虚拟机管理程序等。此外,它还基于rpm设计了自己的软件管理器,可以提供更大粒度的基于二进制的包管理方法,对软件升级可以采取二进制补丁的模式进行,从而可以有效提高软件的更新速度,也可以减少系统的维护工作量。

虚拟机与容器操作系统优化

Alpine Linux是一个短小精悍的Linux发行版,它的最小尺寸只有五兆,因此常常被用为容器镜像的基底操作系统。它没有使用glibc作为C运行时库,而是使用了更小的musl,而且在其他应用软件上也用料极简,比如使用了busybox代替bash、coreutils等。但是由于musl与glibc在实现上有一定差异,因此运行大型应用程序时可能会发生运行时错误。

Photon OS是VMWare推出的一个面向容器的开源操作系统,它使用安全编译选项对系统中的软件进行编译,并对软件进行了精简,使得Photon OS攻击面较小,载入速度较快。

unikernel是库操作系统(Library OS)的进一步发展,unikernel将操作系统视为调用库(library),仅仅提供了对硬件资源的访问接口。应用程序被嵌入内核运行,整个操作系统只有一个应用程序,因此可以进行按需裁剪,使得操作系统最小化,并避免了用户态到内核态的切换,提供了更好的性能。此操作系统可以在虚拟机中运行,从而提供了良好的安全隔离。不过,unikernel也有自己的问题,由于需要与内核一起运行,因此相应的库与通用库不能完全兼容,一般都要求重写应用程序,从而无法保证应用软件的兼容性。此外,因为在内核中只有一个应用程序,因此一旦出现问题,也难以使用常见的软件调试方法对应用程序进行调试。目前,国外有多个团队提供了unikernel软件,但是均未得到规模应用。

容器运行时安全增强

谷歌公司则于2018年推出了gVisor软件解决容器安全隔离性差的问题。gVisor是基于golang语言开发的,兼容OCI规范,在用户态运行的一套软件。它实现了一整套系统调用接口,可以截获处理其它应用程序的系统调用,使得其它程序运行在gVisor上,由此可以通过gVisor沙箱为应用程序提供灵活可靠的安全隔离,又因为没有额外的虚机操作系统开销,因此gVisor的性能也比虚拟机更好。gVisor现在仍处于开发早期,在持续完善中。

podman是红帽提出的Docker替代软件,它与Docker最大的区别就是没有了dockerd守护进程,所有的容器实例都是通过前端命令直接创建的,避免了额外的带有root权限的可攻击点。

面向容器的虚拟机技术

由于容器快,但是不安全,但是虚拟机则刚好相反。因此在2015年,中国的hyperhq团队开发了hyper container,即在虚拟机中运行应用程序,其运行时runv兼容容器开放标准(OCI),而且对虚拟机进行了大量的优化,使得其启动时间低于一秒,而且内存开销也大大减少了。这样就同时提供了虚拟机的安全隔离性,以及容器的可管理性与接近容器的性能。在其后,于2018年,OpenStack社区基于Intel的Clear Linux和hyper container开发了Kata Container,它兼容的虚拟机管理程序更多,而且性能更佳,当然也支持OCI、CRI等容器标准。

国产环境

在国产平台上,由于各方面的原因,虚拟化与云计算发展还比较缓慢,特别是虚拟机技术。这主要的原因是虚拟机技术需要打通包括处理器芯片与指令集、资源虚拟化管理、操作系统内核、虚拟机管理与调度等较多的技术环节,但是容器则只需要在内核支持namespace与cgroups即可,技术深度较浅。

龙芯处理器的虚拟化设计可以追溯到十多年前的龙芯2号研制时期,并在其后通过SimOS模拟器的研制、处理器虚拟化、内存虚拟化与IO虚拟化的探索性研究,于3A3000处理器平台上加入了硬件虚拟化的支持,并通过两年多的努力,于2019年实现了KVM在龙芯平台上的产品化。

申威平台上在十年前即研制了参考Xen思路开发的SWVMM虚拟机技术,但是由于其限制较大,与新一代虚拟机技术不兼容,因此在最近两年,申威也展开了基于KVM的虚拟机技术研制,现在已经通过了PoC阶段,开始进入产品化研制过程,可望在一年内得到稳定的虚拟机产品。深度在这方面也一直在积极配合,是最早适配测试申威平台上KVM+libvirt的操作系统。

除了技术的成熟度之外,虚拟机的性能开销在性能较弱的国产平台上也是一个大问题。现在一般是一个虚拟机会占据一个处理器核,而一个处理器核则可以运行多个容器,因此在实际场景中要使用虚拟机,还必须要解决轻量化、高性能的问题。

结语

云计算仍方兴未艾,除了传统的IaaS、PaaS、SaaS、BaaS等使用模式外,又增加了FaaS(serverless)等的使用模式,在技术上则不断推陈出新。要跟上发展的步伐,甚至有所超越创新,仍是路漫漫其修远兮,大家一起努力吧。

参考资料

发表评论

电子邮件地址不会被公开。 必填项已用*标注