第1章 虚拟化
虚拟化是云计算的基础。简单地说,虚拟化使得在一台物理的服务器上可以跑多台虚拟机,虚拟机共享物理机的CPU、内存、IO硬件资源,但逻辑上虚拟机之间是相互隔离的。
物理机我们一般称为宿主机(Host),宿主机上面的虚拟机称为客户机(Guest)。
那么Host是如何将自己的硬件资源虚拟化,并提供给Guest使用的呢?
这个主要是通过一个叫做Hypervisor的程序实现的。
根据Hypervisor的实现方式和所处的位置,虚拟化又分为两种:1型虚拟化和2型虚拟化。
1.1 1型虚拟化
Hypervisor直接安装在物理机上,多个虚拟机在Hypervisor上运行。Hypervisor实现方式一般是一个特殊定制的Linux系统。Xen和VMWare的ESXi都属于这个类型,如图1-1所示。
图1-1
1.2 2型虚拟化
物理机上首先安装常规的操作系统,比如Redhat、Ubuntu和Windows。Hypervisor作为OS上的一个程序模块运行,并对虚拟机进行管理。KVM、VirtualBox和VMWare Workstation都属于这个类型,如图1-2所示。
图1-2
理论上讲:
1.型虚拟化一般对硬件虚拟化功能进行了特别优化,性能上比2型要高;
2.型虚拟化因为基于普通的操作系统,会比较灵活,比如支持虚拟机嵌套。嵌套意味着可以在KVM虚拟机中再运行KVM。
1.3 KVM
下面重点介绍KVM这种2型虚拟化技术。
1.3.1 基本概念
在x86平台上最热门、运用最广泛的虚拟化方案莫过于KVM了。OpenStack对KVM支持得也最好,我们的教程也理所当然选择KVM作为实验环境的Hypervisor。
KVM全称是Kernel-Based Virtual Machine。也就是说KVM是基于Linux内核实现的。
KVM有一个内核模块叫kvm.ko,只用于管理虚拟CPU和内存。
那IO的虚拟化,比如存储和网络设备由谁实现呢?
这个就交给Linux内核和Qemu来实现。
说白了,作为一个Hypervisor,KVM本身只关注虚拟机调度和内存管理这两个方面。IO外设的任务交给Linux内核和Qemu。
Libvirt
大家在网上看KVM相关文章的时候肯定经常会看到Libvirt这个东西。
Libvirt是啥?
简单地说就是KVM的管理工具。
其实,Libvirt除了能管理KVM这种Hypervisor,还能管理Xen,VirtualBox等。
OpenStack底层也使用Libvirt,所以很有必要学习一下。
Libvirt包含3个东西:后台daemon程序libvirtd、API库和命令行工具virsh。
- libvirtd是服务程序,接收和处理API请求;
- API库使得其他人可以开发基于Libvirt的高级工具,比如virt-manager,这是个图形化的KVM管理工具,后面我们也会介绍;
- virsh是我们经常要用的KVM命令行工具,后面会有使用的示例。
作为KVM和OpenStack的实施人员,virsh和virt-manager是一定要会用的。
今天5分钟差不多了,下一节我们来玩KVM。
1.3.2 KVM实操
1.准备KVM实验环境
上一节说了,KVM是2型虚拟化,是运行在操作系统之上的,所以先要装一个Linux。Ubuntu、Redhat、CentOS都可以,这里以Ubuntu14.04为例。
基本的Ubuntu操作系统装好之后,安装KVM需要的包:
$ sudo apt-get install qemu-kvm qemu-system libvirt-bin virt-manager bridge-utils vlan
通过这些安装包顺便复习一下上一节介绍的KVM的相关知识。
- qemu-kvm和qemu-system是KVM和QEMU的核心包,提供CPU、内存和IO虚拟化功能。
- libvirt-bin就是libvirt,用于管理KVM等Hypervisor。
- virt-manager是KVM图形化管理工具。
- bridge-utils和vlan,主要是网络虚拟化需要,KVM网络虚拟化的实现是基于linux-bridge和VLAN,后面我们会讨论。
Ubuntu默认不安装图形界面,手工安装一下:
sudo apt-get install xinit sudo apt-get install gdm sudo apt-get install kubuntu-desktop
apt默认会到官网上去下载安装包,速度很慢,我们可以使用国内的镜像站点。
配置/etc/apt/sources.list:
deb http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse deb http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ trusty main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ trusty-security main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ trusty-updates main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ trusty-proposed main restricted universe multiverse deb-src http://mirrors.163.com/ubuntu/ trusty-backports main restricted universe multiverse
然后执行下面命令更新安装包index:
# apt update
Redhat和CentOS安装相对简单,安装过程中选择虚拟化和图形组件就可以了。
小窍门:Ubuntu默认是不允许root通过ssh直接登录的,可以修改/etc/ssh/sshd_config,设置:
PermitRootLogin yes
然后重启ssh服务即可:
# service ssh restart ssh stop/waiting ssh start/running, process 27639
在虚拟机上做实验
作为2型虚拟化的KVM,支持虚拟化嵌套,这使得我们可以在虚拟机中实验KVM。
比如我在VMWare Workstation中安装了一个Ubuntu14.04的虚拟机,为了让KVM能创建。
嵌套的虚机,要把CPU的虚拟化功能打开。如图1-3所示,在VMWare中设置以下CPU的模式。
图1-3
Ubuntu启动后,用以下命令确认CPU支持虚拟化:
# egrep -o '(vmx|svm)' /proc/cpuinfo # vmx
确认Libvirtd服务已经启动:
# service libvirt-bin status libvirt-bin start/running, process 1478
2.启动第一个KVM虚机
本节演示如何使用virt-manager启动KVM虚机。
首先通过命令virt-manager启动图形界面,如图1-4所示。
# virt-manager
图1-4
单击图1-4中框选的图标创建虚机,如图1-5所示。
图1-5
给虚机命名为kvm1,这里选择从哪里启动虚机。如果是安装新的OS,可以选择第一项。如果已经有安装好的镜像文件,选最后一项(如图1-5所示)。
接下来需要告诉virt-manager镜像的位置,如图1-6所示。
图1-6
单击“Browser”,打开如图1-7所示的界面。
图1-7
在我的系统中存放了一个cirros-0.3.3-x86_64-disk.img镜像文件,单击“Choose Volume”,如图1-8所示。cirros是一个很小的linux镜像,非常适合测试用,大家可以到http://download.cirros-cloud.net/下载,然后放到/var/lib/libvirt/images/目录下,这是KVM默认查找镜像文件的地方。
图1-8
单击“Forward”,为虚拟机分配CPU和内存,如图1-9所示。
图1-9
单击“Forward”,再确认一下信息,就可以启动虚机了,如图1-10所示。
图1-10
单击“Finish”,virt-manager会打开虚机kvm1的控制台窗口,可以看到启动情况,如图1-11所示。
图1-11
virt-manager可以对虚机进行各种管理操作,界面直观友好,很容易上手,如图1-12所示。
图1-12
同时我们也可以用命令virsh管理虚机,比如查看宿主机上的虚机:
root@ubuntu:~# virsh list Id Name State --------------- 8 kvm1 running
至此,第一个虚机已经跑起来了,采用的都是默认设置,后面我们会逐步讨论有关虚机更细节的内容,比如存储和网卡的设置。
3.远程管理KMV虚机
上一节我们通过virt-manager在本地主机上创建并管理KVM虚机。其实virt-manager也可以管理其他宿主机上的虚机。只需要简单地将宿主机添加进来,如图1-13所示。
图1-13
填入宿主机的相关信息,确定即可,如图1-14所示。
图1-14
接下来,我们就可以像管理本地虚机一样去管理远程宿主机上的虚机了,如图1-15所示。
图1-15
这里其实有一个要配置的地方。
因为KVM(准确说是Libvirt)默认不接受远程管理,需要按下面的内容配置被管理宿主机中的两个文件:
/etc/default/libvirt-bin start_libvirtd="yes" libvirtd_opts="-d -l" /etc/libvirt/libvirtd.conf listen_tls = 0 listen_tcp = 1 unix_sock_group = "libvirtd" unix_sock_ro_perms = "0777" unix_sock_rw_perms = "0770" auth_unix_ro = "none" auth_unix_rw = "none" auth_tcp = "none"
然后重启Libvirtd服务就可以远程管理了。
service libvirt-bin restart
1.4 KVM虚拟化原理
前面我们成功地把KVM跑起来了,有了些感性认识,这个对于初学者非常重要。不过还不够,我们多少得了解一些KVM的实现机制,这对以后的工作会有帮助。
1.4.1 CPU虚拟化
KVM的虚拟化是需要CPU硬件支持的。还记得我们在前面的章节讲过用命令来查看CPU是否支持KVM虚拟化吗?
root@ubuntu:~# egrep -o '(vmx|svm)' /proc/cpuinfo vmx
如果有输出vmx或者svm,就说明当前的CPU支持KVM。CPU厂商Intel和AMD都支持虚拟化了,除非是非常老的CPU。
一个KVM虚机在宿主机中其实是一个qemu-kvm进程,与其他Linux进程一样被调度。
比如,在我的实验机上运行的虚机kvm1在宿主机中ps能看到相应的进程,如图1-16所示。
图1-16
虚机中的每一个虚拟vCPU则对应qemu-kvm进程中的一个线程,如图1-17所示。
图1-17
在这个例子中,宿主机有两个物理CPU,上面起了两个虚机VM1和VM2。
VM1有两个vCPU,VM2有4个vCPU。可以看到VM1和VM2分别有两个和4个线程在两个物理CPU上调度。
这里也演示了另一个知识点,即虚机的vCPU总数可以超过物理CPU数量,这个叫CPU overcommit(超配)。
KVM允许overcommit,这个特性使得虚机能够充分利用宿主机的CPU资源,但前提是在同一时刻,不是所有的虚机都满负荷运行。
当然,如果每个虚机都很忙,反而会影响整体性能,所以在使用overcommit的时候,需要对虚机的负载情况有所了解,需要测试。
1.4.2 内存虚拟化
KVM通过内存虚拟化共享物理系统内存,动态分配给虚拟机,如图1-18所示。
图1-18
为了在一台机器上运行多个虚拟机,KVM需要实现VA(虚拟内存)→ PA(物理内存)→ MA(机器内存)之间的地址转换。虚机OS控制虚拟地址到客户内存物理地址的映射(VA →PA),但是虚机OS不能直接访问实际机器内存,因此KVM需要负责映射客户物理内存到实际机器内存(PA → MA)。具体的实现就不做过多介绍了,大家有兴趣可以查查资料。
还有一点提醒大家,内存也是可以overcommit的,即所有虚机的内存之和可以超过宿主机的物理内存。但使用时也需要充分测试,否则性能会受影响。
1.4.3 存储虚拟化
KVM的存储虚拟化是通过存储池(Storage Pool)和卷(Volume)来管理的。
Storage Pool是宿主机上可以看到的一片存储空间,可以是多种类型,后面会详细讨论。Volume是在Storage Pool中划分出的一块空间,宿主机将Volume分配给虚拟机,Volume在虚拟机中看到的就是一块硬盘。
下面我们学习不同类型的Storage Pool。
1.目录类型的Storage Pool
文件目录是最常用的Storage Pool类型。KVM将宿主机目录/var/lib/libvirt/images/作为默认的Storage Pool。
那么Volume是什么呢?
答案就是该目录下面的文件了,一个文件就是一个Volume。
大家是否还记得我们之前创建第一个虚机kvm1的时候,就是将镜像文件cirros-0.3.3-x86_64-disk.img放到了这个目录下。文件cirros-0.3.3-x86_64-disk.img也就是Volume,对于kvm1来说,就是它的启动磁盘了。如图1-19所示。
图1-19
那KVM是怎么知道要把/var/lib/libvirt/images目录当作默认Storage Pool的呢?
实际上KVM所有可以使用的Storage Pool都定义在宿主机的/etc/libvirt/storage目录下,每个Pool一个xml文件,默认有一个default.xml,其内容如图1-20所示。
图1-20
注意:Storage Pool的类型是“dir”,目录的路径就是/var/lib/libvirt/images。
下面我们为虚机kvm1添加一个新的磁盘,看看有什么变化。
在virt-manager中打开kvm1的配置页面,右键添加新硬件,如图1-21所示。
图1-21
在默认Pool中创建一个8GB的卷,如图1-22所示。
图1-22
单击“Finish”,可以看到新磁盘的信息,如图1-23所示。
图1-23
在/var/lib/libvirt/images/下多了一个8GB的文件kvm1.img:
root@ubuntu:~# ls -l /var/lib/libvirt/images/ total 14044 -rw-r--r-- 1 root root 14417920 Sep 4 11:24 cirros-0.3.3-x86_64-disk.img -rw------- 1 root root 8589934592 Sep 4 21:39 kvm1.img
使用文件做Volume有很多优点:存储方便、移植性好、可复制、可远程访问。
前面几个优点都很好理解,这里对“可远程访问”多解释一下。
远程访问的意思是镜像文件不一定都放置到宿主机本地文件系统中,也可以存储在通过网络连接的远程文件系统,比如NFS,或者是分布式文件系统中,比如GlusterFS。
这样镜像文件就可以在多个宿主机之间共享,便于虚机在不同宿主机之间做Live Migration;如果是分布式文件系统,多副本的特性还可以保证镜像文件的高可用。
KVM支持多种Volume文件格式,在添加Volume时可以选择,如图1-24所示。
图1-24
raw是默认格式,即原始磁盘镜像格式,移植性好,性能好,但大小固定,不能节省磁盘空间。
qcow2是推荐使用的格式,cow表示copy on write,能够节省磁盘空间,支持AES加密,支持zlib压缩,支持多快照,功能很多。
vmdk是VMWare的虚拟磁盘格式,也就是说VMWare虚机可以直接在KVM上运行。
下一节介绍LVM类型的Storage Pool。
2.LVM类型的Storage Pool
不仅一个文件可以分配给客户机作为虚拟磁盘,宿主机上VG中的LV也可以作为虚拟磁盘分配给虚拟机使用。
不过,LV由于没有磁盘的MBR引导记录,不能作为虚拟机的启动盘,只能作为数据盘使用。
这种配置下,宿主机上的VG就是一个Storage Pool,VG中的LV就是Volume。
LV的优点是有较好的性能;不足的地方是管理和移动性方面不如镜像文件,而且不能通过网络远程使用。
下面举个例子。
首先,在宿主机上创建了一个容量为10GB的VG,命名为HostVG,如图1-25所示。
图1-25
然后创建了一个Storage Pool的定义文件/etc/libvirt/storage/HostVG.xml,如图1-26所示。
图1-26
然后通过virsh命令创建新的Storage Pool“HostVG”,如图1-27所示。
图1-27
并启用这个HostVG,如图1-28所示。
图1-28
现在我们可以在virt-manager中为虚机kvm1添加LV的虚拟磁盘了。如图1-29所示。
图1-29
单击“Browse”,如图1-30所示。
图1-30
可以看到HostVG已经在Stroage Pool的列表中了,选择HostVG,如图1-31所示。
图1-31
单击“New Volume”,为volume命名为newlv,并设置大小100MB,如图1-32所示。
图1-32
单击“Finish”,newlv创建成功,如图1-33所示。
图1-33
单击“Choose Volume”,如图1-34所示。
图1-34
单击“Finish”,确认将newlv作为volume添加到kvm1,如图1-35所示。
图1-35
新volume添加成功。在宿主机上则多了一个命名为newlv的LV,如图1-36所示。
图1-36
3.其他类型的Storage Pool
KVM还支持iSCSI、Ceph等多种类型的Storage Pool,这里就不一一介绍了,最常用的就是目录类型,其他类型可以参考文档http://libvirt.org/storage.html。
下一节我们将开始讨论KVM的网络虚拟化原理。
1.5 网络虚拟化
网络虚拟化是虚拟化技术中最复杂的部分,学习难度最大。但因为网络是虚拟化中非常重要的资源,所以再硬的骨头也必须要把它啃下来。为了让大家对虚拟化网络的复杂程度有一个直观的认识,请看图1-37所示。
图1-37
这是OpenStack官网上给出的计算节点(可以理解为KVM的宿主机)虚拟网络的逻辑图,上面的网络设备很多,层次也很复杂,我第一次看到这张图,也着实被吓了一跳。
不过大家也不要怕,万丈高楼平地起,虚拟网络再复杂,也是由一些基础的组件构成的。只要我们将这些基础组件的概念和它们之间的逻辑关系搞清楚了,就能深刻理解虚拟网络的架构,那么云环境下的虚拟化网络也就不在话下了。
下面我们来学习网络虚拟化中最重要的两个东西:Linux Bridge和VLAN。
1.5.1 Linux Bridge
1.基本概念
假设宿主机有1块与外网连接的物理网卡eth0,上面跑了1个虚机VM1,现在有个问题是:
如何让VM1能够访问外网?
至少有两种方案:
(1)将物理网卡eth0直接分配给VM1。
但实施这个方案随之带来的问题很多:宿主机就没有网卡,无法访问了;新的虚机,比如VM2也没有网卡。
(2)给VM1分配一个虚拟网卡vnet0,通过Linux Bridge br0将eth0和vnet0连接起来,如图1-38所示。这个是我们推荐的方案。
图1-38
Linux Bridge是Linux上用来做TCP/IP二层协议交换的设备,其功能大家可以简单地理解为是一个二层交换机或者Hub。多个网络设备可以连接到同一个Linux Bridge,当某个设备收到数据包时,Linux Bridge会将数据转发给其他设备。
在上面这个例子中,当有数据到达eth0时,br0会将数据转发给vnet0,这样VM1就能接收到来自外网的数据。
反过来,VM1发送数据给vnet0,br0也会将数据转发到eth0,从而实现了VM1与外网的通信。
现在我们增加一个虚机VM2,如图1-39所示。
图1-39
VM2的虚拟网卡vnet1也连接到了br0上。现在VM1和VM2之间可以通信,同时VM1和VM2也都可以与外网通信。
有了上面的基础支持,下一节将演示如何在实验环境中实现这套虚拟网络。
2.动手实践虚拟网络
本节将演示如何在实验环境中实现如图1-40所示的虚拟网络。
图1-40
3.配置Linux Bridge br0
编辑/etc/network/interfaces,配置br0。
下面用vmdiff展示了对/etc/network/interfaces的修改,如图1-41所示。
图1-41
有两点需要注意:
- 之前宿主机的IP是通过dhcp配置在eth0上的;创建Linux Bridge之后,IP就必须放到br0上了。
- 在br0的配置信息中请注意最后一行bridge_ports eth0,其作用就是将eth0挂到br0上。
重启宿主机,查看IP配置,可以看到IP已经放到br0上了。
# ifconfig br0 Link encap:Ethernet HWaddr 00:0c:29:8d:ec:be inet addr:192.168.111.107 Bcast:192.168.111.255 Mask:255.255.255.0 inet6 addr: fe80::20c:29ff:fe8d:ecbe/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:22573 errors:0 dropped:0 overruns:0 frame:0 TX packets:2757 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:4927580 (4.9 MB) TX bytes:368895 (368.8 KB) eth0 Link encap:Ethernet HWaddr 00:0c:29:8d:ec:be inet6 addr: fe80::20c:29ff:fe8d:ecbe/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:24388 errors:0 dropped:0 overruns:0 frame:0 TX packets:2816 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:5590438 (5.5 MB) TX bytes:411558 (411.5 KB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:146 errors:0 dropped:0 overruns:0 frame:0 TX packets:146 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:10521 (10.5 KB) TX bytes:10521 (10.5 KB) virbr0 Link encap:Ethernet HWaddr 72:db:fb:f2:19:91 inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
用brctl show查看当前Linux Bridge的配置。eth0已经挂到br0上了。
# brctl show bridge name bridge id STP enabled interfaces br0 8000.000c298decbe no eth0 virbr0 8000.000000000000 yes
除了br0,大家应该注意到还有一个virbr0的Bridge,而且virbr0上已经配置了IP地址192.168.122.1。
virbr0的作用我们会在后面介绍。
在宿主机中,CloudMan(作者)已经提前创建好了虚机VM1和VM2,现在都处于关机状态。
# virsh list --all Id Name State ---------------------------------------------------- - VM1 shut off - VM2 shut off
4.配置VM1
下面我们在virt-manager中查看一下VM1的网卡配置,如图1-42所示。为了使大家能够熟练使用命令行工具virsh和图形工具virt-manager,CloudMan在演示的时候会同时用到它们,两个工具都很重要。
图1-42
可以看到虚拟网卡的source device,我们选择的是br0。
下面我们启动VM1,看会发生什么?
# virsh start VM1 Domain VM1 started # brctl show bridge name bridge id STP enabled interfaces br0 8000.000c298decbe no eth0 vnet0 virbr0 8000.000000000000 yes
brctl show告诉我们,br0下面添加了一个vnet0设备,通过virsh确认这就是VM1的虚拟网卡。
# virsh domiflist VM1 Interface Type Source Model MAC ------------------------------------------------------- vnet0 bridge br0 rtl8139 52:54:00:75:dd:1a
VM1的IP是DHCP获得的(设置静态IP当然也可以),通过virt-manager控制台登录VM1,查看IP。
# ifconfig eth0 Link encap:Ethernet HWaddr 52:54:00:75:dd:1a inet addr:192.168.111.106 Bcast:192.168.111.255 Mask:255.255.255.0 inet6 addr: fe80::5054:ff:fe75:dd1a/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:400 errors:0 dropped:0 overruns:0 frame:0 TX packets:101 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:41950 (41.9 KB) TX bytes:12583 (12.5 KB)
VM1通过DHCP拿到的IP是192.168.111.106,与宿主机(IP为192.168.111.107)是同一个网段。Ping一下外网。
root@VM1:~# ping www.baidu.com PING www.a.shifen.com (180.97.33.108) 56(84) bytes of data. 64 bytes from 180.97.33.108: icmpseq=1 ttl=53 time=34.9 ms 64 bytes from 180.97.33.108: icmpseq=2 ttl=53 time=36.2 ms 64 bytes from 180.97.33.108: icmpseq=3 ttl=53 time=38.8 ms
没问题,可以访问。
另外,在VM1中虚拟网卡是eth0,并不是vnet0。
vnet0是该虚拟网卡在宿主机中对应的设备名称,其类型是TAP设备,这里需要注意一下。
5.配置VM2
跟VM1一样,VM2的虚拟网卡也挂在br0上,启动VM2,查看网卡信息。
# virsh start VM2 Domain VM2 started # brctl show bridge name bridge id STP enabled interfaces br0 8000.000c298decbe no eth0 vnet0 vnet1 virbr0 8000.000000000000 yes
br0下面多了vnet1,通过virsh确认这就是VM2的虚拟网卡。
# virsh domiflist VM2 Interface Type Source Model MAC ------------------------------------------------------- vnet1 bridge br0 rtl8139 52:54:00:cf:33:a1
VM2通过DHCP拿到的IP是192.168.111.108,登录VM2,验证网络的连通性Ping VM1:
root@VM2:~# ping VM1 PING VM1 (192.168.111.106) 56(84) bytes of data. 64 bytes from 192.168.111.106: icmpseq=1 ttl=64 time=4.54 ms 64 bytes from 192.168.111.106: icmpseq=2 ttl=64 time=1.63 ms 64 bytes from 192.168.111.106: icmpseq=3 ttl=64 time=2.16 ms
Ping宿主机:
root@VM2:~# ping 192.168.111.107 PING 192.168.111.107 (192.168.111.107) 56(84) bytes of data. 64 bytes from 192.168.111.107: icmpseq=1 ttl=64 time=1.02 ms 64 bytes from 192.168.111.107: icmpseq=2 ttl=64 time=0.052 ms 64 bytes from 192.168.111.107: icmpseq=3 ttl=64 time=0.064 ms
Ping外网:
root@VM2:~# ping www.baidu.com PING www.a.shifen.com (180.97.33.107) 56(84) bytes of data. 64 bytes from 180.97.33.107: icmpseq=1 ttl=53 time=53.9 ms 64 bytes from 180.97.33.107: icmpseq=2 ttl=53 time=45.0 ms 64 bytes from 180.97.33.107: icmpseq=3 ttl=53 time=44.2 ms
可见,通过br0这个Linux Bridge,我们实现了VM1、VM2、宿主机和外网这四者之间的数据通信。
6.理解virbr0
virbr0是KVM默认创建的一个Bridge,其作用是为连接其上的虚机网卡提供NAT访问外网的功能。
virbr0默认分配了一个IP 192.168.122.1,并为连接其上的其他虚拟网卡提供DHCP服务。
下面我们演示如何使用virbr0。
在virt-manager打开VM1的配置界面,网卡Source device选择“default”,将VM1的网卡挂在virbr0上,如图1-43所示。
图1-43
启动VM1,brctl show可以查看到vnet0已经挂在了virbr0上。
# brctl show bridge name bridge id STP enabled interfaces br0 8000.000c298decbe no eth0 virbr0 8000.fe540075dd1a yes vnet0
用virsh命令确认vnet就是VM1的虚拟网卡。
# virsh domiflist VM1 Interface Type Source Model MAC ------------------------------------------------------- vnet0 network default rtl8139 52:54:00:75:dd:1a
virbr0使用dnsmasq提供DHCP服务,可以在宿主机中查看该进程信息。
# ps -elf|grep dnsmasq 5 S libvirt+ 2422 1 0 80 0 - 7054 poll_s 11:26 ? 00:00:00 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf
在/var/lib/libvirt/dnsmasq/目录下有一个default.leases文件,当VM1成功获得DHCP的IP后,可以在该文件中查看到相应的信息。
# cat /var/lib/libvirt/dnsmasq/default.leases
1441525677 52:54:00:75:dd:1a 192.168.122.6 ubuntu *
上面显示192.168.122.6已经分配给MAC地址为52:54:00:75:dd:1a的网卡,这正是vnet0的MAC。之后就可以使用该IP访问VM1了。
# ssh 192.168.122.6
root@192.168.122.6's password:
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.16.0-30-generic x86_64)
Last login: Sun Sep 6 01:30:23 2015
root@VM1:~# ifconfig
eth0 Link encap:Ethernet HWaddr 52:54:00:75:dd:1a
inet addr:192.168.122.6 Bcast:192.168.122.255
Mask:255.255.255.0
inet6 addr: fe80::5054:ff:fe75:dd1a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:61 errors:0 dropped:0 overruns:0 frame:0
TX packets:66 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:7453 (7.4 KB) TX bytes:8649 (8.6 KB)
Ping一下外网。
root@VM1:~# ping www.baidu.com PING www.a.shifen.com (180.97.33.107) 56(84) bytes of data. 64 bytes from 180.97.33.107: icmpseq=1 ttl=52 time=36.9 ms 64 bytes from 180.97.33.107: icmpseq=2 ttl=52 time=119 ms 64 bytes from 180.97.33.107: icmpseq=3 ttl=52 time=88.5 ms 64 bytes from 180.97.33.107: icmpseq=4 ttl=52 time=38.0 ms 64 bytes from 180.97.33.107: icmpseq=5 ttl=52 time=122 ms
没有问题,可以访问外网,说明NAT起作用了。
需要说明的是,使用NAT的虚机VM1可以访问外网,但外网无法直接访问VM1。
因为VM1发出的网络包源地址并不是192.168.122.6,而是被NAT替换为宿主机的IP地址了。
这个与使用br0不一样,在br0的情况下,VM1通过自己的IP直接与外网通信,不会经过NAT地址转换。
1.5.2 VLAN
1.基本概念
LAN表示Local Area Network,本地局域网,通常使用Hub和Switch来连接LAN中的计算机。
一般来说,两台计算机连入同一个Hub或者Switch时,它们就在同一个LAN中。
一个LAN表示一个广播域,其含义是:LAN中的所有成员都会收到任意一个成员发出的广播包。
VLAN表示Virtual LAN。一个带有VLAN功能的switch能够将自己的端口划分出多个LAN。
计算机发出的广播包可以被同一个LAN中其他计算机收到,但位于其他LAN的计算机则无法收到。
简单地说,VLAN将一个交换机分成了多个交换机,限制了广播的范围,在二层上将计算机隔离到不同的VLAN中。
比方说,有两组机器,Group A和B。我们想配置成Group A中的机器可以相互访问,Group B中的机器也可以相互访问,但是A和B中的机器无法互相访问。
一种方法是使用两个交换机,A和B分别接到一个交换机。
另一种方法是使用一个带VLAN功能的交换机,将A和B的机器分别放到不同的VLAN中。
请注意,VLAN的隔离是二层上的隔离,A和B无法相互访问指的是二层广播包(比如arp)无法跨越VLAN的边界。
但在三层上(比如IP)是可以通过路由器让A和B互通的。概念上一定要分清。
现在的交换机几乎都是支持VLAN的。
通常交换机的端口有两种配置模式:Access和Trunk,如图1-44所示。
图1-44
- Access口
这些端口被打上了VLAN的标签,表明该端口属于哪个VLAN。
不同VLAN用VLAN ID来区分,VLAN ID的范围是1~4096。
Access口都是直接与计算机网卡相连的,这样从该网卡出来的数据包流入Access口后,就会被打上了所在VLAN的标签。
Access口只能属于一个VLAN。
- Trunk口
假设有两个交换机A和B。
A上有VLAN1(红)、VLAN2(黄)、VLAN3(蓝);B上也有VLAN1、VLAN 2、VLAN 3。
那如何让A和B上相同VLAN之间能够通信呢?办法是将A和B连起来,而且连接A和B的端口要允许VLAN1、2、3三个VLAN的数据都能够通过。这样的端口就是Trunk口了。
VLAN1、2、3的数据包在通过Trunk口到达对方交换机的过程中始终带着自己的VLAN标签。
了解了VLAN的概念之后,我们来看KVM虚拟化环境下是如何实现VLAN的。还是先看图,如图1-45所示。
图1-45
eth0是宿主机上的物理网卡,有一个命名为eth0.10的子设备与之相连。
eth0.10就是VLAN设备了,其VLAN ID就是VLAN 10。
eth0.10挂在命名为brvlan10的Linux Bridge上,虚机VM1的虚拟网卡vent0也挂在brvlan10上。
这样的配置,其效果就是:
- 宿主机用软件实现了一个交换机(当然是虚拟的),上面定义了一个VLAN10。
- eth0.10,brvlan10和vnet0都分别接到VLAN10的Access口上。而eth0就是一个Trunk口。
- VM1通过vnet0发出来的数据包会被打上VLAN10的标签。
eth0.10的作用是:定义了VLAN10。
brvlan10的作用是:Bridge上的其他网络设备自动加入到VLAN10中。
我们再增加一个VLAN20,如图1-46所示。
图1-46
这样虚拟交换机就有两个VLAN了,VM1和VM2分别属于VLAN10和VLAN20。
对于新创建的虚机,只需要将其虚拟网卡放入相应的Bridge,就能控制其所属的VLAN。
VLAN设备总是以母子关系出现,母子设备之间是一对多的关系。
一个母设备(eth0)可以有多个子设备(eth0.10,eth0.20 ……),而一个子设备只有一个母设备。
下面我们来看如何在实验环境中实施和配置VLAN网络。
2.配置VLAN
编辑/etc/network/interfaces,配置eth0.10、brvlan10、eth0.20和brvlan20。
下面用vmdiff展示了对/etc/network/interfaces的修改,如图1-47所示。
图1-47
重启宿主机,ifconfig各个网络接口,如图1-48所示。
图1-48
用brctl show查看当前Linux Bridge的配置。
eth0.10和eth0.20分别挂在brvlan10和brvlan20上了,如图1-49所示。
图1-49
在宿主机中已经提前创建好了虚机VM1和VM2,现在都处于关机状态,如图1-50所示。
图1-50
3.配置VM1
在virt-manager中,将VM1的虚拟网卡挂到brvlan10上,如图1-51所示。
图1-51
启动VM1,如图1-52所示。
图1-52
查看Bridge,发现brvlan10已经连接了一个vnet0设备,如图1-53所示。
图1-53
通过virsh确认这就是VM1的虚拟网卡,如图1-54所示。
图1-54
4.配置VM2
类似的,将VM2的网卡挂在brvlan20上,如图1-55所示。
图1-55
启动VM2,如图1-56所示。
图1-56
查看Bridge,发现brvlan20已经连接了一个vnet1设备,如图1-57所示。
图1-57
通过virsh确认这就是VM2的虚拟网卡,如图1-58所示。
图1-58
5.验证VLAN的隔离性
为了验证VLAN10和VLAN20之间的隔离,我们为VM1和VM2配置同一网段的IP。
配置VM1的IP,如图1-59所示。
图1-59
配置VM2的IP,如图1-60所示。
图1-60
Ping测试结果:VM1与VM2是不通的,如图1-61所示。
图1-61
原因如下:
(1)VM2向VM1发Ping包之前,需要知道VM1的IP 192.168.100.10所对应的MAC地址。VM2会在网络上广播ARP包,其作用就是询问“谁知道192.168.100.10的MAC地址是多少?”
(2)ARP是二层协议,VLAN的隔离作用使得ARP只能在VLAN20范围内广播,只有brvlan20和eth0.20能收到,VLAN10里的设备是收不到的。VM1无法应答VM2发出的ARP包。
(3)VM2拿不到VM1 vnet0的MAC地址,也就Ping不到VM1。
1.5.3 Linux Bridge + VLAN =虚拟交换机
现在对KVM的网络虚拟化做个总结。
(1)物理交换机存在多个VLAN,每个VLAN拥有多个端口。
同一VLAN端口之间可以交换转发,不同VLAN端口之间隔离。所以交换机包含两层功能:交换与隔离。
(2)Linux的VLAN设备实现的是隔离功能,但没有交换功能。
一个VLAN母设备(比如eth0)不能拥有两个相同ID的VLAN子设备,因此也就不可能出现数据交换情况。
(3)Linux Bridge专门实现交换功能。
将同一VLAN的子设备都挂载到一个Bridge上,设备之间就可以交换数据了。
总结起来,Linux Bridge加VLAN在功能层面完整模拟现实世界里的二层交换机。
eth0相当于虚拟交换机上的trunk口,允许vlan10和vlan20的数据通过。
eth0.10,vnet0和brvlan10都可以看着vlan10的access口。
eth0.20,vnet1和brvlan20都可以看着vlan20的access口。