三种虚拟化方式

我们先来看第一种方式,完全虚拟化(Full virtualization)。其实说白了,这是一种“骗人”的方式。虚拟化软件会模拟假的 CPU、内存、网络、硬盘给到我,让我自我感觉良好,感觉自己终于又像个内核了。

这种方式一个坏处就是,慢,而且往往慢到不能忍受。

安装虚拟机的时候,我们务必要将物理 CPU 的这个标志位打开。想知道是否打开,对于 Intel,你可以查看 grep “vmx” /proc/cpuinfo;对于 AMD,你可以查看 grep “svm” /proc/cpuinfo
这叫作硬件辅助虚拟化(Hardware-Assisted Virtualization)。

另外就是访问网络或者硬盘的时候,为了取得更高的性能,也需要让虚拟机内核加载特殊的驱动,也是让虚拟机内核从代码层面就重新定位自己的身份,不能像访问物理机一样访问网络或者硬盘,而是用一种特殊的方式。
我知道我不是物理机内核,我知道我是虚拟机,我没那么高的权限,我很可能和很多虚拟机共享物理资源,所以我要学会排队,我写硬盘其实写的是一个物理机上的文件,那我的写文件的缓存方式是不是可以变一下。我发送网络包,根本就不是发给真正的网络设备,而是给虚拟的设备,我可不可以直接在内存里面拷贝给它,等等等等。
一旦我知道我不是物理机内核,痛定思痛,只好重新认识自己,反而能找出很多方式来优化我的资源访问。
这叫作半虚拟化(Paravirtualization)。

对于桌面虚拟化软件,我们多采用 VirtualBox,如果使用服务器的虚拟化软件,则有另外的选型。
服务器上的虚拟化软件,多使用 qemu,其中关键字 emu,全称是 emulator,模拟器。所以,单纯使用 qemu,采用的是完全虚拟化的模式。
qemu 向 Guest OS 模拟 CPU,也模拟其他的硬件,GuestOS 认为自己和硬件直接打交道,其实是同 qemu 模拟出来的硬件打交道,qemu 会将这些指令转译给真正的硬件。由于所有的指令都要从 qemu 里面过一手,因而性能就会比较差。
image.png
按照上面的介绍,完全虚拟化是非常慢的,所以要使用硬件辅助虚拟化技术 Intel-VT,AMD-V,所以需要 CPU 硬件开启这个标志位,一般在 BIOS 里面设置。
**
当确认开始了标志位之后,通过 KVM【 Kernel-based Virtual Machine】,GuestOS 的 CPU 指令不用经过 Qemu 转译,直接运行,大大提高了速度。

所以,KVM 在内核里面需要有一个模块,来设置当前 CPU 是 Guest OS 在用,还是 Host OS 在用。
下面,我们来查看内核模块中是否含有 kvm, lsmod | grep kvm。

KVM 内核模块通过 /dev/kvm 暴露接口,用户态程序可以通过 ioctl 来访问这个接口。例如,你可以通过下面的流程编写程序。
image.png
Qemu 将 KVM 整合进来,将有关 CPU 指令的部分交由内核模块来做,就是 qemu-kvm (qemu-system-XXX)。
qemu 和 kvm 整合之后,CPU 的性能问题解决了。另外 Qemu 还会模拟其他的硬件,如网络和硬盘。同样,全虚拟化的方式也会影响这些设备的性能。
于是,qemu 采取半虚拟化的方式,让 Guest OS 加载特殊的驱动来做这件事情。
例如,网络需要加载 virtio_net,存储需要加载 virtio_blk,Guest 需要安装这些半虚拟化驱动,GuestOS 知道自己是虚拟机,所以数据会直接发送给半虚拟化设备,经过特殊处理(例如排队、缓存、批量处理等性能优化方式),最终发送给真正的硬件。这在一定程度上提高了性能。
至此,整个关系如下图所示。
image.png

我们可以对 KVM 创建桥接网络了。这个要模拟 virtualbox 的桥接网络模式。
如果在桌面虚拟化软件上选择桥接网络,在你的笔记本电脑上,就会形成下面的结构。
image.png
每个虚拟机都会有虚拟网卡,在你的笔记本电脑上,会发现多了几个网卡,其实是虚拟交换机。这个虚拟交换机将虚拟机连接在一起。在桥接模式下,物理网卡也连接到这个虚拟交换机上。物理网卡在桌面虚拟化软件的“界面名称”那里选定。
如果使用桥接网络,当你登录虚拟机里看 IP 地址时会发现,你的虚拟机的地址和你的笔记本电脑的地址,以及你旁边的同事的电脑的网段是一个网段。这是为什么呢?这其实相当于将物理机和虚拟机放在同一个网桥上,相当于这个网桥上有三台机器,是一个网段的,全部打平了。
image.png
在数据中心里面,采取的也是类似的技术,连接方式如下图所示,只不过是 Linux 在每台机器上都创建网桥 br0,虚拟机的网卡都连到 br0 上,物理网卡也连到 br0 上,所有的 br0 都通过物理网卡连接到物理交换机上。
image.png
同样我们换一个角度看待这个拓扑图。同样是将网络打平,虚拟机会和物理网络具有相同的网段,就相当于两个虚拟交换机、一个物理交换机,一共三个交换机连在一起。两组四个虚拟机和两台物理机都是在一个二层网络里面的。
image.png
qemu-kvm 如何才能创建一个这样的桥接网络呢?
1. 在 Host 机器上创建 bridge br0。

  1. brctl addbr br0
  1. 将 br0 设为 up。
    ip link set br0 up
    
  2. 创建 tap device。
    tunctl -b
    
  3. 将 tap0 设为 up。
    ip link set tap0 up
    
  4. 将 tap0 加入到 br0 上。
    brctl addif br0 tap0
    
  5. 启动虚拟机, 虚拟机连接 tap0、tap0 连接 br0。
    qemu-system-x86_64 -enable-kvm -name ubuntutest -m 2048 -hda ubuntutest.qcow2 -vnc :19 -net nic,model=virtio -nettap,ifname=tap0,script=no,downscript=no
    
  6. 虚拟机启动后,网卡没有配置,所以无法连接外网,先给 br0 设置一个 ip。
    ifconfig br0 192.168.57.1/24
    
    8.VNC 连上虚拟机,给网卡设置地址,重启虚拟机,可 ping 通 br0。
    9. 要想访问外网,在 Host 上设置 NAT,并且 enable ip forwarding,可以 ping 通外网网关。
    # sysctl -p
    net.ipv4.ip_forward = 1
    sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    
  7. 如果 DNS 没配错,可以进行 apt-get update。
    在这里,请记住 qemu-system-x86_64 的启动命令,这里面有 CPU 虚拟化 KVM,有内存虚拟化、硬盘虚拟化、网络虚拟化。接下来的章节,我们会看内核是如何进行虚拟化的。

    总结时刻

    今天我们讲了虚拟化的基本原理,并且手动创建一个可以上网的虚拟机。请记住下面这一点,非常重要,理解虚拟机启动的参数就是理解虚拟化技术的入口。学会创建虚拟机,在后面做内核相关实验的时候就会非常方便。
    具体到知识点上,这一节你需要需要记住下面的这些知识点:
  • 虚拟化的本质是用 qemu 的软件模拟硬件,但是模拟方式比较慢,需要加速;
  • 虚拟化主要模拟 CPU、内存、网络、存储,分别有不同的加速办法;
  • CPU 和内存主要使用硬件辅助虚拟化进行加速,需要配备特殊的硬件才能工作;
  • 网络和存储主要使用特殊的半虚拟化驱动加速,需要加载特殊的驱动程序。