You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
18 KiB
Markdown

2 years ago
# 49 | 虚拟机:如何成立子公司,让公司变集团?
我们前面所有章节涉及的Linux操作系统原理都是在一台Linux服务器上工作的。在前面的原理阐述中我们一直把Linux当作一家外包公司的老板来看待。想要管理这么复杂、这么大的一个公司需要配备咱们前面讲过的所有机制。
Linux很强大Linux服务器也随之变得越来越强大了。无论是计算、网络、存储都越来越牛。例如内存动不动就是百G内存网络设备一个端口的带宽就能有几十G甚至上百G存储在数据中心至少是PB级别的一个P是1024个T一个T是1024个G
公司大有大的好处,自然也有大的毛病,也就是咱们常见的“大公司病”——**不灵活**。这里面的不灵活,有下面这几种,我列一下,你看看你是不是都见过。
* **资源大小不灵活**有时候我们不需要这么大规格的机器可能只想尝试一下某些新业务申请个4核8G的服务器试一下但是不可能采购这么小规格的机器。无论每个项目需要多大规格的机器公司统一采购就限制几种全部是上面那种大规格的。
* **资源申请不灵活**:规格定死就定死吧,可是每次申请机器都要重新采购,周期很长。
* **资源复用不灵活**反正我需要的资源不多和别人共享一台机器吧这样不同的进程可能会产生冲突例如socket的端口冲突。另外就是别人用过的机器不知道上面做过哪些操作有很多的历史包袱如果重新安装则代价太大。
这些是不是和咱们在大公司里面遇到的问题很像?按说,大事情流程严谨没问题,很多小事情也要被拖累走整个流程,而且很容易出现资源冲突,每天跨部门的协调很累人,历史包袱严重,创新没有办法轻装上阵。
很多公司处理这种问题采取的策略是成立独立的子公司,独立决策,独立运营,往往用于创新型的项目。
Linux也采取了这样的手段就是在物理机上面创建虚拟机。每个虚拟机有自己单独的操作系统、灵活的规格一个命令就能启动起来。每次创建都是新的操作系统很好地解决了上面不灵活的问题。
但是要使用虚拟机,还有一些问题需要解决一下。
我们知道操作系统上的程序分为两种一种是用户态的程序例如Word、Excel等一种是内核态的程序例如内核代码、驱动程序等。
为了区分内核态和用户态CPU专门设置四个特权等级0、1、2、3来做这个事情。
当时写Linux内核的时候估计大牛们还不知道将来虚拟机会大放异彩。大牛们想一共两级特权一个内核态一个用户态却有四个等级好奢侈、好富裕于是就敞开了用。内核态运行在第0等级用户态运行在第3等级占了两头中间的都不用太不会过日子了。
大牛们在写Linux内核的时候如果用户态程序做事情就将扳手掰到第3等级一旦要申请使用更多的资源就需要申请将扳手掰到第0等级内核才能在高权限访问这些资源申请完资源返回到用户态扳手再掰回去。
这个程序一直非常顺利地运行着,直到虚拟机出现了。
## 三种虚拟化方式
如果你安装VirtualBox桌面版你可以用这个虚拟化软件创建虚拟机在虚拟机里面安装一个Linux外面的操作系统也可以是Linux。VirtualBox这个虚拟化软件和你的Excel一样都是在你的任务栏里面并排放着是一个普通的应用。
当你进入虚拟机的时候虚拟机里面的Excel也是一个普通的应用。
这个时候麻烦的事情出现了,当你设身处地地站在虚拟机的内核角度,去思考一下人生,你就会出现困惑了,会想,我到底是啥?
在硬件上的操作系统来看我是一个普通的应用只能运行在用户态。可是大牛们“生“我的时候我的每一行代码都告诉我我是个内核啊应该运行在内核态。当虚拟机里面的Excel要访问网络的时候向我请求我的代码就要努力地去操作网卡。尽管我努力但是我做不到啊我没有权限
我分裂了……
怎么办呢虚拟化层也就是Virtualbox会帮你解决这个问题它有三种虚拟化的方式。
我们先来看第一种方式,**完全虚拟化**Full virtualization。其实说白了这是一种“骗人”的方式。虚拟化软件会模拟假的CPU、内存、网络、硬盘给到我让我自我感觉良好感觉自己终于又像个内核了。
但是,真正的工作模式其实是下面这样的。
> 虚拟机内核说我要在CPU上跑一个指令
> 虚拟化软件说:没问题,你是内核嘛,可以跑!
> 虚拟化软件转过头去找物理机内核说报告我管理的虚拟机里面的一个要执行一个CPU指令帮忙来一小段时间空闲的CPU时间让我代它跑个指令。
> 物理机内核说:你等着,另一个跑着呢。(过了一会儿)它跑完了,该你了。
> 虚拟化软件说:我代它跑,终于跑完了,出来结果了。
> 虚拟化软件转头给虚拟机内核说:哥们儿,跑完了,结果是这个。我说你是内核吧,绝对有权限,没问题,下次跑指令找我啊!
> 虚拟机内核说:看来我真的是内核呢,可是,哥,好像这点儿指令跑得有点慢啊!
> 虚拟化软件说:这就不错啦,好几个排着队跑呢!
内存的申请模式是下面这样的。
> 虚拟机内核说我启动需要4G内存我好分给我上面的应用。
> 虚拟化软件说没问题才4G你是内核嘛我马上申请好。
> 虚拟化软件转头给物理机内核说报告我启动了一个虚拟机需要4G内存给我4个房间呗。
> 物理机内核怎么又一个虚拟机啊好吧给你90、91、92、93四个房间。
> 虚拟化软件转头给虚拟机内核说哥们内存有了0、1、2、3这个四个房间都是你的。你看你是内核嘛独占资源从0编号的就是你的。
> 虚拟机内核说看来我真的是内核啊能从头开始用。那好我就在房间2的第三个柜子里面放个东西吧
> 虚拟化软件说要放东西啊没问题。但是它心里想我查查看这个虚拟机是90号房间开头的它要在房间2放东西那就相当于在房间92放东西。
> 虚拟化软件转头给物理机内核说报告我上面的虚拟机要在92号房间的第三个柜子里面放个东西。
好了说完了CPU和内存的例子网络和硬盘就不细说了情况也是类似的都是虚拟化软件模拟一个给虚拟机内核看的其实啥事儿都需要虚拟化软件转一遍。
这种方式一个坏处就是,慢,而且往往慢到不能忍受。
于是,虚拟化软件想,我能不能不当传话筒,要让虚拟机内核正视自己的身份。别说你是内核,你还真喘上了。你不是物理机,你是虚拟机!
但是怎么解决权限等级的问题呢于是Intel的VT-x和AMD的AMD-V从硬件层面帮上了忙。当初谁让你们这些写内核的大牛用等级这么奢侈用完了0就是3也不省着点儿用没办法只好另起炉灶弄一个新的标志位表示当前是在虚拟机状态下还是在真正的物理机内核下。
对于虚拟机内核来讲只要将标志位设为虚拟机状态我们就可以直接在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里面过一手因而性能就会比较差。
![](https://static001.geekbang.org/resource/image/05/fa/058be86de5a43a782392aff3cb8a1ffa.png)
按照上面的介绍完全虚拟化是非常慢的所以要使用硬件辅助虚拟化技术Intel-VTAMD-V所以需要CPU硬件开启这个标志位一般在BIOS里面设置。
当确认开始了标志位之后通过KVMGuestOS的CPU指令不用经过Qemu转译直接运行大大提高了速度。
所以KVM在内核里面需要有一个模块来设置当前CPU是Guest OS在用还是Host OS在用。
下面我们来查看内核模块中是否含有kvm, lsmod | grep kvm。
KVM内核模块通过/dev/kvm暴露接口用户态程序可以通过ioctl来访问这个接口。例如你可以通过下面的流程编写程序。
![](https://static001.geekbang.org/resource/image/f5/62/f5ee1a44d7c4890e411c2520507ddc62.png)
Qemu将KVM整合进来将有关CPU指令的部分交由内核模块来做就是qemu-kvm (qemu-system-XXX)。
qemu和kvm整合之后CPU的性能问题解决了。另外Qemu还会模拟其他的硬件如网络和硬盘。同样全虚拟化的方式也会影响这些设备的性能。
于是qemu采取半虚拟化的方式让Guest OS加载特殊的驱动来做这件事情。
例如网络需要加载virtio\_net存储需要加载virtio\_blkGuest需要安装这些半虚拟化驱动GuestOS知道自己是虚拟机所以数据会直接发送给半虚拟化设备经过特殊处理例如排队、缓存、批量处理等性能优化方式最终发送给真正的硬件。这在一定程度上提高了性能。
至此,整个关系如下图所示。
![](https://static001.geekbang.org/resource/image/f7/22/f748fd6b6b84fa90a1044a92443c3522.png)
## 创建虚拟机
了解了qemu-kvm的工作原理之后下面我们来看一下如何使用qemu-kvm创建一个能够上网的虚拟机。
如果使用VirtualBox创建过虚拟机通过界面点点就能创建一个能够上网的虚拟机。如果使用qemu-kvm就没有这么简单了。一切都得自己来做不过这个过程可以了解KVM虚拟机的创建原理。
首先我们要给虚拟机起一个名字在KVM里面就是-name ubuntutest。
![](https://static001.geekbang.org/resource/image/93/a8/93d2df627d6dfb09cf1c13fee16629a8.png)
设置一个内存大小在KVM里面就是-m 1024。
![](https://static001.geekbang.org/resource/image/db/76/db13672936d08b2c2c28115f16937876.png)
创建一个虚拟硬盘对于VirtualBox是VDI格式对于KVM则不同。
![](https://static001.geekbang.org/resource/image/13/dd/136d17009a7481cbd472036e4ee83ddd.png)
硬盘有两种格式,一个是动态分配,也即开始创建的时候,看起来很大,其实占用的空间很少,真实有多少数据,才真的占用多少空间。一个是固定大小,一开始就占用指定的大小。
![](https://static001.geekbang.org/resource/image/c2/66/c201a260cb24b2f39d6ba0ac7b548a66.png)
比如我这台电脑硬盘的大小为8G。
![](https://static001.geekbang.org/resource/image/9e/6d/9ed4e7712a6fe9f43dae5d1c1ecb9e6d.png)
在KVM中创建一个虚拟机镜像大小为8G其中qcow2格式为动态分配raw格式为固定大小。
```
qemu-img create -f qcow2 ubuntutest.img 8G
```
我们将Ubuntu的ISO挂载为光盘在KVM里面-cdrom [ubuntu-xxx-server-amd64.iso](http://ubuntu-xxx-server-amd64.iso)。
![](https://static001.geekbang.org/resource/image/09/b0/091d934004d10550a87b4d635546d5b0.png)
创建一个网络有时候会选择桥接网络有时候会选择NAT网络这个在KVM里面只有自己配置了。
![](https://static001.geekbang.org/resource/image/6d/5b/6d8733d73192bd1b114df03f01c6275b.png)
接下来Virtualbox就会有一个界面可以看到安装的整个过程在KVM里面我们用VNC来做。参数为-vnc :19
于是我们也可以创建KVM虚拟机了可以用下面的命令
```
qemu-system-x86_64 -enable-kvm -name ubuntutest -m 2048 -hda ubuntutest.img -cdrom ubuntu-14.04-server-amd64.iso -boot d -vnc :19
```
启动了虚拟机后连接VNC我们也能看到安装的过程。
![](https://static001.geekbang.org/resource/image/6a/1e/6afde27eb9bf29b566c47bf60fd56f1e.png)
按照普通安装Ubuntu的流程安装好Ubuntu然后shutdown -h now关闭虚拟机。
接下来我们可以对KVM创建桥接网络了。这个要模拟virtualbox的桥接网络模式。
如果在桌面虚拟化软件上选择桥接网络,在你的笔记本电脑上,就会形成下面的结构。
![](https://static001.geekbang.org/resource/image/2b/47/2b49867c473162d4706553e8cbb5f247.png)
每个虚拟机都会有虚拟网卡,在你的笔记本电脑上,会发现多了几个网卡,其实是虚拟交换机。这个虚拟交换机将虚拟机连接在一起。在桥接模式下,物理网卡也连接到这个虚拟交换机上。物理网卡在桌面虚拟化软件的“界面名称”那里选定。
如果使用桥接网络当你登录虚拟机里看IP地址时会发现你的虚拟机的地址和你的笔记本电脑的地址以及你旁边的同事的电脑的网段是一个网段。这是为什么呢这其实相当于将物理机和虚拟机放在同一个网桥上相当于这个网桥上有三台机器是一个网段的全部打平了。
![](https://static001.geekbang.org/resource/image/78/47/7899a96aaa0b91c165f867d3ec42e947.png)
在数据中心里面采取的也是类似的技术连接方式如下图所示只不过是Linux在每台机器上都创建网桥br0虚拟机的网卡都连到br0上物理网卡也连到br0上所有的br0都通过物理网卡连接到物理交换机上。
![](https://static001.geekbang.org/resource/image/da/a7/da83bb01b7ed63ac0062b5cc835099a7.png)
同样我们换一个角度看待这个拓扑图。同样是将网络打平,虚拟机会和物理网络具有相同的网段,就相当于两个虚拟交换机、一个物理交换机,一共三个交换机连在一起。两组四个虚拟机和两台物理机都是在一个二层网络里面的。
![](https://static001.geekbang.org/resource/image/8e/c6/8e471a287e0181f1b7af56b60b84adc6.png)
qemu-kvm如何才能创建一个这样的桥接网络呢
1.在Host机器上创建bridge br0。
```
brctl addbr br0
```
2.将br0设为up。
```
ip link set br0 up
```
3.创建tap device。
```
tunctl -b
```
4.将tap0设为up。
```
ip link set tap0 up
```
5.将tap0加入到br0上。
```
brctl addif br0 tap0
```
6.启动虚拟机, 虚拟机连接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
```
7.虚拟机启动后网卡没有配置所以无法连接外网先给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
```
10.如果DNS没配错可以进行apt-get update。
在这里请记住qemu-system-x86\_64的启动命令这里面有CPU虚拟化KVM有内存虚拟化、硬盘虚拟化、网络虚拟化。接下来的章节我们会看内核是如何进行虚拟化的。
## 总结时刻
今天我们讲了虚拟化的基本原理,并且手动创建一个可以上网的虚拟机。请记住下面这一点,非常重要,理解虚拟机启动的参数就是理解虚拟化技术的入口。学会创建虚拟机,在后面做内核相关实验的时候就会非常方便。
具体到知识点上,这一节你需要需要记住下面的这些知识点:
* 虚拟化的本质是用qemu的软件模拟硬件但是模拟方式比较慢需要加速
* 虚拟化主要模拟CPU、内存、网络、存储分别有不同的加速办法
* CPU和内存主要使用硬件辅助虚拟化进行加速需要配备特殊的硬件才能工作
* 网络和存储主要使用特殊的半虚拟化驱动加速,需要加载特殊的驱动程序。
## 课堂练习
请你务必自己使用qemu按照上面我写的步骤创建一台虚拟机。
欢迎留言和我分享你的疑惑和见解,也欢迎可以收藏本节内容,反复研读。你也可以把今天的内容分享给你的朋友,和他一起学习和进步。