虚拟化技术大观|长文慎入
Posted 云技术实践
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了虚拟化技术大观|长文慎入相关的知识,希望对你有一定的参考价值。
https://ring0.me/2014/12/virtualization-overview/
虚拟化技术大家都不陌生,我们大都使用过诸如 VMWare、VirtualBox
的虚拟机软件。一些人认为,虚拟化技术是近几年跟着云计算的潮流才火起来的,十年前只是桌面用户测试其他操作系统的玩具。非也。只要计算机上同时运行着多个任务,就会有任务隔离的需求,虚拟化就是让每个任务看起来独占整个计算机、隔离任务之间影响的技术。早在计算机还是庞然大物的 20 世纪 60 年代,虚拟化技术就开始发展了。
IBM 7044 黑历史:硬件虚拟化
1964 年的 IBM M44/44X 被认为是世界上第一个支持虚拟化的系统。它采用专门的硬件和软件,能够在一台物理机器上虚拟多个当时流行的 IBM 7044 大型机。它使用的虚拟化方法是非常原始的:像分时系统一样,在每个时间片,一个 IBM 7044 大型机独占所有硬件资源来运行。
在那个 “进程” 概念尚未被发明的年代,多任务操作系统和虚拟化技术事实上是难以分开的,因为 “虚拟机” 就是一个任务,而且当时还没有 Intel x86 这种霸主地位的体系结构,各家的大型机各自为政,也谈不上兼容别家的体系结构。这种 “任务级” 或者说 “进程级” 虚拟化,从概念上延续到今天,就是以 LXC 和 OpenVZ 为代表的操作系统级虚拟化。
这种主要依赖定制的硬件来实现虚拟化的技术,史称 “硬件虚拟化”。在这个什么都要 “软件定义” 的时代,大型机已经日薄西山,大部分依赖硬件的虚拟化也进了历史博物馆。今天我们看到的虚拟化技术,大多是软件为主,硬件为辅。下图所示的划分没有严格的界限,而且一种虚拟化解决方案可能同时使用了下图中的多种技术,因此不要在意这些细节啦~
从模拟执行到二进制翻译
前面提到大型机时代各大厂商各有各的体系结构和指令集,为什么没有出现各种指令集之间的翻译软件呢?须知,思科就是靠兼容各家网络设备和协议起家的(这里面还有八卦,创办思科的那对小情侣希望使用计算机网络传递情书,但网络设备五花八门的,于是他们就发明了兼容多种协议的路由器)。
思科第一台路由器
在网络协议之间翻译和在指令集之间翻译,都是机械、冗长、繁琐的事情,能把它做对,考虑到各种边角情况,是需要无比天才和细心的事情。指令集比网络协议麻烦的地方是,指令的边界(哪里是第一条指令,哪里是最后一条指令)未知,可能执行特权操作(如重启),还能把动态生成的数据作为代码来执行(冯·诺依曼体系结构中,数据和代码共享线性内存空间)。因此,在二进制代码运行之前就做好指令集之间的静态翻译,是不可能的。
最简单粗暴的解决方法是 “模拟执行”。开一个大数组当 “虚拟机” 的内存,拿来指令集手册,写一个无数个 case 的 switch 语句,判断当前要执行的是什么指令,按照手册的说法模拟执行。这样做自然是可行的,但效率就不敢恭维了,虚拟机至少比物理机慢一个数量级。所谓的 “动态类型语言”,如 Python、php、Ruby,在编译成中间代码后,大多也是用这种 “模拟执行” 的方法,因此快不起来。著名的 x86 模拟器 Bochs 就是模拟执行的,虽然慢,但兼容性好,而且不容易有安全漏洞。
不能因为指令翻译难做就因噎废食,一个运行 1 亿次的 for 循环,里面如果都是加加减减一类的操作,翻译成机器码直接执行,肯定比模拟执行要快。在二进制翻译前面,要加上 “动态” 两个字,也就是在程序执行的过程中,能翻译的部分翻译成目标架构的机器码直接执行(并缓存起来以便重复利用),不能翻译的部分就陷入到模拟器里,模拟执行特权指令,再对后面的代码进行翻译。如今 Java、.NET、javascript 等使用的 JIT(Just-In-Time)技术也是类似的套路。
有人会问,如果我只是虚拟相同的体系结构,比如在 64 位 x86 系统上虚拟一个 64 位 x86 系统,需要做指令翻译吗?需要的。比如,虚拟机可能读取特权寄存器 GDT、LDT、IDT 和 TR,并不会触发处理器异常(即虚拟机管理器无法捕获到这样的行为),但这些特权寄存器的值又是需要对虚拟机 “伪造” 的。这就需要在虚拟机读取特权寄存器的指令执行之前,把它替换成调用虚拟机管理器的指令。
遗憾的是,在大型机年代,能把动态二进制翻译这件事做好的天才级人物 Fabrice Bellard 才刚刚出生(1972 年)。
Fabrice Bellard
Fabrice Bellard 的 QEMU(Quick EMUlator)是目前最流行的采用动态二进制翻译技术的虚拟化软件。它可以模拟 x86、x86_64、ARM、MIPS、SPARC、 PowerPC 等多种处理器架构,无修改地运行这些架构上的操作系统。当我们享受视听的乐趣,当我们流畅地运行各种架构的虚拟机系统时,不应忘记 ffmpeg 和 qemu 的创造者 Fabrice Bellard 大神。
以我们最熟悉的 Intel x86 架构为例,分为四个特权级 0~3。一般情况下,操作系统内核(特权代码)运行在 ring 0(最高特权级),而用户进程(非特权代码)运行在 ring 3(最低特权级)。(即使你是 root,你的进程也在 ring 3!只有进了内核才是 ring 0,无上的权力意味着巨大的责任,内核编程的限制很多,吐槽一下)
使用了虚拟机之后,虚拟机(Guest OS)运行在 ring 1,主机操作系统(VMM,Virtual Machine Monitor)运行在 ring 0。比如在 Windows 上装个 Linux 虚拟机,Windows 内核运行在 ring 0,而被虚拟的 Linux 内核运行在 ring 1,Linux 系统里的应用程序则运行在 ring 3。
当虚拟机系统需要执行特权指令时,虚拟机管理器(VMM)就会立即捕 获它(谁让 ring 0 比 ring 1的特权级高呢!)并模拟执行这条特权指令,再返回到虚拟机系统。为了提高系统调用、中断处理的性能,有时会利用动态二进制翻译的技术,在运行前把这些特权指令替换成调用虚拟机管理器 API 的指令。如果所有特权指令都模拟得天衣无缝,虚拟机系统就像运行在物理机器上一样,完全不能发现自己运行在虚拟机里。(当然,事实上还是有一些破绽的)
请虚拟机系统和 CPU 来帮忙,动态二进制翻译虽然比模拟执行快了很多,但由于每条特权指令都要到虚拟机管理器里绕一圈(模拟执行),离物理机的性能仍然有不小的差距。要让虚拟机快起来,人们想到两种方法:
让虚拟机操作系统帮忙,所谓 “半虚拟化”(paravirtualization)或 OS-assisted virtualization
让 CPU 帮忙,所谓 “硬件辅助虚拟化”(hardware-assisted virtualization)
这两种方法不是互斥的。现代的很多虚拟化解决方案,如 Xen、VMware,都同时使用了两种方法。
半虚拟化(paravirtualization)
既然动态二进制翻译的难点和性能瓶颈在于模拟执行那些杂七杂八的特权指令,我们能不能修改虚拟机系统的内核,把那些特权指令改得好看些?毕竟在多数情况下,我们并不需要对虚拟机刻意 “隐瞒” 虚拟化层的存在,而是要在虚拟机之间提供必要的隔离,同时又不造成太多性能开销。
Paravirtualization 这个单词的前缀是 para-,即 “with” “alongside” 之意。也就是虚拟机系统与虚拟化层(主机系统)不再是严格的上下级关系,而是互信合作的关系,虚拟化层要在一定程度上信任虚拟机系统。在 x86 架构中,虚拟化层(Virtualization Layer)和虚拟机系统的内核(Guest OS)都运行在 ring 0。
虚拟机系统的内核需要经过特殊修改,把特权指令改成对虚拟化层 API 的调用。在现代操作系统中,由于这些体系结构相关的特权操作都被封装起来了(例如 Linux 内核源码中的 arch/ 目录),比起二进制翻译需要考虑各种边角情况,这种对虚拟机内核源码的修改就简单一些了。
相比使用二进制翻译的全虚拟化(full virtualization),半虚拟化是牺牲了通用性来换取性能,因为任何操作系统都可以无修改地运行在全虚拟化平台上,而每个半虚拟化的操作系统内核都要经过人肉修改。
硬件辅助的虚拟化
同样的功能,专用硬件实现几乎总是比软件实现更快,几乎是一条金科玉律了。在虚拟化这件事上,比尔搞不定的事情,自然也要请安迪来帮忙。(比尔是微软公司创始人,安迪是 Intel 公司创始人)
让硬件帮助软件实现虚拟化的概念也不是新东西了。早在 1974 年,著名论文 Formal requirements for virtualizable third generation architectures 就提出了可虚拟化体系结构的三个基本条件:
虚拟机管理器提供了与真实机器一模一样的虚拟环境;
运行在虚拟机里的程序在最坏情况下也比物理机慢得不多;
虚拟机管理器能够完全控制所有的系统资源。
虚拟机里的程序不能访问未分配给它的资源
在某些情况下,虚拟机管理器能够收回已经分配给虚拟机的资源
早期的 x86 指令集不满足上述条件,因此需要虚拟机管理器做复杂的动态二进制翻译。既然二进制翻译的主要开销在 “捕获” 虚拟机系统的特权指令上,CPU 能做的事就是帮忙把 “捕获” 的事情给做了。Intel 家的解决方案叫做 Virtual Machine Control Structures (VT-x),于 2005 年冬天推出;AMD 也不甘人后,随后推出了类似的 Virtual Machine Control Blocks (AMD-V)。
Intel 在原有的四个特权级基础上,增加了一个专供虚拟机管理器(VMM)使用的 “Root Mode”。这就好像是天不怕地不怕的孙悟空(ring 0)逃不出如来佛(Root Mode)的手掌心。这样,虚拟机系统尽管运行在 ring 0,其执行的特权指令仍然会被 CPU 自动捕获(触发异常),陷入到 Root Mode 的虚拟机管理器里,处理后再使用 VMLAUNCH 或 VMRESUME 指令返回到虚拟机系统。
为了方便半虚拟化(paravirtualization)中用 API 调用替代 CPU 异常捕获,Intel 还提供了从虚拟机(Non-root Mode)到虚拟机管理器(Root Mode)的 “系统调用”:VMCALL 指令。
看起来很美好,不是吗?事实上,对刚刚开始支持硬件辅助虚拟化的 CPU,使用这个方式未必比动态二进制翻译性能高。因为硬件辅助虚拟化模式对每条特权指令,需要切换到 Root Mode,处理完后再返回,这个模式切换就像实模式和保护模式切换一样,需要初始化很多寄存器,还要保存和恢复现场,更不用说对TLB、高速缓存的影响了。不过,Intel 和 AMD 的工程师也不是吃白饭的,在较新的 CPU 里,硬件辅助虚拟化的性能开销已经比动态二进制翻译做得更好了。
最后说点实用的:在大多数 Bios 里,硬件辅助虚拟化都是有开关选项的。只有使能了 Intel Virtualization Technology 这样的选项,虚拟机管理器才能用上硬件加速。因此在使用虚拟机的时候,不要忘了进 BIOS 检查一下。
CPU 虚拟化不是一切前面说了这么多,给大家一种假象:只要虚拟了 CPU 指令就万事大吉了。CPU 固然是计算机的大脑,但计算机的其他组件也不容忽略。这些组件包括与 CPU 朝夕共处的内存和硬盘、显卡、网卡等形形***的外设。
内存虚拟化
当切换到一台虚拟机时,就用这台虚拟机的内存映射关系(页表)作为物理机的页表;
如果虚拟机访问一个页面时它被换出到外部存储了,就会触发缺页异常,虚拟化层要负责把缺页异常分发到该虚拟机的操作系统。
设备虚拟化
除了 CPU 和内存以外的组件,被统称为外设。CPU 与外设之间的通信就是 I/O 了。每台虚拟机需要有硬盘、网络,甚至显卡、鼠标、键盘、光驱等。如果大家使用过虚拟机,应该对这些配置不陌生。
Hyper-V 中的虚拟设备配置
设备虚拟化一般有三种方式:
虚拟设备,共享使用
直接分配,独占访问
在物理设备的辅助下,虚拟出多个 “小设备”
我们以网卡为例,看看上述三种设备虚拟化方式是怎样的:
最经典的做法: 对每个虚拟机虚拟出一个与物理设备无关的网卡,虚拟机访问网卡时,就会陷入到虚拟机管理器(VMM)。这个虚拟网卡仿佛有 A/B 两面,A 面在虚拟机内,B 面在虚拟机管理器(主机)里。从 A 面发出的数据包会被送到 B 面,而从 B 面的发出的数据包会被送到 A 面。虚拟机管理器里有一个虚拟交换机,在各个虚拟机的 B 面以及物理网卡间进行转发。显然,纯软件实现的虚拟交换机是系统的性能瓶颈。
又到了实用时间:跟硬件辅助虚拟化一样,I/O MMU 在 BIOS 里也是有开关的,别忘了打开哦~
设备虚拟化也有 “全虚拟化” 和 “半虚拟化” 之分。如果虚拟机系统里的驱动程序能够修改,就可以直接调用虚拟机管理器(VMM)的 API,减少模拟硬件设备的开销,这种修改虚拟机内的驱动程序来提高性能的行为就属于半虚拟化。
通过在虚拟机系统里安装额外的驱动程序,还可以实现一些主机与虚拟机之间的交互(如共享剪贴板、拖动传文件)。这些驱动程序会在虚拟机系统中加载钩子,调用虚拟化管理器提供的 API 完成与主机系统的交互。
在虚拟机里安装额外的驱动程序做个小结,大家可以去喝杯茶,回味一下:
根据虚拟化管理器的实现方式,分为硬件虚拟化和软件虚拟化,硬件虚拟化已经退出历史舞台;
根据虚拟机操作系统是否需要修改,分为全虚拟化(Full Virtualization)和半虚拟化(Paravirtualization);
根据如何处理特权指令,分为模拟执行(效率很低)、二进制翻译(QEMU)和硬件辅助的虚拟化(KVM 等)。
操作系统级虚拟化
很多时候,我们并不是想在虚拟机里运行任意的操作系统,而是希望在不同的任务间实现一定程度的隔离。前面提到的虚拟化技术,每个虚拟机都是一个独立的操作系统,有自己的任务调度、内存管理、文件系统、设备驱动程序等,还会运行一定数量的系统服务(如刷新磁盘缓冲区、日志记录器、定时任务、ssh 服务器、时间同步服务),这些东西都会消耗系统资源(主要是内存),而且虚拟机和虚拟机管理器的两层任务调度、设备驱动等也会增加时间开销。能不能让虚拟机共享操作系统内核,又保持一定的隔离性呢?
两河缘何入一渠。为了方便开发和测试,1979 年的 UNIX 第七版引入了 chroot 机制。chroot 就是让一个进程把指定的目录作为根目录,它的所有文件系统操作都只能在这个指定目录里进行,这样就不会危害到主机系统。尽管 chroot 存在经典的跳出漏洞,而且它没有对进程、网络等资源进行任何隔离,chroot 至今仍然被用作构建和测试软件的干净环境。
要成为一个真正的虚拟化解决方案,只有文件系统隔离是不够的。另外两个重要的方面是:
进程、网络、IPC(进程间通信)、用户等命名空间的隔离。使得虚拟机内部只能看到自己的进程,只能使用自己的虚拟网卡,进程间通信时不会干扰到虚拟机外面,虚拟机内的 UID/GID 与外面的独立。
资源的限制和审计。不能因为虚拟机内的程序 “跑飞了”,就占掉物理机器的所有 CPU、内存、硬盘等资源。必须要能统计虚拟机占了多少资源,并能够对资源进行限制。
上述两件事情就是 BSD 和 Linux 社区在进入 21 世纪以来逐步在做的。在 Linux 中,命名空间的隔离叫做用户命名空间,在创建进程时,通过指定 clone 系统调用的参数来创建新的命名空间;资源的限制和审计是 cgroups 做的,它的 API 位于 proc 虚拟文件系统中。
这种虚拟机里运行一个或多个进程、虚拟机与主机共享一个内核的虚拟化方案,被称为 “操作系统级虚拟化” 或 “任务级虚拟化”。由于 Linux Containers(LXC)从 Linux 3.8 版本开始被纳入内核主线,操作系统级虚拟化又被称为 “容器”(container)。为了与虚拟机是一个完整的操作系统的虚拟化方案相区分,被隔离执行的进程(进程组)往往不称为 “虚拟机”,而称为 “容器”。由于没有多余的一层操作系统内核,容器比虚拟机更加轻量,启动更快,内存开销、调度开销也更小,更重要的是访问磁盘等 I/O 设备不需要经过虚拟化层,没有性能损失。
Linux 上的操作系统级虚拟化并不是从 LXC 开始有的,恰恰相反,LXC 是 “长江后浪推前浪” 的典型。Linux-Vserver、OpenVZ、Parallels Containers 都是在 Linux 内核里实现操作系统级虚拟化的解决方案。尽管小字辈们赢得了更多的眼球,作为一个长者,OpenVZ 还是比 LXC 多一些 “企业级” 的功能:
可以审计并限制每个容器的磁盘配额,通过目录级别的磁盘空间审计来实现(这也是 freeshell 使用 OpenVZ 而非 LXC 的主要原因);
支持检查点(checkpoint)、热迁移(live migration);
free -m、df -lh 等内存和磁盘的容量,在 OpenVZ 容器里看到的是它的配额,而 LXC 里看到的是物理机的容量;
支持 swap 空间,当发生 OOM(Out Of Memory)时杀死进程的行为与物理机器相同,而 LXC 会直接分配不出内存。
但是,由于 OpenVZ 坚持走 RHEL 路线,RHEL 6 还是 2.6.32 的老内核,RHEL 7 刚发布 OpenVZ 还没跟进,OpenVZ 内核现在看来已经很老了,连新版本的 systemd 都运行不起来,更不用说 3.x 内核的各种酷炫新功能了。
OpenVZ 架构
容器的好管家 Docker
好马配好鞍,这么好用的 Linux 容器,自然也要有个好管家。从哪里获得系统镜像?如何对镜像进行版本控制?Docker 就是近来大红大紫的 Linux 容器好管家,据说连巨硬都向 Docker 示好,要为 Windows 开发容器支持了。
Docker 其实是为系统运维而生的,它大大降低了软件安装、部署的成本。软件的安装之所以是个麻烦事,是因为
软件之间存在依赖关系。 比如,Linux 上依赖标准 C 库 glibc,依赖密码学库 OpenSSL,依赖 Java 运行环境;Windows 上依赖 .NET Framework,依赖 Flash 播放器。如果每个软件都带上它所有的依赖,那就太臃肿了,如何找到并安装软件的依赖,是一门大学问,也是各个 Linux 发行版的特色所在。
软件之间存在冲突。比如,程序 A 依赖 glibc 2.13,而程序 B 依赖 glibc 2.14;甲脚本需要 Python 3,乙脚本需要 Python 2;Apache 和 nginx 两个 Web 服务器都想要监听 80 端口。互相冲突的软件安装在同一个系统里,总是容易带来一些混乱,比如 Windows 早期的 DLL Hell。解决软件冲突之道就是隔离,让多个版本在系统里共存,并提供方法来找到匹配的版本。
我们看看 Docker 如何解决这两个问题:
把软件的所有依赖关系和运行环境打包在一个镜像里,而不是使用复杂的脚本来在未知的环境里 “安装” 软件;
这个包含了所有依赖的包一定很大,因此 Docker 的镜像是层次化的,即应用程序的镜像一般是基于基本系统镜像,只需要传输和存储增量部分就行了;
Docker 使用基于容器的虚拟化,把每个软件运行在独立的容器里,避免了不同软件的文件系统路径冲突和运行时的资源冲突。
其中,Docker 的层次化镜像结构依赖于 Linux 的 AUFS(Another Union File System),AUFS 可以把基础目录 A、增量目录 B 合并挂载为一个目录 C,C 中能够同时看到 A、B 中的文件(有冲突以 B 中的为准),对 C 的修改会被写入 B。当一个 Docker 容器被启动时,就会生成一个增量目录并与作为基础目录的 Docker 镜像合并挂载,Docker 容器的所有写操作都被写入增量目录,而不会修改基础目录。这样就以比较低的开销实现了文件系统的 “版本控制”,也减小了软件的分发体积(只需分发增量部分,基础镜像是大多数人已经有的)。
Docker、LXC 与内核组件的关系Docker 的虚拟化则是基于 libcontainer(上图比较老了,那时还是基于 LXC)。libcontainer 和 LXC 事实上都是基于 Linux 内核提供的 cgroups 资源审计、chroot 文件系统隔离、命名空间隔离等机制。
插播:Freeshell 是如何启动的我们知道 freeshell 采用的是 OpenVZ 虚拟化技术,经常有人问能不能换内核,还有人问 freeshell 系统是从哪里启动的。事实上,跟普通的 Linux 系统一样,freeshell 是从虚拟机里的 /sbin/init 开始运行的(看看是不是 1 号进程?),后面就是虚拟机系统自己的启动过程了。
Freeshell 控制面板一角事实上,不同类型的虚拟化技术是从不同的地方开始引导虚拟机系统的:
从模拟的 BIOS 开始引导的,支持 MBR、EFI、PXE 等启动方式,如 QEMU、VMWare;
从内核开始引导的,虚拟机镜像内不包含内核,如 KVM、Xen;
从 init 进程开始引导的,虚拟机是一个与主机共享内核的容器,会按照操作系统的引导过程启动各种系统服务,如 LXC、OpenVZ;
只运行一个特定的应用程序或服务的,也是基于容器,如 Docker。
云操作系统 OpenStack前面讲的都是实现虚拟化的具体技术。但要让最终用户用上虚拟机,还需要有管理虚拟机的平台,或称 “云操作系统”。OpenStack 是目前最火的云操作系统。
OpenStack 云操作系统OpenStack(或者任何靠谱的云操作系统)要对云上的各种资源进行虚拟化,它的管理组件称为 Nova。
计算: 本文所说的虚拟化技术就是计算的虚拟化。OpenStack 可以使用多种多样的虚拟化解决方案,如 Xen、KVM、QEMU、Docker。管理组件 Nova 根据各物理节点的负载决定把虚拟机调度到哪台物理机,再调用这些虚拟化解决方案的 API 来创建、删除、开机、关机等。
存储:虚拟机镜像如果只能存储在计算节点本地,那么不仅不利于数据的冗余,也不利于虚拟机的迁移。因此在云中,一般采用逻辑上集中、物理上分布式的存储系统,独立于计算节点,也就是计算节点对数据磁盘的访问一般是通过网络访问。
网络:每个客户要有自己的虚拟网络,如何让不同客户的虚拟网络在物理网络上互不干扰,就是网络虚拟化的事情,参见我的另一篇博客《》。
除了最核心的虚拟化管理器 Nova,OpenStack 还有虚拟机镜像管理器 Glance、对象存储 Swift、块存储 Cinder、虚拟网络 Neutron、身份认证服务 Keystone、控制面板 Horizon 等众多组件。
OpenStack 控制面板(Horizon)下面两张图展示了 Nova 分别使用 Docker 和 Xen 作为虚拟化解决方案的架构。
Docker 受 OpenStack Nova 计算组件的调用
使用 Xen 作为 OpenStack 的计算虚拟化方案
结语
任务隔离的需求催生了虚拟化,我们都既希望任务隔离得彻底一些,又不希望损失太多的性能。从隔离性最高但慢到不实用的模拟执行,到现代全虚拟化技术所采用的动态二进制翻译与硬件辅助虚拟化,再到修改虚拟机系统的半虚拟化,再到共享内核、基于容器的操作系统级虚拟化,性能始终是虚拟化技术浪潮的第一推动力。不过,当我们选择虚拟化技术时,还是要根据实际需求,在隔离性与性能的天平上找到平衡点。
古老的计算虚拟化技术,加上相对新生的存储、网络虚拟化技术,构成了云操作系统的基石。九层之台,起于垒土,当我们享受云端似乎取之不尽用之不竭的计算资源时,如果能剥开一层层的封装,洞悉计算的本质,也许我们会更加珍惜云端的计算资源,更加赞叹虚拟化技术大厦的宏伟与精致,也更加崇敬和膜拜那些引领人类走进云时代的计算机大师。
特别提示:
KVM云社区微信群加入,联系北极熊:
QQ 1群:434720759(已满)
QQ 2群:131961942,加入密码大写KVM
1000人VMWare技术交流群:494084329,加入密码小写vm
2000人OpenStack开发纯技术群: 334605713 加入密码nova
Cloudstack纯技术交流群:515249455密码cs
2000人桌面云行业讨论: 484979056 加入密码大写VDI
2000人超融合行业讨论群:65779632 加入密码大写HC
以上是关于虚拟化技术大观|长文慎入的主要内容,如果未能解决你的问题,请参考以下文章