VXLAN详解及实践

(本文章是学习《kubernetes 网络权威指南》 一书时做的笔记,由于本人是刚学习k8s,且自学方式就是把它敲一遍,然后加一些自己的理解。所以会发现很多内容是跟书中内容一模一样,如果本文是对本书的侵权,敬请谅解,告知后会删除。如果引用或转载,请注明出处——谢谢)


VXLAN 虚拟可扩展的局域网,是一种虚拟话隧道通信技术,它是一种overlay(覆盖网络技术),通过三层网络搭建虚拟的二层网络。
VXLAN是在底层物理网络(underlay)之上使用隧道技术,依托UDP层构建的overlay的逻辑网络,使逻辑网络与物理网络解耦。
不同于企业隧道协议,VXLAN是一个一对多的网络,并不仅仅是一对一的隧道协议。一个VXLAN设备能通过像网桥一样的学习方式学习到其他对端的IP地址,也可以直接配置静态转发。

为什么需要VXLAN

VLAN技术的缺陷是VLAN header预留的长度只有12bit,故最多只能支持4096个子网的划分,无法满足云计算场景下主机数量。VXLAN可以支持更多的子网数量。总体而言VXLAN主要解决以下几个问题
当前VXLAN的报文header有24bit,可以支持2的24次方个子网,并通过VNI(virtual network identifier)区分不同子网,相当于VLAN ID
多租网络隔离,越来越多的数据中心,尤其是公有云服务,需要提供多租户的功能,不同用户之间需要独立的IP和MAC地址,如何保证这个功能的扩展性和正确性是待解决的问题
云计算业务对业务灵活性要求很高,虚拟机可能会大规模迁徙,保证网络一直可用,也就是大二层的概念。解决这个问题同时保证二层的广播域不会过分扩大,这也是云计算网络的要求

VXLAN 协议原理简介

VXLAN 隧道网络相比改造传统的二层或三层网络,对原有的网络架构影响较小。隧道网络不需要原来的网络做任何的修改,可在原来的网络基础上架设一层新的网络。
VXLAN创建在原来的IP网络伤,只要是三层网络可达(能够通过IP互相通信)的网络就能部署VXLAN。在VXLAN网络的每一个断点上都有一个VTEP设备,负责VXLAN协议报文的封包和解包,也就是在虚拟报文伤封装VTEP通信的报文头部。物理网络上可以创建多个VXLAN网络,可将这些VXLAN网络看作一个隧道,不同节点上的虚拟机/容器能够通过隧道直连。通过VNI标识不同的VXLAN网络,使不同的VXLAN可以互相隔离。

VXLAN几个重要概念

  • VTEP(VXLAN tunnel endpoints):VXLAN网络的边缘设备,用来进行VXLAN报文的封包与解包。VTEP可以是网络设备(例如交换机),也可以是一台机器(例如虚拟化集群中的宿主机)。
  • VNI(VXLAN network identifier):VNI是VXLAN的标识,是个24位整数,因此最大值是2的24次方 16777216。如果一个VNI对应一个租户,那么理论上VXLAN可以支持千万级别的租户。
  • tunnel:隧道是一个逻辑伤的概念,在VXLAN模型中并没有具体的物理实体相对应。隧道可以看作一个虚拟通道,VXLAN通信双方都认为自己在直接通信,并不知道底层网络的存在。从整体上看,每个VXLAN网络像是为通信的设备搭建了一个单独的通信通道,也就是隧道。

前面提到,VXLAN是在三层网络上构建出来的一个二层网络隧道。VNI相同的机器逻辑上处于同一个二层网络中。VXLAN封包格式如图。
在这里插入图片描述
   
VXLAN 的报文就是MAC in UDP,即在三层网络的基础上构建一个虚拟的二层网络。为什么这么说呢?VXLAN的封包格式显示原来的二层以太网帧(包含MAC头部、IP头部和传输层头部的报文),被放在VXLAN包头里进行封装,再套到标准的UDP头部(UDP头部、IP头部和MAC头部),用来在底层网络上传输报文。
可以看出,VXLAN报文比原始报文多出50个字节,这降低了网络链路传输的有效数据比例,尤其是小包。
需要注意的是,UDP目的端口是接收方VTEP设备使用的端口,IANA分配了4789作为VXLAN的目的UDP端口(flannel VXLAN模式是8472)
VXLAN 的配置管理使用iproute2包,这个工具是和VXLAN一起合入内核功能的,我们常用的ip命令就是iproute2的客户端工具。VXLAN要求内核在3.7版本以上,最好是3.9以上。所以在一些旧的Linux上无法使用VXLAN的封包技术。

VXLAN 组网必要信息

VXLAN报文的转发过程是:原始报文金国VTEP,被Linux内核添加VXLAN包头及外部UDP头部,再发送出去。对端在收到VXLAN报文后,拆除UDP报头,并根据VXLAN头部的VNI把报文发送给目的服务器
以上信息看似并不复杂,但是在第一次通信的时候,需要解决以下几个问题:

  • 哪些VTEP需要添加到同一个VNI组
  • 发送方如何知道对方的MAC地址
  • 如何知道目的服务器在哪个节点伤

第一个问题,VTEP通常由网络管理员分配。另外两个问题可以归结为一个问题:VXLAN网络通信的双方如何感知彼此并选择正确的路径传输报文?要回答这两个问题,的要回到VXLAN报文上,看完整的VXLAN报文需要哪些信息:

  • 内层报文:通信双方的IP地址已经明确,需要填充的是对方MAC地址,VXLAN需要一个机制来实现ARP的功能
  • VXLAN头部:要知道VNI,要么是直接配置在VTEP上的,要么是提前划分的,要么是根据内部报文自动生成的
  • 外层UDP头部:源地址和目的地址端口,源地址端口是系统生成并管理的,目的地址端口一般固定为IANA分配的4789端口(Linux默认是8472)
  • 外层IP头部:IP头部关心的是对端VTEP的IP,源地址可以通过简单的方式获取,目的地址是虚拟机所在地址宿主机VTEP的IP地址,需要某种方式确定
  • 外层MAC头部:确定了VTEP的IP后,MAC地址可以通过传统的ARP方式获取,毕竟VTEP是在同一个三层网络

总结一下:一个VXLAN报文需要知道两个地址信息:内层报文(目的虚拟机/容器)的MAC地址,外层报文(目的虚拟机/容器所在宿主机的VTEP)IP地址。如果VNI也是动态感知的,那么VXLAN一共需要知道三个信息:内部MAC、VTEP IP和VNI。
一般有两种方式获取以上信息:多播和控制中心。多播的感念是同一个VXLAN网络的VTEP加入同一个多播网络。如果需要以上信息,就在组内发送多播来查询。控制中心就是集中在某个地方保存所有虚拟机以上信息,自动告知VTEP它需要的信息。

VXLAN 基本配置命令

创建VXLAN 接口

ip link add vxlan0 type vxlan id 42 group 239.1.1.1 dev eth0 dstport 4789

该命令或创建一个叫vxlan0 的VXLAN新接口,它使用 eth0伤的多播组 239.1.1.1 通信,初始化时没有转发表,目的端口使用IANA规定的4789。一般将VXLAN的接口(例子中的vxlan0)叫做VTEP,VXLAN的子网报文需要从VTEP出去。
删除VXLAN 接口

ip link delete vxlan0

查看VXLAN接口信息

ip -d link show vxlan0

VXLAN 转发表
可以使用 bridge命令创建、删除或查看VXLAN接口的转发表
创建一条转发表项

bridge fdb add to dstmac dst 192.168.0.123 dev vxlan0

dstmac 是对端VTEP的MAC地址,192.168.0.123 是对端VTEP的IP地址
删除一条转发表项

bridge fdb delete dstmac dev vxlan0

查看 VXLAN转发表

bridge fdb show dev vxlan0

注:网络设备都以MAC地址唯一地址标识自己,而交换机要实现设备之间的通信就必须知道自己的哪个端口连接哪台设备,因此就需要一张MAC地址与端口号对应的表,以便在交换机内部实现二层转发。这张表就叫FDB表,它主要由MAC地址、VLAN号、端口号和一些标志域等信息组成。如果收到的数据帧的目的MAC地址不在FDB表中,那给数据将被转发给除源端口外,该数据所属VLAN中的其他所有端口,把数据发给其他所有端口的行为称之为洪泛。

FDB表形成,交换机在收到数据帧时,提取数据帧中的源MAC、VLAN和接收数据帧的端口,组成FDB表的条目。当下次看到相同VLAN时。相同MAC地址的报文就直接从记录端口丢出去。

VXLAN网络实践

1、点对点的VXLAN

先从简单的点对点VXLAN网络说起。点对点VXLAN即两台机器构成一个VXLAN网络,每台机器上有一个VTEP,VTEP之间使用它们的IP地址进行通信。
先通过命令创建VXLAN接口

ip link add vxlan0 type vxlan id 42 dstport 4789 remote 192.168.30.108 \
local 192.168.30.104 dev ens33

命令会创建一个名为 vxlan0 ,类型为vxlan的网络接口,一些重要参数说明:
id 42:指定VNI的值,在1~2的24次方之间
dstport: VTEP通信端口,IANA分配的是4789,Linux默认使用的是8472
remote 192.168.30.108: 对端VTEP的地址
local 192.168.30.104: 当前节点VTEP要使用的IP地址,即当前隧道口的IP地址
dev ens33:当前节点用于VTEP要使用的IP地址,用来获取VTEP IP地址。注意这个与参数local参数含义一样,在使用过程中二选一即可
为VXLAN网卡配置IP地址并启用

ip addr add 172.17.1.2/24 dev vxlan0
ip link set vxlan0 up

执行成功后会发现路由表多了以下内容,所有目的地址是172.17.1.0/24网段的包要通过vxlan0转发

ip route
172.17.1.0/24 dev vxlan0 proto kernel scope link src 172.17.1.2

同时vxlan0的fdb表项中内容如下

bridge fdb show dev vxlan0
00:00:00:00:00:00 dst 192.168.30.108 via ens33 self permanent

这个表项的意思是,默认的VTEP对端地址为 192.168.30.105.换句话说,原始报文经过vxlan0后,会被内核加上VXLAN头部,而外部UDP头部的目的IP地址为被冠伤192.168.30.105。
在另外一台机器上(192.160.30.105)上也进行相同的配置,要保证VNI也是42,dstport也是4789,并修改VTEP的local和remote IP地址到相应的值。测试两个VTEP的连通性

ping 172.17.1.2 
PING 172.17.1.2 (172.17.1.2) 56(84) bytes of data.
64 bytes from 172.17.1.2: icmp_seq=1 ttl=64 time=3.98 ms
64 bytes from 172.17.1.2: icmp_seq=2 ttl=64 time=0.649 ms
64 bytes from 172.17.1.2: icmp_seq=3 ttl=64 time=0.488 ms

--- 172.17.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2011ms
rtt min/avg/max/mdev = 0.488/1.707/3.984/1.611 ms
...

同时使用tcpdump抓包可以看出采用VXLAN封包

tcpdump  -i ens33 -n 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
17:14:12.377092 IP 192.168.30.108.50894 > 192.168.30.104.4789: VXLAN, flags [I] (0x08), vni 42
IP 172.17.1.3 > 172.17.1.2: ICMP echo request, id 9965, seq 36, length 64
17:14:12.377225 IP 192.168.30.104.47202 > 192.168.30.108.4789: VXLAN, flags [I] (0x08), vni 42
IP 172.17.1.2 > 172.17.1.3: ICMP echo reply, id 9965, seq 36, length 64
17:14:12.581544 IP 192.168.30.108.48170 > 192.168.30.104.4789: VXLAN, flags [I] (0x08), vni 42
IP6 fe80::c4e1:65ff:fe1d:4276 > ff02::2: ICMP6, router solicitation, length 16
17:14:13.379596 IP 192.168.30.108.50894 > 192.168.30.104.4789: VXLAN, flags [I] (0x08), vni 42
IP 172.17.1.3 > 172.17.1.2: ICMP echo request, id 9965, seq 37, length 64
17:14:13.379706 IP 192.168.30.104.47202 > 192.168.30.108.4789: VXLAN, flags [I] (0x08), vni 42
IP 172.17.1.2 > 172.17.1.3: ICMP echo reply, id 9965, seq 37, length 64
17:14:14.179587 ARP, Request who-has 192.168.30.103 tell 192.168.30.1, length 46
17:14:14.404872 IP 192.168.30.108.50894 > 192.168.30.104.4789: VXLAN, flags [I] (0x08), vni 42
IP 172.17.1.3 > 172.17.1.2: ICMP echo request, id 9965, seq 38, length 64
17:14:14.404986 IP 192.168.30.104.47202 > 192.168.30.108.4789: VXLAN, flags [I] (0x08), vni 42
IP 172.17.1.2 > 172.17.1.3: ICMP echo reply, id 9965, seq 38, length 64
...

2、多播模式的VXLAN

要组成同一个VXLAN网络,VTEP必须能够感知到彼此的存在,多播组本身的功能就是把网络中的某个节点组成一个虚拟的组,所以VXLAN最初想到用多播来实现也是很自然的。
注:如果VXLAN要使用多播,那么底层网络结构需要支持多播功能
本实验与前面的实验比较相似,只不过主机之间不是点对点的连接,而是通过多播组成一个虚拟的整体。
虽然加入了一个多播组,但是实际比较简单,和点对点相比就多了参数group

ip link add vxlan0 type vxlan id 43 dstport 4789 dev ens33 group 239.1.1.1 

同样为杠创建的VXLAN接口配置地址并启用

ip addr add 172.17.1.2/24 dev vxlan0
ip link set dev vxlan0 up

这里比较重要的参数是239.1.1.1,它表示将VTEP加入一个多播组,多播组的地址是239.1.1.1。
注:多播地址能够让设备将报文发送给一组设备,属于多播组的设备将被分配一个多播组IP,多播地址范围在224.0.0.0~239.255.255.255
执行完上面命令,同样会添加路由信息

ip route
172.17.1.0/24 dev vxlan0 proto kernel scope link src 172.17.1.2

不同的是fdb表项内容

bridge fdb
00:00:00:00:00:00 dev vxlan0 dst 239.1.1.1 via ens33 self permanent

dst字段变成了多播地址239.1.1.1,而不是前面对方的VTEP 地址,意思是原始报文经过vxlan0后,被内核添加伤VXLAN头部,其外部UDP头目的IP地址会被改成多播地址239.1.1.1。
同理,需要为通信的节点进行上诉配置,验证它们是否通过172.17.1.0/24网络互相通信。

ping 172.17.1.2
PING 172.17.1.2 (172.17.1.2) 56(84) bytes of data.
64 bytes from 172.17.1.2: icmp_seq=1 ttl=64 time=1.88 ms
64 bytes from 172.17.1.2: icmp_seq=2 ttl=64 time=0.625 ms
64 bytes from 172.17.1.2: icmp_seq=3 ttl=64 time=0.514 ms
64 bytes from 172.17.1.2: icmp_seq=4 ttl=64 time=0.651 ms
64 bytes from 172.17.1.2: icmp_seq=5 ttl=64 time=0.696 ms
64 bytes from 172.17.1.2: icmp_seq=6 ttl=64 time=0.753 ms
64 bytes from 172.17.1.2: icmp_seq=7 ttl=64 time=0.708 ms
64 bytes from 172.17.1.2: icmp_seq=8 ttl=64 time=0.522 ms

通过tcpdump抓包

tcpdump -i ens33 -n 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:34:54.050371 IP 192.168.30.108.50894 > 192.168.30.104.4789: VXLAN, flags [I] (0x08), vni 43
IP 172.17.1.3 > 172.17.1.2: ICMP echo request, id 9204, seq 9, length 64
20:34:54.050477 IP 192.168.30.104.47202 > 192.168.30.108.4789: VXLAN, flags [I] (0x08), vni 43
IP 172.17.1.2 > 172.17.1.3: ICMP echo reply, id 9204, seq 9, length 64
20:34:55.074169 IP 192.168.30.108.50894 > 192.168.30.104.4789: VXLAN, flags [I] (0x08), vni 43
IP 172.17.1.3 > 172.17.1.2: ICMP echo request, id 9204, seq 10, length 64
20:34:55.074299 IP 192.168.30.104.47202 > 192.168.30.108.4789: VXLAN, flags [I] (0x08), vni 43
IP 172.17.1.2 > 172.17.1.3: ICMP echo reply, id 9204, seq 10, length 64

分析一下多播模式下通信过程

  1. 主机1通过vxlan0发送ping报文到主机2的地址,此时内核发现是在同一个局域网内。需要知道对方的MAC地址,而本地又没有缓存,此时内核会发送一个ARP查询
  2. ARP报文源MAC地址是主机1上vxlan0的MAC地址,目的地址为255.255.255.255广播地址,并根据配置添加VXLAN头部VNI=43
  3. 不知道对端VETP在哪台主机上,但又配置了多播组,根据配置,VTEP会向多播地址239.1.1.1 发送多播报文
  4. 多播组中所有的主机都会收到这个报文,内核发现是VXLAN报文,根据VNI发送给对应的VTEP。
  5. 主机2的VTEP去掉VXLAN头部,取出真正的ARP请求报文。同时,VTEP会记录源MAC地址和IP地址信息存放到FDB中,这便是一次学习过程。如果发现ARP不是发送给自己则丢弃;如果是发送给自己,则生成ARP应答报文。
  6. 应答报文目的MAC地址是发送方VTEP的MAC地址,不需要多播。对端VTEP已经通过源报文学习到了VTEP主机的MAC地址,故会直接单播发送给目的VTEP
  7. 应答报文通过底层网络直接返回发送方主机,发送方根据VNI把报文转发给VTEP,VTEP解包取出ARP应答报文,添加到VTEP缓存中,并根据报文学习到目的VTEP所在的主机地址,添加到FDB表中
  8. VTEP双方(隧道网络双方)已经通过一次ARP报文知道了建立ICMP通信需要的所有信息,因此后续的ICMP报文都是在这条逻辑隧道中单播进行

总结以上过程:一个VXLAN网络的ping报文要经历ARP寻址+ICMP响应两个过程。当VTEP设备学习到对方ARP地址后,就免去了ARP寻址的过程。

3、VXLAN+网桥网络

前面的方法能够通过多播实现自动话的overlay网络构建,但是通信双方只有一个VTEP,在实际环境中,每台主机都有几十台甚至上百台虚拟机或者容器需要通信,因此需要一种方法将它们组织起来,再经过VTEP转发出去。
我们知道Linux网桥可以连接多个网卡,因此可以使用网桥将多个虚拟机或容器放到同一个VXLAN网络中,和前面的多播相比,只是多了一块网桥,连接同一个主机上不同容器的 veth pair,这里先用 network namespace 代替容器,其实原理是一样的。创建一个network namespace ,并通过 veth pair将namespace 中的eth0 网卡连接到网桥,同时VXLAN也连接到网桥。
首先创建VXLAN,使用多播模式

ip link add vxlan0 type vxlan id 44 dstport 4789 dev ens33  group 233.1.1.1

然后创建网桥 bridge1 ,把vxlan0绑定到上面,并启用它们

ip link add bridge1 type bridge
ip link set vxlan0 master bridge1
ip link set vxlan0 up
ip link set bridge1 up

创建network namespace 和一对 veth pair,并把veth pair一端绑定到网桥,另一端放到network namespace 并绑定IP地址 172.17.30.2

ip netns add container1

ip link add veth0 type veth peer name veth1
ip link set dev veth0 master bridge1
ip link set dev veth0 up

ip link set dev veth1 netns container1
ip netns exec container1 ip link set lo up

ip netns exec container1 ip link set veth1 name eth0
ip netns exec container1 ip addr add 172.17.30.2/24 dev eth0
ip netns exec container1 ip link set eth0 up

同样的方法在灵台主机上配置VXLAN网络,兵丁172.17.30.3/24 到另外李哥network namespace中的eth0。
从172.17.30.2 Ping 172.17.30.3 整个过程和前面实现类似,只不过容器发出的ARP报文会先经过网桥,再转发给vxlan0;然后在vxlan0处由Linux内核添加VXLAN头部。通过多播的方式查询通信对端的MAC地址。
逻辑上,VXLAN网络下不同主机上的network namespace中的网卡被连接到了同一个网桥上。

4、分布式控制中心

因为并不是所有的网络设备都支持多播,并且多播方式带来的报文浪费,在实际生产环境中VXLAN的多播模式很少使用。
回顾我们为什么要是用多播。从多播过程流程可以看出,其实隧道网络发送报文最关键的就是要知道对方虚拟机/容器的MAC地址及所在主机的VTEP IP地址。对overlay网络来说,它的网段范围是分布在多个主机上的,因此传统ARP报文的广播无法直接使用。要想做到overlay网络的广播,就需要把报文发送到所有VTEP节点,这才使用了多播。如果事先能知道MAC地址和VTEP IP信息,直接高松发送方VETP,就不需要多播了。
虚拟机和容器场景中,当虚拟机或者容器还进行通信时,我们就可以知道它的IP和Mac(可能使用某种方式获取,也可能是事先控制了这两个地址),分布式控制中心保存了这些信息。除此之外,控制中心还保存了每个VXLAN网络的VTEP,以及这些VETP地址。有了这些信息,VTEP在发送报文时直接查询并添加头部,不需要多播去满网络问了。
在分布式控制中心,一般情况下,这种架构在每个VTEP所在的节点都运行一个agent,它会和通信中心通信,获取隧道通信需要的信息并以某种方式告知VTEP。
(喜欢的话,记得点赞跟收藏啦!)

发布了13 篇原创文章 · 获赞 6 · 访问量 351

猜你喜欢

转载自blog.csdn.net/WuYuChen20/article/details/104515608