mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2026-05-10 19:54:28 +08:00
mod
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
<audio id="audio" title="第24讲 | 云中网络:自己拿地成本高,购买公寓更灵活" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/01/43/01c265bd1bb26282aa21e2e745fe0643.mp3"></audio>
|
||||
|
||||
前面我们讲了,数据中心里面堆着一大片一大片的机器,用网络连接起来,机器数目一旦非常多,人们就发现,维护这么一大片机器还挺麻烦的,有好多不灵活的地方。
|
||||
|
||||
<li>
|
||||
采购不灵活:如果客户需要一台电脑,那就需要自己采购、上架、插网线、安装操作系统,周期非常长。一旦采购了,一用就N年,不能退货,哪怕业务不做了,机器还在数据中心里留着。
|
||||
</li>
|
||||
<li>
|
||||
运维不灵活:一旦需要扩容CPU、内存、硬盘,都需要去机房手动弄,非常麻烦。
|
||||
</li>
|
||||
<li>
|
||||
规格不灵活:采购的机器往往动不动几百G的内存,而每个应用往往可能只需要4核8G,所以很多应用混合部署在上面,端口各种冲突,容易相互影响。
|
||||
</li>
|
||||
<li>
|
||||
复用不灵活:一台机器,一旦一个用户不用了,给另外一个用户,那就需要重装操作系统。因为原来的操作系统可能遗留很多数据,非常麻烦。
|
||||
</li>
|
||||
|
||||
## 从物理机到虚拟机
|
||||
|
||||
为了解决这些问题,人们发明了一种叫虚拟机的东西,并基于它产生了云计算技术。
|
||||
|
||||
其实在你的个人电脑上,就可以使用虚拟机。如果你对虚拟机没有什么概念,你可以下载一个桌面虚拟化的软件,自己动手尝试一下。它可以让你灵活地指定CPU的数目、内存的大小、硬盘的大小,可以有多个网卡,然后在一台笔记本电脑里面创建一台或者多台虚拟电脑。不用的时候,一点删除就没有了。
|
||||
|
||||
在数据中心里面,也有一种类似的开源技术qemu-kvm,能让你在一台巨大的物理机里面,掏出一台台小的机器。这套软件就能解决上面的问题:一点就能创建,一点就能销毁。你想要多大就有多大,每次创建的系统还都是新的。
|
||||
|
||||
**我们常把物理机比喻为自己拿地盖房子,而虚拟机则相当于购买公寓,更加灵活方面,随时可买可卖。** 那这个软件为什么能做到这些事儿呢?
|
||||
|
||||
它用的是**软件模拟硬件**的方式。刚才说了,数据中心里面用的qemu-kvm。从名字上来讲,emu就是Emulator(模拟器)的意思,主要会模拟CPU、内存、网络、硬盘,使得虚拟机感觉自己在使用独立的设备,但是真正使用的时候,当然还是使用物理的设备。
|
||||
|
||||
例如,多个虚拟机轮流使用物理CPU,内存也是使用虚拟内存映射的方式,最终映射到物理内存上。硬盘在一块大的文件系统上创建一个N个G的文件,作为虚拟机的硬盘。
|
||||
|
||||
简单比喻,虚拟化软件就像一个“骗子”,向上“骗”虚拟机里面的应用,让它们感觉独享资源,其实自己啥都没有,全部向下从物理机里面弄。
|
||||
|
||||
## 虚拟网卡的原理
|
||||
|
||||
那网络是如何“骗”应用的呢?如何将虚拟机的网络和物理机的网络连接起来?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/93/ca/93ec56f83d51c17f788c715a45c6bfca.jpeg" alt="">
|
||||
|
||||
首先,虚拟机要有一张网卡。对于qemu-kvm来说,这是通过Linux上的一种TUN/TAP技术来实现的。
|
||||
|
||||
虚拟机是物理机上跑着的一个软件。这个软件可以像其他应用打开文件一样,打开一个称为TUN/TAP的Char Dev(字符设备文件)。打开了这个字符设备文件之后,在物理机上就能看到一张虚拟TAP网卡。
|
||||
|
||||
虚拟化软件作为“骗子”,会将打开的这个文件,在虚拟机里面虚拟出一张网卡,让虚拟机里面的应用觉得它们真有一张网卡。于是,所有的网络包都往这里发。
|
||||
|
||||
当然,网络包会到虚拟化软件这里。它会将网络包转换成为文件流,写入字符设备,就像写一个文件一样。内核中TUN/TAP字符设备驱动会收到这个写入的文件流,交给TUN/TAP的虚拟网卡驱动。这个驱动将文件流再次转成网络包,交给TCP/IP协议栈,最终从虚拟TAP网卡发出来,成为标准的网络包。
|
||||
|
||||
就这样,几经转手,数据终于从虚拟机里面,发到了虚拟机外面。
|
||||
|
||||
## 虚拟网卡连接到云中
|
||||
|
||||
我们就这样有了虚拟TAP网卡。接下来就要看,这个卡怎么接入庞大的数据中心网络中。
|
||||
|
||||
在接入之前,我们先来看,云计算中的网络都需要注意哪些点。
|
||||
|
||||
<li>
|
||||
**共享**:尽管每个虚拟机都会有一个或者多个虚拟网卡,但是物理机上可能只有有限的网卡。那这么多虚拟网卡如何共享同一个出口?
|
||||
</li>
|
||||
<li>
|
||||
**隔离**:分两个方面,一个是安全隔离,两个虚拟机可能属于两个用户,那怎么保证一个用户的数据不被另一个用户窃听?一个是流量隔离,两个虚拟机,如果有一个疯狂下片,会不会导致另外一个上不了网?
|
||||
</li>
|
||||
<li>
|
||||
**互通**:分两个方面,一个是如果同一台机器上的两个虚拟机,属于同一个用户的话,这两个如何相互通信?另一个是如果不同物理机上的两个虚拟机,属于同一个用户的话,这两个如何相互通信?
|
||||
</li>
|
||||
<li>
|
||||
**灵活**:虚拟机和物理不同,会经常创建、删除,从一个机器漂移到另一台机器,有的互通、有的不通等等,灵活性比物理网络要好得多,需要能够灵活配置。
|
||||
</li>
|
||||
|
||||
### 共享与互通问题
|
||||
|
||||
这些问题,我们一个个来解决。
|
||||
|
||||
首先,一台物理机上有多个虚拟机,有多个虚拟网卡,这些虚拟网卡如何连在一起,进行相互访问,并且可以访问外网呢?
|
||||
|
||||
还记得我们在大学宿舍里做的事情吗?你可以想象你的物理机就是你们宿舍,虚拟机就是你的个人电脑,这些电脑应该怎么连接起来呢?当然应该买一个交换机。
|
||||
|
||||
在物理机上,应该有一个虚拟的交换机,在Linux上有一个命令叫作brctl,可以创建虚拟的网桥brctl addbr br0。创建出来以后,将两个虚拟机的虚拟网卡,都连接到虚拟网桥brctl addif br0 tap0上,这样将两个虚拟机配置相同的子网网段,两台虚拟机就能够相互通信了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/79/f1/793469d10d57b4845d5678c266a9a6f1.jpeg" alt="">
|
||||
|
||||
那这些虚拟机如何连接外网呢?在桌面虚拟化软件上面,我们能看到以下选项。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ee/24/ee3424547c32433e04fb174fdbaa9924.jpg" alt="">
|
||||
|
||||
这里面,host-only的网络对应的,其实就是上面两个虚拟机连到一个br0虚拟网桥上,而且不考虑访问外部的场景,只要虚拟机之间能够相互访问就可以了。
|
||||
|
||||
如果要访问外部,往往有两种方式。
|
||||
|
||||
一种方式称为**桥接**。如果在桌面虚拟化软件上选择桥接网络,则在你的笔记本电脑上,就会形成下面的结构。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/64/d4/64d80d328f318b90d8d83a584138ffd4.jpeg" alt="">
|
||||
|
||||
每个虚拟机都会有虚拟网卡,在你的笔记本电脑上,会发现多了几个网卡,其实是虚拟交换机。这个虚拟交换机将虚拟机连接在一起。在桥接模式下,物理网卡也连接到这个虚拟交换机上,物理网卡在桌面虚拟化软件上,在“界面名称”那里选定。
|
||||
|
||||
如果使用桥接网络,当你登录虚拟机里看IP地址的时候会发现,你的虚拟机的地址和你的笔记本电脑的,以及你旁边的同事的电脑的网段是一个网段。这是为什么呢?这其实相当于将物理机和虚拟机放在同一个网桥上,相当于这个网桥上有三台机器,是一个网段的,全部打平了。我将图画成下面的样子你就好理解了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f9/e3/f90500a85292a466df2dd4e6cab1e2e3.jpeg" alt="">
|
||||
|
||||
在数据中心里面,采取的也是类似的技术,只不过都是Linux,在每台机器上都创建网桥br0,虚拟机的网卡都连到br0上,物理网卡也连到br0上,所有的br0都通过物理网卡出来连接到物理交换机上。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/44/44/44d70c3de1258337af8b352c767bb044.jpeg" alt="">
|
||||
|
||||
同样我们换一个角度看待这个拓扑图。同样是将网络打平,虚拟机会和你的物理网络具有相同的网段。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/03/30/03e8e31978040de9ffcb21413bb0f830.jpeg" alt="">
|
||||
|
||||
在这种方式下,不但解决了同一台机器的互通问题,也解决了跨物理机的互通问题,因为都在一个二层网络里面,彼此用相同的网段访问就可以了。但是当规模很大的时候,会存在问题。
|
||||
|
||||
你还记得吗?在一个二层网络里面,最大的问题是广播。一个数据中心的物理机已经很多了,广播已经非常严重,需要通过VLAN进行划分。如果使用了虚拟机,假设一台物理机里面创建10台虚拟机,全部在一个二层网络里面,那广播就会很严重,所以除非是你的桌面虚拟机或者数据中心规模非常小,才可以使用这种相对简单的方式。
|
||||
|
||||
另外一种方式称为**NAT**。如果在桌面虚拟化软件中使用NAT模式,在你的笔记本电脑上会出现如下的网络结构。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2e/41/2e959deab0e3e3a5c183033bf108eb41.jpeg" alt="">
|
||||
|
||||
在这种方式下,你登录到虚拟机里面查看IP地址,会发现虚拟机的网络是虚拟机的,物理机的网络是物理机的,两个不相同。虚拟机要想访问物理机的时候,需要将地址NAT成为物理机的地址。
|
||||
|
||||
除此之外,它还会在你的笔记本电脑里内置一个DHCP服务器,为笔记本电脑上的虚拟机动态分配IP地址。因为虚拟机的网络自成体系,需要进行IP管理。为什么桥接方式不需要呢?因为桥接将网络打平了,虚拟机的IP地址应该由物理网络的DHCP服务器分配。
|
||||
|
||||
在数据中心里面,也是使用类似的方式。这种方式更像是真的将你宿舍里面的情况,搬到一台物理机上来。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a3/2a/a37a80a624d8acee6f2cd8e41571972a.jpeg" alt="">
|
||||
|
||||
虚拟机是你的电脑,路由器和DHCP Server相当于家用路由器或者寝室长的电脑,物理网卡相当于你们宿舍的外网网口,用于访问互联网。所有电脑都通过内网网口连接到一个网桥br0上,虚拟机要想访问互联网,需要通过br0连到路由器上,然后通过路由器将请求NAT成为物理网络的地址,转发到物理网络。
|
||||
|
||||
如果是你自己登录到物理机上做个简单配置,你可以简化一下。例如将虚拟机所在网络的网关的地址直接配置到br0上,不用DHCP Server,手动配置每台虚拟机的IP地址,通过命令iptables -t nat -A POSTROUTING -o ethX -j MASQUERADE,直接在物理网卡ethX上进行NAT,所有从这个网卡出去的包都NAT成这个网卡的地址。通过设置net.ipv4.ip_forward = 1,开启物理机的转发功能,直接做路由器,而不用单独的路由器,这样虚拟机就能直接上网了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8f/72/8f4f531e929b196bff0fc2eaba7a9172.jpeg" alt="">
|
||||
|
||||
### 隔离问题
|
||||
|
||||
解决了互通的问题,接下来就是隔离的问题。
|
||||
|
||||
如果一台机器上的两个虚拟机不属于同一个用户,怎么办呢?好在brctl创建的网桥也是支持VLAN功能的,可以设置两个虚拟机的tag,这样在这个虚拟网桥上,两个虚拟机是不互通的。
|
||||
|
||||
但是如何跨物理机互通,并且实现VLAN的隔离呢?由于brctl创建的网桥上面的tag是没办法在网桥之外的范围内起作用的,因此我们需要寻找其他的方式。
|
||||
|
||||
有一个命令**vconfig**,可以基于物理网卡eth0创建带VLAN的虚拟网卡,所有从这个虚拟网卡出去的包,都带这个VLAN,如果这样,跨物理机的互通和隔离就可以通过这个网卡来实现。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4b/12/4b6aa2b970ac285be94c3af082153912.jpg" alt="">
|
||||
|
||||
首先为每个用户分配不同的VLAN,例如有一个用户VLAN 10,一个用户VLAN 20。在一台物理机上,基于物理网卡,为每个用户用vconfig创建一个带VLAN的网卡。不同的用户使用不同的虚拟网桥,带VLAN的虚拟网卡也连接到虚拟网桥上。
|
||||
|
||||
这样是否能保证两个用户的隔离性呢?不同的用户由于网桥不通,不能相互通信,一旦出了网桥,由于VLAN不同,也不会将包转发到另一个网桥上。另外,出了物理机,也是带着VLAN ID的。只要物理交换机也是支持VLAN的,到达另一台物理机的时候,VLAN ID依然在,它只会将包转发给相同VLAN的网卡和网桥,所以跨物理机,不同的VLAN也不会相互通信。
|
||||
|
||||
使用brctl创建出来的网桥功能是简单的,基于VLAN的虚拟网卡也能实现简单的隔离。但是这都不是大规模云平台能够满足的,一个是VLAN的隔离,数目太少。前面我们学过,VLAN ID只有4096个,明显不够用。另外一点是这个配置不够灵活。谁和谁通,谁和谁不通,流量的隔离也没有实现,还有大量改进的空间。
|
||||
|
||||
## 小结
|
||||
|
||||
好了,这一节就到这里了,我们来总结一下:
|
||||
|
||||
<li>
|
||||
云计算的关键技术是虚拟化,这里我们重点关注的是,虚拟网卡通过打开TUN/TAP字符设备的方式,将虚拟机内外连接起来;
|
||||
</li>
|
||||
<li>
|
||||
云中的网络重点关注四个方面,共享、隔离、互通、灵活。其中共享和互通有两种常用的方式,分别是桥接和NAT,隔离可以通过VLAN的方式。
|
||||
</li>
|
||||
|
||||
接下来,给你留两个思考题。
|
||||
|
||||
<li>
|
||||
为了直观,这一节的内容我们以桌面虚拟化系统举例。在数据中心里面,有一款著名的开源软件OpenStack,这一节讲的网络连通方式对应OpenStack中的哪些模型呢?
|
||||
</li>
|
||||
<li>
|
||||
这一节的最后,我们也提到了,本节提到的网络配置方式比较不灵活,你知道什么更加灵活的方式吗?
|
||||
</li>
|
||||
|
||||
我们的专栏更新到第24讲,不知你掌握得如何?每节课后我留的思考题,你都有没有认真思考,并在留言区写下答案呢?我会从**已发布的文章中选出一批认真留言的同学**,赠送学习奖励礼券和我整理的独家网络协议知识图谱。
|
||||
|
||||
欢迎你留言和我讨论。趣谈网络协议,我们下期见!
|
||||
@@ -0,0 +1,303 @@
|
||||
<audio id="audio" title="第25讲 | 软件定义网络:共享基础设施的小区物业管理办法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4c/b5/4c8f54c1d5ce1b83f305a3b603d6fcb5.mp3"></audio>
|
||||
|
||||
上一节我们说到,使用原生的VLAN和Linux网桥的方式来进行云平台的管理,但是这样在灵活性、隔离性方面都显得不足,而且整个网络缺少统一的视图、统一的管理。
|
||||
|
||||
可以这样比喻,云计算就像大家一起住公寓,要共享小区里面的基础设施,其中网络就相当于小区里面的电梯、楼道、路、大门等,大家都走,往往会常出现问题,尤其在上班高峰期,出门的人太多,对小区的物业管理就带来了挑战。
|
||||
|
||||
物业可以派自己的物业管理人员,到每个单元的楼梯那里,将电梯的上下行速度调快一点,可以派人将隔离健身区、景色区的栅栏门暂时打开,让大家可以横穿小区,直接上地铁,还可以派人将多个小区出入口,改成出口多、入口少等等。等过了十点半,上班高峰过去,再派人都改回来。
|
||||
|
||||
## 软件定义网络(SDN)
|
||||
|
||||
这种模式就像传统的网络设备和普通的Linux网桥的模式,配置整个云平台的网络通路,你需要登录到这台机器上配置这个,再登录到另外一个设备配置那个,才能成功。
|
||||
|
||||
如果物业管理人员有一套智能的控制系统,在物业监控室里就能看到小区里每个单元、每个电梯的人流情况,然后在监控室里面,只要通过远程控制的方式,拨弄一个手柄,电梯的速度就调整了,栅栏门就打开了,某个入口就改出口了。
|
||||
|
||||
这就是软件定义网络(SDN)。它主要有以下三个特点。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/34/f9/346fe3b3dbe1024e7119ec4ffa9377f9.jpg" alt="">
|
||||
|
||||
<li>
|
||||
**控制与转发分离**:转发平面就是一个个虚拟或者物理的网络设备,就像小区里面的一条条路。控制平面就是统一的控制中心,就像小区物业的监控室。它们原来是一起的,物业管理员要从监控室出来,到路上去管理设备,现在是分离的,路就是走人的,控制都在监控室。
|
||||
</li>
|
||||
<li>
|
||||
**控制平面与转发平面之间的开放接口**:控制器向上提供接口,被应用层调用,就像总控室提供按钮,让物业管理员使用。控制器向下调用接口,来控制网络设备,就像总控室会远程控制电梯的速度。这里经常使用两个名词,前面这个接口称为**北向接口**,后面这个接口称为**南向接口**,上北下南嘛。
|
||||
</li>
|
||||
<li>
|
||||
**逻辑上的集中控制**:逻辑上集中的控制平面可以控制多个转发面设备,也就是控制整个物理网络,因而可以获得全局的网络状态视图,并根据该全局网络状态视图实现对网络的优化控制,就像物业管理员在监控室能够看到整个小区的情况,并根据情况优化出入方案。
|
||||
</li>
|
||||
|
||||
## OpenFlow和OpenvSwitch
|
||||
|
||||
SDN有很多种实现方式,我们来看一种开源的实现方式。
|
||||
|
||||
OpenFlow是SDN控制器和网络设备之间互通的南向接口协议,OpenvSwitch用于创建软件的虚拟交换机。OpenvSwitch是支持OpenFlow协议的,当然也有一些硬件交换机也支持OpenFlow协议。它们都可以被统一的SDN控制器管理,从而实现物理机和虚拟机的网络连通。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/22/15/220b53c0f027763yy54c1a08yy2e5a15.jpg" alt="">
|
||||
|
||||
SDN控制器是如何通过OpenFlow协议控制网络的呢?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/1c/78/1c739b9ecc23e9b7c246136782fcd078.jpg" alt="">
|
||||
|
||||
在OpenvSwitch里面,有一个流表规则,任何通过这个交换机的包,都会经过这些规则进行处理,从而接收、转发、放弃。
|
||||
|
||||
那流表长啥样呢?其实就是一个个表格,每个表格好多行,每行都是一条规则。每条规则都有优先级,先看高优先级的规则,再看低优先级的规则。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/31/2f/314c82553a164444437b25b215fa012f.jpg" alt="">
|
||||
|
||||
对于每一条规则,要看是否满足匹配条件。这些条件包括,从哪个端口进来的,网络包头里面有什么等等。满足了条件的网络包,就要执行一个动作,对这个网络包进行处理。可以修改包头里的内容,可以跳到任何一个表格,可以转发到某个网口出去,也可以丢弃。
|
||||
|
||||
通过这些表格,可以对收到的网络包随意处理。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8e/1a/8e8751005253a47a823f08d6ac6cfc1a.jpg" alt="">
|
||||
|
||||
具体都能做什么处理呢?通过上面的表格可以看出,简直是想怎么处理怎么处理,可以覆盖TCP/IP协议栈的四层。
|
||||
|
||||
对于物理层:
|
||||
|
||||
<li>
|
||||
匹配规则包括从哪个口进来;
|
||||
</li>
|
||||
<li>
|
||||
执行动作包括从哪个口出去。
|
||||
</li>
|
||||
|
||||
对于MAC层:
|
||||
|
||||
<li>
|
||||
匹配规则包括:源MAC地址是多少?(dl_src),目标MAC是多少?(dl_dst),所属vlan是多少?(dl_vlan);
|
||||
</li>
|
||||
<li>
|
||||
执行动作包括:修改源MAC(mod_dl_src),修改目标MAC(mod_dl_dst),修改VLAN(mod_vlan_vid),删除VLAN(strip_vlan),MAC地址学习(learn)。
|
||||
</li>
|
||||
|
||||
对于网络层:
|
||||
|
||||
<li>
|
||||
匹配规则包括:源IP地址是多少?(nw_src),目标IP是多少?(nw_dst)。
|
||||
</li>
|
||||
<li>
|
||||
执行动作包括:修改源IP地址(mod_nw_src),修改目标IP地址(mod_nw_dst)。
|
||||
</li>
|
||||
|
||||
对于传输层:
|
||||
|
||||
<li>
|
||||
匹配规则包括:源端口是多少?(tp_src),目标端口是多少?(tp_dst)。
|
||||
</li>
|
||||
<li>
|
||||
执行动作包括:修改源端口(mod_tp_src),修改目标端口(mod_tp_dst)。
|
||||
</li>
|
||||
|
||||
总而言之,对于OpenvSwitch来讲,网络包到了我手里,就是一个Buffer,我想怎么改怎么改,想发到哪个端口就发送到哪个端口。
|
||||
|
||||
OpenvSwitch有本地的命令行可以进行配置,能够实验咱们前面讲过的一些功能。我们可以通过OpenvSwitch的命令创建一个虚拟交换机。然后可以将多个虚拟端口port添加到这个虚拟交换机上。
|
||||
|
||||
```
|
||||
ovs-vsctl add-br ubuntu_br
|
||||
|
||||
```
|
||||
|
||||
## 实验一:用OpenvSwitch实现VLAN的功能
|
||||
|
||||
下面我们实验一下通过OpenvSwitch实现VLAN的功能,在OpenvSwitch中端口port分两种。
|
||||
|
||||
第一类是access port:
|
||||
|
||||
<li>
|
||||
这个端口配置tag,从这个端口进来的包会被打上这个tag;
|
||||
</li>
|
||||
<li>
|
||||
如果网络包本身带有的VLAN ID等于tag,则会从这个port发出;
|
||||
</li>
|
||||
<li>
|
||||
从access port发出的包不带VLAN ID。
|
||||
</li>
|
||||
|
||||
第二类是trunk port:
|
||||
|
||||
<li>
|
||||
这个port不配置tag,配置trunks;
|
||||
</li>
|
||||
<li>
|
||||
如果trunks为空,则所有的VLAN都trunk,也就意味着对于所有VLAN的包,本身带什么VLAN ID,就是携带着什么VLAN ID,如果没有设置VLAN,就属于VLAN 0,全部允许通过;
|
||||
</li>
|
||||
<li>
|
||||
如果trunks不为空,则仅仅带着这些VLAN ID的包通过。
|
||||
</li>
|
||||
|
||||
我们通过以下命令创建如下的环境:
|
||||
|
||||
```
|
||||
ovs-vsctl add-port ubuntu_br first_br
|
||||
ovs-vsctl add-port ubuntu_br second_br
|
||||
ovs-vsctl add-port ubuntu_br third_br
|
||||
ovs-vsctl set Port vnet0 tag=101
|
||||
ovs-vsctl set Port vnet1 tag=102
|
||||
ovs-vsctl set Port vnet2 tag=103
|
||||
ovs-vsctl set Port first_br tag=103
|
||||
ovs-vsctl clear Port second_br tag
|
||||
ovs-vsctl set Port third_br trunks=101,102
|
||||
|
||||
```
|
||||
|
||||
另外要配置禁止MAC地址学习。
|
||||
|
||||
```
|
||||
ovs-vsctl set bridge ubuntu_br flood-vlans=101,102,103
|
||||
|
||||
```
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8f/08/8ffb2a94ae0393f1785f8fefd5ea5908.jpg" alt="">
|
||||
|
||||
创建好了环境以后,我们来做这个实验。
|
||||
|
||||
<li>
|
||||
从192.168.100.102来ping 192.168.100.103,然后用tcpdump进行抓包。first_if收到包了,从first_br出来的包头是没有VLAN ID的。second_if也收到包了,由于second_br是trunk port,因而出来的包头是有VLAN ID的,third_if收不到包。
|
||||
</li>
|
||||
<li>
|
||||
从192.168.100.100来ping 192.168.100.105, 则second_if和third_if可以收到包,当然ping不通,因为third_if不属于某个VLAN。first_if是收不到包的。second_if能够收到包,而且包头里面是VLAN ID=101。third_if也能收到包,而且包头里面是VLAN ID=101。
|
||||
</li>
|
||||
<li>
|
||||
从192.168.100.101来ping 192.168.100.104, 则second_if和third_if可以收到包。first_if是收不到包的。second_br能够收到包,而且包头里面是VLAN ID=102。third_if也能收到包,而且包头里面是VLAN ID=102。
|
||||
</li>
|
||||
|
||||
通过这个例子,我们可以看到,通过OpenvSwitch,不用买一个支持VLAN的交换机,你也能学习VLAN的工作模式了。
|
||||
|
||||
## 实验二:用OpenvSwitch模拟网卡绑定,连接交换机
|
||||
|
||||
接下来,我们来做另一个实验。在前面,我们还说过,为了高可用,可以使用网卡绑定,连接到交换机,OpenvSwitch也可以模拟这一点。
|
||||
|
||||
在OpenvSwitch里面,有个bond_mode,可以设置为以下三个值:
|
||||
|
||||
<li>
|
||||
active-backup:一个连接是active,其他的是backup,当active失效的时候,backup顶上;
|
||||
</li>
|
||||
<li>
|
||||
balance-slb:流量安装源MAC和output VLAN进行负载均衡;
|
||||
</li>
|
||||
<li>
|
||||
balance-tcp:必须在支持LACP协议的情况下才可以,可根据L2, L3, L4进行负载均衡。
|
||||
</li>
|
||||
|
||||
我们搭建一个测试环境。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d2/ce/d2381bd12ab8620c64249f05fd7d19ce.jpg" alt="">
|
||||
|
||||
我们使用下面的命令,建立bond连接。
|
||||
|
||||
```
|
||||
ovs-vsctl add-bond br0 bond0 first_br second_br
|
||||
ovs-vsctl add-bond br1 bond1 first_if second_if
|
||||
ovs-vsctl set Port bond0 lacp=active
|
||||
ovs-vsctl set Port bond1 lacp=active
|
||||
|
||||
```
|
||||
|
||||
默认情况下bond_mode是active-backup模式,一开始active的是first_br和first_if。
|
||||
|
||||
这个时候我们从192.168.100.100 ping 192.168.100.102,以及从192.168.100.101 ping 192.168.100.103的时候,tcpdump可以看到所有的包都是从first_if通过。
|
||||
|
||||
如果把first_if设成down,则包的走向会变,发现second_if开始有流量,对于192.168.100.100和192.168.100.101似乎没有收到影响。
|
||||
|
||||
如果我们通过以下命令,把bond_mode设为balance-slb。然后我们同时在192.168.100.100 ping 192.168.100.102,在192.168.100.101 ping 192.168.100.103,我们通过tcpdump发现包已经被分流了。
|
||||
|
||||
```
|
||||
ovs-vsctl set Port bond0 bond_mode=balance-slb
|
||||
ovs-vsctl set Port bond1 bond_mode=balance-slb
|
||||
|
||||
```
|
||||
|
||||
通过这个例子,我们可以看到,通过OpenvSwitch,你不用买两台支持bond的交换机,也能看到bond的效果。
|
||||
|
||||
那OpenvSwitch是怎么做到这些的呢?我们来看OpenvSwitch的架构图。
|
||||
|
||||
OpenvSwitch包含很多的模块,在用户态有两个重要的进程,也有两个重要的命令行工具。
|
||||
|
||||
<li>
|
||||
第一个进程是OVSDB进程。ovs-vsctl命令行会和这个进程通信,去创建虚拟交换机,创建端口,将端口添加到虚拟交换机上,OVSDB会将这些拓扑信息保存在一个本地的文件中。
|
||||
</li>
|
||||
<li>
|
||||
第一个进程是vswitchd进程。ovs-ofctl命令行会和这个进程通信,去下发流表规则,规则里面会规定如何对网络包进行处理,vswitchd会将流表放在用户态Flow Table中。
|
||||
</li>
|
||||
|
||||
在内核态,OpenvSwitch有内核模块OpenvSwitch.ko,对应图中的Datapath部分。在网卡上注册一个函数,每当有网络包到达网卡的时候,这个函数就会被调用。
|
||||
|
||||
在内核的这个函数里面,会拿到网络包,将各个层次的重要信息拿出来,例如:
|
||||
|
||||
<li>
|
||||
在物理层,in_port即包进入的网口的ID;
|
||||
</li>
|
||||
<li>
|
||||
在MAC层,源和目的MAC地址;
|
||||
</li>
|
||||
<li>
|
||||
在IP层,源和目的IP地址;
|
||||
</li>
|
||||
<li>
|
||||
在传输层,源和目的端口号。
|
||||
</li>
|
||||
|
||||
在内核中,有一个内核态Flow Table。接下来内核模块在这个内核流表中匹配规则,如果匹配上了,则执行操作、修改包,或者转发或者放弃。如果内核没有匹配上,则需要进入用户态,用户态和内核态之间通过Linux的一个机制Netlink相互通信。
|
||||
|
||||
内核通过upcall,告知用户态进程vswitchd在用户态Flow Table里面去匹配规则,这里面的规则是全量的流表规则,而内核Flow Table里面的只是为了快速处理,保留了部分规则,内核里面的规则过一阵就会过期。
|
||||
|
||||
当在用户态匹配到了流表规则之后,就在用户态执行操作,同时将这个匹配成功的流表通过reinject下发到内核,从而接下来的包都能在内核找到这个规则。
|
||||
|
||||
这里调用openflow协议的,是本地的命令行工具,也可以是远程的SDN控制器,一个重要的SDN控制器是OpenDaylight。
|
||||
|
||||
下面这个图就是OpenDaylight中看到的拓扑图。是不是有种物业管理员在监控室里的感觉?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/27/a8/274442ba251fdc63c88bc5dbfc6183a8.jpg" alt="">
|
||||
|
||||
我们可以通过在OpenDaylight里,将两个交换机之间配置通,也可以配置不通,还可以配置一个虚拟IP地址VIP,在不同的机器之间实现负载均衡等等,所有的策略都可以灵活配置。
|
||||
|
||||
## 如何在云计算中使用OpenvSwitch?
|
||||
|
||||
OpenvSwitch这么牛,如何用在云计算中呢?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/10/e5/102a3c46c36047498139d8bcbd7551e5.jpg" alt="">
|
||||
|
||||
我们还是讨论VLAN的场景。
|
||||
|
||||
在没有OpenvSwitch的时候,如果一个新的用户要使用一个新的VLAN,还需要创建一个属于新的VLAN的虚拟网卡,并且为这个租户创建一个单独的虚拟网桥,这样用户越来越多的时候,虚拟网卡和虚拟网桥会越来越多,管理非常复杂。
|
||||
|
||||
另一个问题是虚拟机的VLAN和物理环境的VLAN是透传的,也即从一开始规划的时候,就需要匹配起来,将物理环境和虚拟环境强绑定,本来就不灵活。
|
||||
|
||||
而引入了OpenvSwitch,状态就得到了改观。
|
||||
|
||||
首先,由于OpenvSwitch本身就是支持VLAN的,所有的虚拟机都可以放在一个网桥br0上,通过不同的用户配置不同的tag,就能够实现隔离。例如上面的图,用户A的虚拟机都在br0上,用户B的虚拟机都在br1上,有了OpenvSwitch,就可以都放在br0上,只是设置了不同的tag。
|
||||
|
||||
另外,还可以创建一个虚拟交换机br1,将物理网络和虚拟网络进行隔离。物理网络有物理网络的VLAN规划,虚拟机在一台物理机上,所有的VLAN都是从1开始的。由于一台机器上的虚拟机不会超过4096个,所以VLAN在一台物理机上如果从1开始,肯定够用了。
|
||||
|
||||
例如在图中,上面的物理机里面,用户A被分配的tag是1,用户B被分配的tag是2,而在下面的物理机里面,用户A被分配的tag是7,用户B被分配的tag是6。
|
||||
|
||||
如果物理机之间的通信和隔离还是通过VLAN的话,需要将虚拟机的VLAN和物理环境的VLAN对应起来,但为了灵活性,不一定一致,这样可以实现分别管理物理机的网络和虚拟机的网络。好在OpenvSwitch可以对包的内容进行修改。例如通过匹配dl_vlan,然后执行mod_vlan_vid来改进进出出物理机的网络包。
|
||||
|
||||
尽管租户多了,物理环境的VLAN还是不够用,但是有了OpenvSwitch的映射,将物理和虚拟解耦,从而可以让物理环境使用其他技术,而不影响虚拟机环境,这个我们后面再讲。
|
||||
|
||||
## 小结
|
||||
|
||||
好了,这一节就到这里了,我们来总结一下:
|
||||
|
||||
<li>
|
||||
用SDN控制整个云里面的网络,就像小区保安从总控室管理整个物业是一样的,将控制面和数据面进行了分离;
|
||||
</li>
|
||||
<li>
|
||||
一种开源的虚拟交换机的实现OpenvSwitch,它能对经过自己的包做任意修改,从而使得云对网络的控制十分灵活;
|
||||
</li>
|
||||
<li>
|
||||
将OpenvSwitch引入了云之后,可以使得配置简单而灵活,并且可以解耦物理网络和虚拟网络。
|
||||
</li>
|
||||
|
||||
最后,给你留两个思考题:
|
||||
|
||||
<li>
|
||||
在这一节中,提到了通过VIP可以通过流表在不同的机器之间实现复杂均衡,你知道怎样才能做到吗?
|
||||
</li>
|
||||
<li>
|
||||
虽然OpenvSwitch可以解耦物理网络和虚拟网络,但是在物理网络里面使用VLAN,数目还是不够,你知道该怎么办吗?
|
||||
</li>
|
||||
|
||||
我们的专栏更新到第25讲,不知你掌握得如何?每节课后我留的思考题,你都有没有认真思考,并在留言区写下答案呢?我会从**已发布的文章中选出一批认真留言的同学**,赠送学习奖励礼券和我整理的独家网络协议知识图谱。
|
||||
|
||||
欢迎你留言和我讨论。趣谈网络协议,我们下期见!
|
||||
@@ -0,0 +1,220 @@
|
||||
<audio id="audio" title="第26讲 | 云中的网络安全:虽然不是土豪,也需要基本安全和保障" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/54/7e/543080b04cde38e3a36987e3bb026f7e.mp3"></audio>
|
||||
|
||||
在今天的内容开始之前,我先卖个关子。文章结尾,我会放一个超级彩蛋,所以,今天的内容你一定要看到最后哦!
|
||||
|
||||
上一节我们看到,做一个小区物业维护一个大家共享的环境,还是挺不容易的。如果都是自觉遵守规则的住户那还好,如果遇上不自觉的住户就会很麻烦。
|
||||
|
||||
就像公有云的环境,其实没有你想的那么纯净,各怀鬼胎的黑客到处都是。扫描你的端口呀,探测一下你启动的什么应用啊,看一看是否有各种漏洞啊。这就像小偷潜入小区后,这儿看看,那儿瞧瞧,窗户有没有关严了啊,窗帘有没有拉上啊,主人睡了没,是不是时机潜入室内啊,等等。
|
||||
|
||||
假如你创建了一台虚拟机,里面明明跑了一个电商应用,这是你非常重要的一个应用,你会把它进行安全加固。这台虚拟机的操作系统里,不小心安装了另外一个后台应用,监听着一个端口,而你的警觉性没有这么高。
|
||||
|
||||
虚拟机的这个端口是对着公网开放的,碰巧这个后台应用本身是有漏洞的,黑客就可以扫描到这个端口,然后通过这个后台应用的端口侵入你的机器,将你加固好的电商网站黑掉。这就像你买了一个五星级的防盗门,卡车都撞不开,但是厕所窗户的门把手是坏的,小偷从厕所里面就进来了。
|
||||
|
||||
所以**对于公有云上的虚拟机,我的建议是仅仅开放需要的端口,而将其他的端口一概关闭。这个时候,你只要通过安全措施守护好这个唯一的入口就可以了**。采用的方式常常是用**ACL**(Access Control List,访问控制列表)来控制IP和端口。
|
||||
|
||||
设置好了这些规则,只有指定的IP段能够访问指定的开放接口,就算有个有漏洞的后台进程在那里,也会被屏蔽,黑客进不来。在云平台上,这些规则的集合常称为**安全组**。那安全组怎么实现呢?
|
||||
|
||||
我们来复习一下,当一个网络包进入一台机器的时候,都会做什么事情。
|
||||
|
||||
首先拿下MAC头看看,是不是我的。如果是,则拿下IP头来。得到目标IP之后呢,就开始进行路由判断。在路由判断之前,这个节点我们称为**PREROUTING**。如果发现IP是我的,包就应该是我的,就发给上面的传输层,这个节点叫作**INPUT**。如果发现IP不是我的,就需要转发出去,这个节点称为**FORWARD**。如果是我的,上层处理完毕后,一般会返回一个处理结果,这个处理结果会发出去,这个节点称为**OUTPUT**,无论是FORWARD还是OUTPUT,都是路由判断之后发生的,最后一个节点是**POSTROUTING**。
|
||||
|
||||
整个过程如图所示。
|
||||
|
||||
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a7/49/a7b549514cf6d750f7dfb1e488ebdd49.jpg" alt="">
|
||||
|
||||
整个包的处理过程还是原来的过程,只不过为什么要格外关注这**五个节点**呢?
|
||||
|
||||
是因为在Linux内核中,有一个框架叫Netfilter。它可以在这些节点插入hook函数。这些函数可以截获数据包,对数据包进行干预。例如做一定的修改,然后决策是否接着交给TCP/IP协议栈处理;或者可以交回给协议栈,那就是**ACCEPT**;或者过滤掉,不再传输,就是**DROP**;还有就是**QUEUE**,发送给某个用户态进程处理。
|
||||
|
||||
这个比较难理解,经常用在内部负载均衡,就是过来的数据一会儿传给目标地址1,一会儿传给目标地址2,而且目标地址的个数和权重都可能变。协议栈往往处理不了这么复杂的逻辑,需要写一个函数接管这个数据,实现自己的逻辑。
|
||||
|
||||
有了这个Netfilter框架就太好了,你可以在IP转发的过程中,随时干预这个过程,只要你能实现这些hook函数。
|
||||
|
||||
一个著名的实现,就是**内核模块ip_tables**。它在这五个节点上埋下函数,从而可以根据规则进行包的处理。按功能可分为四大类:连接跟踪(conntrack)、数据包的过滤(filter)、网络地址转换(nat)和数据包的修改(mangle)。其中连接跟踪是基础功能,被其他功能所依赖。其他三个可以实现包的过滤、修改和网络地址转换。
|
||||
|
||||
在用户态,还有一个你肯定知道的客户端程序iptables,用命令行来干预内核的规则。内核的功能对应iptables的命令行来讲,就是**表和链**的概念。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/74/95/746131a029919768c4f00a0fe7fayy95.jpg" alt="">
|
||||
|
||||
iptables的表分为四种:raw-->mangle-->nat-->filter。这四个优先级依次降低,raw不常用,所以主要功能都在其他三种表里实现。每个表可以设置多个链。
|
||||
|
||||
filter表处理过滤功能,主要包含三个链:
|
||||
|
||||
<li>
|
||||
INPUT链:过滤所有目标地址是本机的数据包;
|
||||
</li>
|
||||
<li>
|
||||
FORWARD链:过滤所有路过本机的数据包;
|
||||
</li>
|
||||
<li>
|
||||
OUTPUT链:过滤所有由本机产生的数据包。
|
||||
</li>
|
||||
|
||||
nat表主要是处理网络地址转换,可以进行Snat(改变数据包的源地址)、Dnat(改变数据包的目标地址),包含三个链:
|
||||
|
||||
<li>
|
||||
PREROUTING链:可以在数据包到达防火墙时改变目标地址;
|
||||
</li>
|
||||
<li>
|
||||
OUTPUT链:可以改变本地产生的数据包的目标地址;
|
||||
</li>
|
||||
<li>
|
||||
POSTROUTING链:在数据包离开防火墙时改变数据包的源地址。
|
||||
</li>
|
||||
|
||||
mangle表主要是修改数据包,包含:
|
||||
|
||||
<li>
|
||||
PREROUTING链;
|
||||
</li>
|
||||
<li>
|
||||
INPUT链;
|
||||
</li>
|
||||
<li>
|
||||
FORWARD链;
|
||||
</li>
|
||||
<li>
|
||||
OUTPUT链;
|
||||
</li>
|
||||
<li>
|
||||
POSTROUTING链。
|
||||
</li>
|
||||
|
||||
将iptables的表和链加入到上面的过程图中,就形成了下面的图和过程。
|
||||
|
||||
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e0/ec/e06c112fce8e3f3bc8a89c52f86fdfec.jpg" alt="">
|
||||
|
||||
<li>
|
||||
数据包进入的时候,先进mangle表的PREROUTING链。在这里可以根据需要,改变数据包头内容之后,进入nat表的PREROUTING链,在这里可以根据需要做Dnat,也就是目标地址转换。
|
||||
</li>
|
||||
<li>
|
||||
进入路由判断,要判断是进入本地的还是转发的。
|
||||
</li>
|
||||
<li>
|
||||
如果是进入本地的,就进入INPUT链,之后按条件过滤限制进入。
|
||||
</li>
|
||||
<li>
|
||||
之后进入本机,再进入OUTPUT链,按条件过滤限制出去,离开本地。
|
||||
</li>
|
||||
<li>
|
||||
如果是转发就进入FORWARD链,根据条件过滤限制转发。
|
||||
</li>
|
||||
<li>
|
||||
之后进入POSTROUTING链,这里可以做Snat,离开网络接口。
|
||||
</li>
|
||||
|
||||
有了iptables命令,我们就可以在云中实现一定的安全策略。例如我们可以处理前面的偷窥事件。首先我们将所有的门都关闭。
|
||||
|
||||
```
|
||||
iptables -t filter -A INPUT -s 0.0.0.0/0.0.0.0 -d X.X.X.X -j DROP
|
||||
|
||||
```
|
||||
|
||||
-s表示源IP地址段,-d表示目标地址段,DROP表示丢弃,也即无论从哪里来的,要想访问我这台机器,全部拒绝,谁也黑不进来。
|
||||
|
||||
但是你发现坏了,ssh也进不来了,都不能远程运维了,可以打开一下。
|
||||
|
||||
```
|
||||
iptables -I INPUT -s 0.0.0.0/0.0.0.0 -d X.X.X.X -p tcp --dport 22 -j ACCEPT
|
||||
|
||||
```
|
||||
|
||||
如果这台机器是提供的是web服务,80端口也应该打开,当然一旦打开,这个80端口就需要很好的防护,但是从规则角度还是要打开。
|
||||
|
||||
```
|
||||
iptables -A INPUT -s 0.0.0.0/0.0.0.0 -d X.X.X.X -p tcp --dport 80 -j ACCEPT
|
||||
|
||||
```
|
||||
|
||||
这样就搞定了,其他的账户都封死,就一个防盗门可以进出,只要防盗门是五星级的,就比较安全了。
|
||||
|
||||
这些规则都可以在虚拟机里,自己安装iptables自己配置。但是如果虚拟机数目非常多,都要配置,对于用户来讲就太麻烦了,能不能让云平台把这部分工作做掉呢?
|
||||
|
||||
当然可以了。在云平台上,一般允许一个或者多个虚拟机属于某个安全组,而属于不同安全组的虚拟机之间的访问以及外网访问虚拟机,都需要通过安全组进行过滤。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/06/21/069e51d949312246yy9d2764e6d6c921.jpg" alt="">
|
||||
|
||||
例如图中,我们会创建一系列的网站,都是前端在Tomcat里面,对外开放8080端口。数据库使用MySQL,开放3306端口。
|
||||
|
||||
为了方便运维,我们创建两个安全组,将Tomcat所在的虚拟机放在安全组A里面。在安全组A里面,允许任意IP地址0.0.0.0/0访问8080端口,但是对于ssh的22端口,仅仅允许管理员网段203.0.113.0/24访问。
|
||||
|
||||
我们将MySQL所在的虚拟机放在安全组B里面。在安全组B里面,仅仅允许来自安全组A的机器访问3306端口,但是对于ssh的22端口,同样允许管理员网段203.0.113.0/24访问。
|
||||
|
||||
这些安全组规则都可以自动下发到每个在安全组里面的虚拟机上,从而控制一大批虚拟机的安全策略。这种批量下发是怎么做到的呢?你还记得这幅图吗?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/24/24/246db57c915d9ccf6e0d66182de0fe24.jpg" alt="">
|
||||
|
||||
两个VM都通过tap网卡连接到一个网桥上,但是网桥是二层的,两个VM之间是可以随意互通的,因而需要有一个地方统一配置这些iptables规则。
|
||||
|
||||
可以多加一个网桥,在这个网桥上配置iptables规则,将在用户在界面上配置的规则,放到这个网桥上。然后在每台机器上跑一个Agent,将用户配置的安全组变成iptables规则,配置在这个网桥上。
|
||||
|
||||
安全问题解决了,iptables真强大!别忙,iptables除了filter,还有nat呢,这个功能也非常重要。
|
||||
|
||||
前面的章节我们说过,在设计云平台的时候,我们想让虚拟机之间的网络和物理网络进行隔离,但是虚拟机毕竟还是要通过物理网和外界通信的,因而需要在出物理网的时候,做一次网络地址转换,也即nat,这个就可以用iptables来做。
|
||||
|
||||
我们学过,IP头里面包含源IP地址和目标IP地址,这两种IP地址都可以转换成其他地址。转换源IP地址的,我们称为Snat;转换目标IP地址的,我们称为Dnat。
|
||||
|
||||
你有没有思考过这个问题,TCP的访问都是一去一回的,而你在你家里连接WiFi的IP地址是一个私网IP,192.168.1.x。当你通过你们家的路由器访问163网站之后,网站的返回结果如何能够到达你的笔记本电脑呢?肯定不能通过192.168.1.x,这是个私网IP,不具有公网上的定位能力,而且用这个网段的人很多,茫茫人海,怎么能够找到你呢?
|
||||
|
||||
所以当你从你家里访问163网站的时候,在你路由器的出口,会做Snat的,运营商的出口也可能做Snat,将你的私网IP地址,最终转换为公网IP地址,然后163网站就可以通过这个公网IP地址返回结果,然后再nat回来,直到到达你的笔记本电脑。
|
||||
|
||||
云平台里面的虚拟机也是这样子的,它只有私网IP地址,到达外网网口要做一次Snat,转换成为机房网IP,然后出数据中心的时候,再转换为公网IP。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/1a/1a/1a5d299c2eb5480eda93a8f8e3b3ca1a.jpg" alt="">
|
||||
|
||||
这里有一个问题是,在外网网口上做Snat的时候,是全部转换成一个机房网IP呢,还是每个虚拟机都对应一个机房网IP,最终对应一个公网IP呢?前面也说过了,公网IP非常贵,虚拟机也很多,当然不能每个都有单独的机房网和公网IP了,因此这种Snat是一种特殊的Snat,MASQUERADE(地址伪装)。
|
||||
|
||||
这种方式下,所有的虚拟机共享一个机房网和公网的IP地址,所有从外网网口出去的,都转换成为这个IP地址。那又一个问题来了,都变成一个公网IP了,当163网站返回结果的时候,给谁呢,再nat成为哪个私网的IP呢?
|
||||
|
||||
这就是Netfilter的连接跟踪(conntrack)功能了。对于TCP协议来讲,肯定是上来先建立一个连接,可以用“源/目的IP+源/目的端口”唯一标识一条连接,这个连接会放在conntrack表里面。当时是这台机器去请求163网站的,虽然源地址已经Snat成公网IP地址了,但是conntrack表里面还是有这个连接的记录的。当163网站返回数据的时候,会找到记录,从而找到正确的私网IP地址。
|
||||
|
||||
这是虚拟机做客户端的情况,如果虚拟机做服务器呢?也就是说,如果虚拟机里面部署的就是163网站呢?
|
||||
|
||||
|
||||
|
||||
这个时候就需要给这个网站配置固定的物理网的IP地址和公网IP地址了。这时候就需要详细配置Snat规则和Dnat规则了。
|
||||
|
||||
当外部访问进来的时候,外网网口会通过Dnat规则将公网IP地址转换为私网IP地址,到达虚拟机,虚拟机里面是163网站,返回结果,外网网口会通过Snat规则,将私网IP地址转换为那个分配给它的固定的公网IP地址。
|
||||
|
||||
类似的规则如下:
|
||||
|
||||
<li>
|
||||
源地址转换(Snat):iptables -t nat -A -s 私网IP -j Snat --to-source 外网IP
|
||||
</li>
|
||||
<li>
|
||||
目的地址转换(Dnat):iptables -t nat -A -PREROUTING -d 外网IP -j Dnat --to-destination 私网IP
|
||||
</li>
|
||||
|
||||
到此为止iptables解决了非法偷窥隐私的问题。
|
||||
|
||||
## 小结
|
||||
|
||||
好了,这一节就讲到这里了,我们来总结一下。
|
||||
|
||||
<li>
|
||||
云中的安全策略的常用方式是,使用iptables的规则,请记住它的五个阶段,PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。
|
||||
</li>
|
||||
<li>
|
||||
iptables分为四种表,raw、mangle、nat、filter。其中安全策略主要在filter表中实现,而虚拟网络和物理网络地址的转换主要在nat表中实现。
|
||||
</li>
|
||||
|
||||
最后,给你留两个思考题。
|
||||
|
||||
<li>
|
||||
这一节中重点讲了iptables的filter和nat功能,iptables还可以通过QUEUE实现负载均衡,你知道怎么做吗?
|
||||
</li>
|
||||
<li>
|
||||
这一节仅仅讲述了云中偷窥的问题,如果是一个合法的用户,但是不自觉抢占网络通道,应该采取什么策略呢?
|
||||
</li>
|
||||
|
||||
我们的专栏更新到第26讲,不知你掌握得如何?是不是有很多问题想要跟我面对面探讨呢?这里就有一个机会。
|
||||
|
||||
今天晚上8:30,我会在极客时间APP里做一个直播,主题是“技术人如何在技术浪潮中线性成长?”,我会把我们讲过的网络协议作为案例,在直播中展开讲解,也会分享我从业多年来的心得体会。**你可以直接在这里留言提问,也可以准备好问题在直播的时候和我交流。**
|
||||
|
||||
欢迎你来看直播!我们晚上见!
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/00/ab/001997ebd09dd7e9f649f183207cdfab.jpg" alt="">
|
||||
@@ -0,0 +1,169 @@
|
||||
<audio id="audio" title="第27讲 | 云中的网络QoS:邻居疯狂下电影,我该怎么办?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/00/26/006be4d2d2e2e70b6063bdd40c1dbc26.mp3"></audio>
|
||||
|
||||
在小区里面,是不是经常有住户不自觉就霸占公共通道,如果你找他理论,他的话就像一个相声《楼道曲》说的一样:“公用公用,你用我用,大家都用,我为什么不能用?”。
|
||||
|
||||
除此之外,你租房子的时候,有没有碰到这样的情况:本来合租共享WiFi,一个人狂下小电影,从而你网都上不去,是不是很懊恼?
|
||||
|
||||
在云平台上,也有这种现象,好在有一种流量控制的技术,可以实现**QoS**(Quality of Service),从而保障大多数用户的服务质量。
|
||||
|
||||
对于控制一台机器的网络的QoS,分两个方向,一个是入方向,一个是出方向。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/74/11/747b0d537fd1705171ffcca3faf96211.jpg" alt="">
|
||||
|
||||
其实我们能控制的只有出方向,通过Shaping,将出的流量控制成自己想要的模样。而进入的方向是无法控制的,只能通过Policy将包丢弃。
|
||||
|
||||
## 控制网络的QoS有哪些方式?
|
||||
|
||||
在Linux下,可以通过TC控制网络的QoS,主要就是通过队列的方式。
|
||||
|
||||
### 无类别排队规则
|
||||
|
||||
第一大类称为**无类别排队规则**(Classless Queuing Disciplines)。还记得我们讲[ip addr](https://time.geekbang.org/column/article/7772)的时候讲过的**pfifo_fast**,这是一种不把网络包分类的技术。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e3/6c/e391b4b79580a7d66afe4307ff3f6f6c.jpg" alt="">
|
||||
|
||||
pfifo_fast分为三个先入先出的队列,称为三个Band。根据网络包里面TOS,看这个包到底应该进入哪个队列。TOS总共四位,每一位表示的意思不同,总共十六种类型。
|
||||
|
||||
通过命令行tc qdisc show dev eth0,可以输出结果priomap,也是十六个数字。在0到2之间,和TOS的十六种类型对应起来,表示不同的TOS对应的不同的队列。其中Band 0优先级最高,发送完毕后才轮到Band 1发送,最后才是Band 2。
|
||||
|
||||
另外一种无类别队列规则叫作**随机公平队列**(Stochastic Fair Queuing)。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b6/99/b6ec2e4e20ddee7d6952b7fa4586ba99.jpg" alt="">
|
||||
|
||||
会建立很多的FIFO的队列,TCP Session会计算hash值,通过hash值分配到某个队列。在队列的另一端,网络包会通过轮询策略从各个队列中取出发送。这样不会有一个Session占据所有的流量。
|
||||
|
||||
当然如果两个Session的hash是一样的,会共享一个队列,也有可能互相影响。hash函数会经常改变,从而session不会总是相互影响。
|
||||
|
||||
还有一种无类别队列规则称为**令牌桶规则**(TBF,Token Bucket Filte)。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/14/9b/145c6f8593bf7603eae79246b9d6859b.jpg" alt="">
|
||||
|
||||
所有的网络包排成队列进行发送,但不是到了队头就能发送,而是需要拿到令牌才能发送。
|
||||
|
||||
令牌根据设定的速度生成,所以即便队列很长,也是按照一定的速度进行发送的。
|
||||
|
||||
当没有包在队列中的时候,令牌还是以既定的速度生成,但是不是无限累积的,而是放满了桶为止。设置桶的大小为了避免下面的情况:当长时间没有网络包发送的时候,积累了大量的令牌,突然来了大量的网络包,每个都能得到令牌,造成瞬间流量大增。
|
||||
|
||||
### 基于类别的队列规则
|
||||
|
||||
另外一大类是**基于类别的队列规则**(Classful Queuing Disciplines),其中典型的为**分层令牌桶规则**(**HTB**, Hierarchical Token Bucket)。
|
||||
|
||||
HTB往往是一棵树,接下来我举个具体的例子,通过TC如何构建一棵HTB树来带你理解。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e6/f5/e6de57bf00f2fe8865ec3548bf8c67f5.jpg" alt="">
|
||||
|
||||
使用TC可以为某个网卡eth0创建一个HTB的队列规则,需要付给它一个句柄为(1:)。
|
||||
|
||||
这是整棵树的根节点,接下来会有分支。例如图中有三个分支,句柄分别为(:10)、(:11)、(:12)。最后的参数default 12,表示默认发送给1:12,也即发送给第三个分支。
|
||||
|
||||
```
|
||||
tc qdisc add dev eth0 root handle 1: htb default 12
|
||||
|
||||
```
|
||||
|
||||
对于这个网卡,需要规定发送的速度。一般有两个速度可以配置,一个是**rate**,表示一般情况下的速度;一个是**ceil**,表示最高情况下的速度。对于根节点来讲,这两个速度是一样的,于是创建一个root class,速度为(rate=100kbps,ceil=100kbps)。
|
||||
|
||||
```
|
||||
tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps
|
||||
|
||||
```
|
||||
|
||||
接下来要创建分支,也即创建几个子class。每个子class统一有两个速度。三个分支分别为(rate=30kbps,ceil=100kbps)、(rate=10kbps,ceil=100kbps)、(rate=60kbps,ceil=100kbps)。
|
||||
|
||||
```
|
||||
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30kbps ceil 100kbps
|
||||
tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10kbps ceil 100kbps
|
||||
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps
|
||||
|
||||
```
|
||||
|
||||
你会发现三个rate加起来,是整个网卡允许的最大速度。
|
||||
|
||||
HTB有个很好的特性,同一个root class下的子类可以相互借流量,如果不直接在队列规则下面创建一个root class,而是直接创建三个class,它们之间是不能相互借流量的。借流量的策略,可以使得当前不使用这个分支的流量的时候,可以借给另一个分支,从而不浪费带宽,使带宽发挥最大的作用。
|
||||
|
||||
最后,创建叶子队列规则,分别为**fifo**和**sfq**。
|
||||
|
||||
```
|
||||
tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 5
|
||||
tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5
|
||||
tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10
|
||||
|
||||
```
|
||||
|
||||
基于这个队列规则,我们还可以通过TC设定发送规则:从1.2.3.4来的,发送给port 80的包,从第一个分支1:10走;其他从1.2.3.4发送来的包从第二个分支1:11走;其他的走默认分支。
|
||||
|
||||
```
|
||||
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 match ip dport 80 0xffff flowid 1:10
|
||||
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 flowid 1:11
|
||||
|
||||
```
|
||||
|
||||
## 如何控制QoS?
|
||||
|
||||
我们讲过,使用OpenvSwitch将云中的网卡连通在一起,那如何控制QoS呢?
|
||||
|
||||
就像我们上面说的一样,OpenvSwitch支持两种:
|
||||
|
||||
- 对于进入的流量,可以设置策略Ingress policy;
|
||||
|
||||
```
|
||||
ovs-vsctl set Interface tap0 ingress_policing_rate=100000
|
||||
ovs-vsctl set Interface tap0 ingress_policing_burst=10000
|
||||
|
||||
```
|
||||
|
||||
- 对于发出的流量,可以设置QoS规则Egress shaping,支持HTB。
|
||||
|
||||
我们构建一个拓扑图,来看看OpenvSwitch的QoS是如何工作的。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/3b/ee/3b0de72bc937e108519a473067f607ee.jpg" alt="">
|
||||
|
||||
首先,在port上可以创建QoS规则,一个QoS规则可以有多个队列Queue。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e6/84/e65435bde65a255a085f10d02d2ff184.jpg" alt="">
|
||||
|
||||
```
|
||||
ovs-vsctl set port first_br qos=@newqos -- --id=@newqos create qos type=linux-htb other-config:max-rate=10000000 queues=0=@q0,1=@q1,2=@q2 -- --id=@q0 create queue other-config:min-rate=3000000 other-config:max-rate=10000000 -- --id=@q1 create queue other-config:min-rate=1000000 other-config:max-rate=10000000 -- --id=@q2 create queue other-config:min-rate=6000000 other-config:max-rate=10000000
|
||||
|
||||
```
|
||||
|
||||
上面的命令创建了一个QoS规则,对应三个Queue。min-rate就是上面的rate,max-rate就是上面的ceil。通过交换机的网络包,要通过流表规则,匹配后进入不同的队列。然后我们就可以添加流表规则Flow(first_br是br0上的port 5)。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br0 "in_port=6 nw_src=192.168.100.100 actions=enqueue:5:0"
|
||||
ovs-ofctl add-flow br0 "in_port=7 nw_src=192.168.100.101 actions=enqueue:5:1"
|
||||
ovs-ofctl add-flow br0 "in_port=8 nw_src=192.168.100.102 actions=enqueue:5:2"
|
||||
|
||||
```
|
||||
|
||||
接下来,我们单独测试从192.168.100.100,192.168.100.101,192.168.100.102到192.168.100.103的带宽的时候,每个都是能够打满带宽的。
|
||||
|
||||
如果三个一起测试,一起狂发网络包,会发现是按照3:1:6的比例进行的,正是根据配置的队列的带宽比例分配的。
|
||||
|
||||
如果192.168.100.100和192.168.100.101一起测试,发现带宽占用比例为3:1,但是占满了总的流量,也即没有发包的192.168.100.102有60%的带宽被借用了。
|
||||
|
||||
如果192.168.100.100和192.168.100.102一起测试,发现带宽占用比例为1:2。如果192.168.100.101和192.168.100.102一起测试,发现带宽占用比例为1:6。
|
||||
|
||||
## 小结
|
||||
|
||||
好了,这一节就讲到这里了,我们来总结一下。
|
||||
|
||||
<li>
|
||||
云中的流量控制主要通过队列进行的,队列分为两大类:无类别队列规则和基于类别的队列规则。
|
||||
</li>
|
||||
<li>
|
||||
在云中网络Openvswitch中,主要使用的是分层令牌桶规则(HTB),将总的带宽在一棵树上按照配置的比例进行分配,并且在一个分支不用的时候,可以借给另外的分支,从而增强带宽利用率。
|
||||
</li>
|
||||
|
||||
最后,给你留两个思考题。
|
||||
|
||||
<li>
|
||||
这一节中提到,入口流量其实没有办法控制,出口流量是可以很好控制的,你能想出一个控制云中的虚拟机的入口流量的方式吗?
|
||||
</li>
|
||||
<li>
|
||||
安全性和流量控制大概解决了,但是不同用户在物理网络的隔离还是没有解决,你知道怎么解决吗?
|
||||
</li>
|
||||
|
||||
我们的专栏更新到第27讲,不知你掌握得如何?每节课后我留的思考题,你都有没有认真思考,并在留言区写下答案呢?我会从**已发布的文章中选出一批认真留言的同学**,赠送学习奖励礼券和我整理的独家网络协议知识图谱。
|
||||
|
||||
欢迎你留言和我讨论。趣谈网络协议,我们下期见!
|
||||
@@ -0,0 +1,277 @@
|
||||
<audio id="audio" title="第28讲 | 云中网络的隔离GRE、VXLAN:虽然住一个小区,也要保护隐私" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/05/c1/05d27405cee757dcf8a8f13bab4f68c1.mp3"></audio>
|
||||
|
||||
对于云平台中的隔离问题,前面咱们用的策略一直都是VLAN,但是我们也说过这种策略的问题,VLAN只有12位,共4096个。当时设计的时候,看起来是够了,但是现在绝对不够用,怎么办呢?
|
||||
|
||||
**一种方式是修改这个协议**。这种方法往往不可行,因为当这个协议形成一定标准后,千千万万设备上跑的程序都要按这个规则来。现在说改就放,谁去挨个儿告诉这些程序呢?很显然,这是一项不可能的工程。
|
||||
|
||||
**另一种方式就是扩展**,在原来包的格式的基础上扩展出一个头,里面包含足够用于区分租户的ID,外层的包的格式尽量和传统的一样,依然兼容原来的格式。一旦遇到需要区分用户的地方,我们就用这个特殊的程序,来处理这个特殊的包的格式。
|
||||
|
||||
这个概念很像咱们[第22讲](https://time.geekbang.org/column/article/10386)讲过的**隧道理论**,还记得自驾游通过摆渡轮到海南岛的那个故事吗?在那一节,我们说过,扩展的包头主要是用于加密的,而我们现在需要的包头是要能够区分用户的。
|
||||
|
||||
底层的物理网络设备组成的网络我们称为**Underlay网络**,而用于虚拟机和云中的这些技术组成的网络称为**Overlay网络**,**这是一种基于物理网络的虚拟化网络实现**。这一节我们重点讲两个Overlay的网络技术。
|
||||
|
||||
## GRE
|
||||
|
||||
第一个技术是**GRE**,全称Generic Routing Encapsulation,它是一种IP-over-IP的隧道技术。它将IP包封装在GRE包里,外面加上IP头,在隧道的一端封装数据包,并在通路上进行传输,到另外一端的时候解封装。你可以认为Tunnel是一个虚拟的、点对点的连接。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b1/31/b189df0a6ee4b0462818bf2f154c9531.jpg" alt="">
|
||||
|
||||
从这个图中可以看到,在GRE头中,前32位是一定会有的,后面的都是可选的。在前4位标识位里面,有标识后面到底有没有可选项?这里面有个很重要的key字段,是一个32位的字段,里面存放的往往就是用于区分用户的Tunnel ID。32位,够任何云平台喝一壶的了!
|
||||
|
||||
下面的格式类型专门用于网络虚拟化的GRE包头格式,称为**NVGRE**,也给网络ID号24位,也完全够用了。
|
||||
|
||||
除此之外,GRE还需要有一个地方来封装和解封装GRE的包,这个地方往往是路由器或者有路由功能的Linux机器。
|
||||
|
||||
使用GRE隧道,传输的过程就像下面这张图。这里面有两个网段、两个路由器,中间要通过GRE隧道进行通信。当隧道建立之后,会多出两个Tunnel端口,用于封包、解封包。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/76/ce/76298ce51d349bc9805fbf317312e4ce.jpg" alt="">
|
||||
|
||||
<li>
|
||||
主机A在左边的网络,IP地址为192.168.1.102,它想要访问主机B,主机B在右边的网络,IP地址为192.168.2.115。于是发送一个包,源地址为192.168.1.102,目标地址为192.168.2.115。因为要跨网段访问,于是根据默认的default路由表规则,要发给默认的网关192.168.1.1,也即左边的路由器。
|
||||
</li>
|
||||
<li>
|
||||
根据路由表,从左边的路由器,去192.168.2.0/24这个网段,应该走一条GRE的隧道,从隧道一端的网卡Tunnel0进入隧道。
|
||||
</li>
|
||||
<li>
|
||||
在Tunnel隧道的端点进行包的封装,在内部的IP头之外加上GRE头。对于NVGRE来讲,是在MAC头之外加上GRE头,然后加上外部的IP地址,也即路由器的外网IP地址。源IP地址为172.17.10.10,目标IP地址为172.16.11.10,然后从E1的物理网卡发送到公共网络里。
|
||||
</li>
|
||||
<li>
|
||||
在公共网络里面,沿着路由器一跳一跳地走,全部都按照外部的公网IP地址进行。
|
||||
</li>
|
||||
<li>
|
||||
当网络包到达对端路由器的时候,也要到达对端的Tunnel0,然后开始解封装,将外层的IP头取下来,然后根据里面的网络包,根据路由表,从E3口转发出去到达服务器B。
|
||||
</li>
|
||||
|
||||
从GRE的原理可以看出,GRE通过隧道的方式,很好地解决了VLAN ID不足的问题。但是,GRE技术本身还是存在一些不足之处。
|
||||
|
||||
首先是**Tunnel的数量问题**。GRE是一种点对点隧道,如果有三个网络,就需要在每两个网络之间建立一个隧道。如果网络数目增多,这样隧道的数目会呈指数性增长。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/00/fe/006cc8a4bf7a13fea0f456905c263afe.jpg" alt="">
|
||||
|
||||
其次,**GRE不支持组播**,因此一个网络中的一个虚机发出一个广播帧后,GRE会将其广播到所有与该节点有隧道连接的节点。
|
||||
|
||||
另外一个问题是目前还是**有很多防火墙和三层网络设备无法解析GRE**,因此它们无法对GRE封装包做合适地过滤和负载均衡。
|
||||
|
||||
## VXLAN
|
||||
|
||||
第二种Overlay的技术称为VXLAN。和三层外面再套三层的GRE不同,VXLAN则是从二层外面就套了一个VXLAN的头,这里面包含的VXLAN ID为24位,也够用了。在VXLAN头外面还封装了UDP、IP,以及外层的MAC头。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/3b/0f/3b02d54c9093e3de6d1a847dd0eb060f.jpg" alt="">
|
||||
|
||||
VXLAN作为扩展性协议,也需要一个地方对VXLAN的包进行封装和解封装,实现这个功能的点称为**VTEP**(VXLAN Tunnel Endpoint)。
|
||||
|
||||
VTEP相当于虚拟机网络的管家。每台物理机上都可以有一个VTEP。每个虚拟机启动的时候,都需要向这个VTEP管家注册,每个VTEP都知道自己上面注册了多少个虚拟机。当虚拟机要跨VTEP进行通信的时候,需要通过VTEP代理进行,由VTEP进行包的封装和解封装。
|
||||
|
||||
和GRE端到端的隧道不同,VXLAN不是点对点的,而是支持通过组播的来定位目标机器的,而非一定是这一端发出,另一端接收。
|
||||
|
||||
当一个VTEP启动的时候,它们都需要通过IGMP协议。加入一个组播组,就像加入一个邮件列表,或者加入一个微信群一样,所有发到这个邮件列表里面的邮件,或者发送到微信群里面的消息,大家都能收到。而当每个物理机上的虚拟机启动之后,VTEP就知道,有一个新的VM上线了,它归我管。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e4/77/e4541dfd1571aab11694343520970a77.jpg" alt="">
|
||||
|
||||
如图,虚拟机1、2、3属于云中同一个用户的虚拟机,因而需要分配相同的VXLAN ID=101。在云的界面上,就可以知道它们的IP地址,于是可以在虚拟机1上ping虚拟机2。
|
||||
|
||||
虚拟机1发现,它不知道虚拟机2的MAC地址,因而包没办法发出去,于是要发送ARP广播。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/27/79/27b0f23c0e94c10bac63d2ec6401e079.jpg" alt="">
|
||||
|
||||
ARP请求到达VTEP1的时候,VTEP1知道,我这里有一台虚拟机,要访问一台不归我管的虚拟机,需要知道MAC地址,可是我不知道啊,这该咋办呢?
|
||||
|
||||
VTEP1想,我不是加入了一个微信群么?可以在里面@all 一下,问问虚拟机2归谁管。于是VTEP1将ARP请求封装在VXLAN里面,组播出去。
|
||||
|
||||
当然在群里面,VTEP2和VTEP3都收到了消息,因而都会解开VXLAN包看,里面是一个ARP。
|
||||
|
||||
VTEP3在本地广播了半天,没人回,都说虚拟机2不归自己管。
|
||||
|
||||
VTEP2在本地广播,虚拟机2回了,说虚拟机2归我管,MAC地址是这个。通过这次通信,VTEP2也学到了,虚拟机1归VTEP1管,以后要找虚拟机1,去找VTEP1就可以了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/37/6c/377070660f2474b90489b0f10f8f686c.jpg" alt="">
|
||||
|
||||
VTEP2将ARP的回复封装在VXLAN里面,这次不用组播了,直接发回给VTEP1。
|
||||
|
||||
VTEP1解开VXLAN的包,发现是ARP的回复,于是发给虚拟机1。通过这次通信,VTEP1也学到了,虚拟机2归VTEP2管,以后找虚拟机2,去找VTEP2就可以了。
|
||||
|
||||
虚拟机1的ARP得到了回复,知道了虚拟机2的MAC地址,于是就可以发送包了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/5b/6e/5ba8f197a682de2539594ef5d7e7d56e.jpg" alt="">
|
||||
|
||||
虚拟机1发给虚拟机2的包到达VTEP1,它当然记得刚才学的东西,要找虚拟机2,就去VTEP2,于是将包封装在VXLAN里面,外层加上VTEP1和VTEP2的IP地址,发送出去。
|
||||
|
||||
网络包到达VTEP2之后,VTEP2解开VXLAN封装,将包转发给虚拟机2。
|
||||
|
||||
虚拟机2回复的包,到达VTEP2的时候,它当然也记得刚才学的东西,要找虚拟机1,就去VTEP1,于是将包封装在VXLAN里面,外层加上VTEP1和VTEP2的IP地址,也发送出去。
|
||||
|
||||
网络包到达VTEP1之后,VTEP1解开VXLAN封装,将包转发给虚拟机1。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/b4/19/b4d39cfc833be380be67eeee8019d319.jpg" alt="">
|
||||
|
||||
有了GRE和VXLAN技术,我们就可以解决云计算中VLAN的限制了。那如何将这个技术融入云平台呢?
|
||||
|
||||
还记得将你宿舍里面的情况,所有东西都搬到一台物理机上那个故事吗?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8f/4c/8fc4b26b9e42c37adb87db81e36cc64c.jpg" alt="">
|
||||
|
||||
虚拟机是你的电脑,路由器和DHCP Server相当于家用路由器或者寝室长的电脑,外网网口访问互联网,所有的电脑都通过内网网口连接到一个交换机br0上,虚拟机要想访问互联网,需要通过br0连到路由器上,然后通过路由器将请求NAT后转发到公网。
|
||||
|
||||
接下来的事情就惨了,你们宿舍闹矛盾了,你们要分成三个宿舍住,对应上面的图,你们寝室长,也即路由器单独在一台物理机上,其他的室友也即VM分别在两台物理机上。这下把一个完整的br0一刀三断,每个宿舍都是单独的一段。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/18/cb/184a02e0ee2404b46409cbf3d34837cb.jpg" alt="">
|
||||
|
||||
可是只有你的寝室长有公网口可以上网,于是你偷偷在三个宿舍中间打了一个隧道,用网线通过隧道将三个宿舍的两个br0连接起来,让其他室友的电脑和你寝室长的电脑,看起来还是连到同一个br0上,其实中间是通过你隧道中的网线做了转发。
|
||||
|
||||
为什么要多一个br1这个虚拟交换机呢?主要通过br1这一层将虚拟机之间的互联和物理机机之间的互联分成两层来设计,中间隧道可以有各种挖法,GRE、VXLAN都可以。
|
||||
|
||||
使用了OpenvSwitch之后,br0可以使用OpenvSwitch的Tunnel功能和Flow功能。
|
||||
|
||||
OpenvSwitch支持三类隧道:GRE、VXLAN、IPsec_GRE。在使用OpenvSwitch的时候,虚拟交换机就相当于GRE和VXLAN封装的端点。
|
||||
|
||||
我们模拟创建一个如下的网络拓扑结构,来看隧道应该如何工作。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/fc/49/fca6857aaca4f3549b02445ffce71f49.jpg" alt="">
|
||||
|
||||
三台物理机,每台上都有两台虚拟机,分别属于两个不同的用户,因而VLAN tag都得打地不一样,这样才不能相互通信。但是不同物理机上的相同用户,是可以通过隧道相互通信的,因而通过GRE隧道可以连接到一起。
|
||||
|
||||
接下来,所有的Flow Table规则都设置在br1上,每个br1都有三个网卡,其中网卡1是对内的,网卡2和3是对外的。
|
||||
|
||||
下面我们具体来看Flow Table的设计。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/88/69/8888426b42555043c3e05ec26fe47f69.png" alt="">
|
||||
|
||||
|
||||
|
||||
1.Table 0是所有流量的入口,所有进入br1的流量,分为两种流量,一个是进入物理机的流量,一个是从物理机发出的流量。
|
||||
|
||||
从port 1进来的,都是发出去的流量,全部由Table 1处理。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 in_port=1 actions=resubmit(,1)"
|
||||
|
||||
```
|
||||
|
||||
从port 2、3进来的,都是进入物理机的流量,全部由Table 3处理。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 in_port=2 actions=resubmit(,3)"
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 in_port=3 actions=resubmit(,3)"
|
||||
|
||||
```
|
||||
|
||||
如果都没匹配上,就默认丢弃。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 actions=drop"
|
||||
|
||||
```
|
||||
|
||||
2.Table 1用于处理所有出去的网络包,分为两种情况,一种是单播,一种是多播。
|
||||
|
||||
对于单播,由Table 20处理。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=1 dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20)"
|
||||
|
||||
```
|
||||
|
||||
对于多播,由Table 21处理。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=1 dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21)"
|
||||
|
||||
```
|
||||
|
||||
3.Table 2是紧接着Table1的,如果既不是单播,也不是多播,就默认丢弃。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=2 actions=drop"
|
||||
|
||||
```
|
||||
|
||||
4.Table 3用于处理所有进来的网络包,需要将隧道Tunnel ID转换为VLAN ID。
|
||||
|
||||
如果匹配不上Tunnel ID,就默认丢弃。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=3 actions=drop"
|
||||
|
||||
```
|
||||
|
||||
如果匹配上了Tunnel ID,就转换为相应的VLAN ID,然后跳到Table 10。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=3 tun_id=0x1 actions=mod_vlan_vid:1,resubmit(,10)"
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=3 tun_id=0x2 actions=mod_vlan_vid:2,resubmit(,10)"
|
||||
|
||||
```
|
||||
|
||||
5.对于进来的包,Table 10会进行MAC地址学习。这是一个二层交换机应该做的事情,学习完了之后,再从port 1发出去。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1 table=10 actions=learn(table=20,priority=1,hard_timeout=300,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]),output:1"
|
||||
|
||||
```
|
||||
|
||||
Table 10是用来学习MAC地址的,学习的结果放在Table 20里面。Table20被称为MAC learning table。
|
||||
|
||||
NXM_OF_VLAN_TCI是VLAN tag。在MAC learning table中,每一个entry都仅仅是针对某一个VLAN来说的,不同VLAN的learning table是分开的。在学习结果的entry中,会标出这个entry是针对哪个VLAN的。
|
||||
|
||||
NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]表示,当前包里面的MAC Source Address会被放在学习结果的entry里的dl_dst里。这是因为每个交换机都是通过进入的网络包来学习的。某个MAC从某个port进来,交换机就应该记住,以后发往这个MAC的包都要从这个port出去,因而源MAC地址就被放在了目标MAC地址里面,因为这是为了发送才这么做的。
|
||||
|
||||
load:0->NXM_OF_VLAN_TCI[]是说,在Table20中,将包从物理机发送出去的时候,VLAN tag设为0,所以学习完了之后,Table 20中会有actions=strip_vlan。
|
||||
|
||||
load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[]的意思是,在Table 20中,将包从物理机发出去的时候,设置Tunnel ID,进来的时候是多少,发送的时候就是多少,所以学习完了之后,Table 20中会有set_tunnel。
|
||||
|
||||
output:NXM_OF_IN_PORT[]是发送给哪个port。例如是从port 2进来的,那学习完了之后,Table 20中会有output:2。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4d/dd/4dc0fe34819ee02a53a97c89811747dd.jpg" alt="">
|
||||
|
||||
所以如图所示,通过左边的MAC地址学习规则,学习到的结果就像右边的一样,这个结果会被放在Table 20里面。
|
||||
|
||||
6.Table 20是MAC Address Learning Table。如果不为空,就按照规则处理;如果为空,就说明没有进行过MAC地址学习,只好进行广播了,因而要交给Table 21处理。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=20 actions=resubmit(,21)"
|
||||
|
||||
```
|
||||
|
||||
7.Table 21用于处理多播的包。
|
||||
|
||||
如果匹配不上VLAN ID,就默认丢弃。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=0 table=21 actions=drop"
|
||||
|
||||
```
|
||||
|
||||
如果匹配上了VLAN ID,就将VLAN ID转换为Tunnel ID,从两个网卡port 2和port 3都发出去,进行多播。
|
||||
|
||||
```
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1table=21dl_vlan=1 actions=strip_vlan,set_tunnel:0x1,output:2,output:3"
|
||||
ovs-ofctl add-flow br1 "hard_timeout=0 idle_timeout=0 priority=1table=21dl_vlan=2 actions=strip_vlan,set_tunnel:0x2,output:2,output:3"
|
||||
|
||||
```
|
||||
|
||||
## 小结
|
||||
|
||||
好了,这一节就到这里了,我们来总结一下。
|
||||
|
||||
<li>
|
||||
要对不同用户的网络进行隔离,解决VLAN数目有限的问题,需要通过Overlay的方式,常用的有GRE和VXLAN。
|
||||
</li>
|
||||
<li>
|
||||
GRE是一种点对点的隧道模式,VXLAN支持组播的隧道模式,它们都要在某个Tunnel Endpoint进行封装和解封装,来实现跨物理机的互通。
|
||||
</li>
|
||||
<li>
|
||||
OpenvSwitch可以作为Tunnel Endpoint,通过设置流表的规则,将虚拟机网络和物理机网络进行隔离、转换。
|
||||
</li>
|
||||
|
||||
最后,给你留两个思考题。
|
||||
|
||||
<li>
|
||||
虽然VXLAN可以支持组播,但是如果虚拟机数目比较多,在Overlay网络里面,广播风暴问题依然会很严重,你能想到什么办法解决这个问题吗?
|
||||
</li>
|
||||
<li>
|
||||
基于虚拟机的云比较复杂,而且虚拟机里面的网卡,到物理网络转换层次比较多,有一种比虚拟机更加轻量级的云的模式,你知道是什么吗?
|
||||
</li>
|
||||
|
||||
我们的专栏更新到第28讲,不知你掌握得如何?每节课后我留的思考题,你都有没有认真思考,并在留言区写下答案呢?我会从**已发布的文章中选出一批认真留言的同学**,赠送学习奖励礼券和我整理的独家网络协议知识图谱。
|
||||
|
||||
欢迎你留言和我讨论。趣谈网络协议,我们下期见!
|
||||
Reference in New Issue
Block a user