1.flannel支持的后端模式,及VXLAN后端三个版本的变化

参考:

https://github.com/coreos/flannel/blob/v0.9.0/backend/vxlan/vxlan.go

https://www.sdnlab.com/21143.html

https://mingxin.io/VXLAN&Flannel/

 

从0.9版本开始有如下变化,地址:https://github.com/coreos/flannel/blob/v0.9.0/backend/vxlan/vxlan.go

// Some design notes and history:
// VXLAN encapsulates L2 packets (though flannel is L3 only so don't expect to be able to send L2 packets across hosts)
// The first versions of vxlan for flannel registered the flannel daemon as a handler for both "L2" and "L3" misses
// - When a container sends a packet to a new IP address on the flannel network (but on a different host) this generates
//   an L2 miss (i.e. an ARP lookup)
// - The flannel daemon knows which flannel host the packet is destined for so it can supply the VTEP MAC to use.
//   This is stored in the ARP table (with a timeout) to avoid constantly looking it up.
// - The packet can then be encapsulated but the host needs to know where to send it. This creates another callout from
//   the kernal vxlan code to the flannel daemon to get the public IP that should be used for that VTEP (this gets called
//   an L3 miss). The L2/L3 miss hooks are registered when the vxlan device is created. At the same time a device route
//   is created to the whole flannel network so that non-local traffic is sent over the vxlan device.
//
// In this scheme the scaling of table entries (per host) is:
//  - 1 route (for the configured network out the vxlan device)
//  - One arp entry for each remote container that this host has recently contacted
//  - One FDB entry for each remote host
//
// The second version of flannel vxlan removed the need for the L3MISS callout. When a new remote host is found (either
// during startup or when it's created), flannel simply adds the required entries so that no further lookup/callout is required.
//
//
// The latest version of the vxlan backend  removes the need for the L2MISS too, which means that the flannel deamon is not
// listening for any netlink messages anymore. This improves reliability (no problems with timeouts if
// flannel crashes or restarts) and simplifies upgrades.
//
// How it works:
// Create the vxlan device but don't register for any L2MISS or L3MISS messages
// Then, as each remote host is discovered (either on startup or when they are added), do the following
// 1) create routing table entry for the remote subnet. It goes via the vxlan device but also specifies a next hop (of the remote flannel host).
// 2) Create a static ARP entry for the remote flannel host IP address (and the VTEP MAC)
// 3) Create an FDB entry with the VTEP MAC and the public IP of the remote flannel daemon.
//
// In this scheme the scaling of table entries is linear to the number of remote hosts - 1 route, 1 arp entry and 1 FDB entry per host
//
// In this newest scheme, there is also the option of skipping the use of vxlan for hosts that are on the same subnet,
// this is called "directRouting"

大致意思是:

Flannel 一共迭代了 3 个版本:

第一版

每个机器上的 flannel daemon 会创建 VXLAN interface,并把自己注册为 L2MISS 和 L3MISS 事件的 handler。

L2MISS 是在 2 层网络的 miss,也就是从 IP 查找 MAC 这一步的 miss。Flannel daemon 收到 miss 后会查找存储的数据(比如kubernetes是从etcd中查询)来给出对应的 MAC 地址,并将其加入 arp 缓存。

L3MISS 是 host 不知道某个 MAC 地址应该发往哪里时产生的 miss。收到 miss 后给出 ip 地址(比如kubernetes是从etcd中查询),并加入FDB。

这个版本每个机器上需要有:

  • 路由表记录(指向 VXLAN interface)
  • 目标容器或者虚拟机的ARP表记录
  • MAC和主机对应的FDB表记录

第二版

去掉 L3MISS handler。每次新机器加入集群时,直接添加在所有主机上添加好所需的FDB记录。

第三版

去掉 L2MISS handler。需要添加路由表记录,这些路由表记录和前面不同的是,除了将路由指向 VXLAN interface,还指定了通过 VXLAN 之后下一跳的地址(对端主机VTEP的网卡地址)。

这样就只需要每个主机 1 条 arp 记录,以及每个主机 1 条 fdb 记录(这个不理解可以看下面........)。

这样 flannel daemon就不需要监听任何内核的事件,只需要在机器加入、退出集群的时候维护好这些记录。即使 flannel daemon 挂了整个 overlay 网络还是能(在很长一段时间内)正常运行。

###################################################################

但是目前现在在用的应该都是0.9之前的版本,也就是The first versions 或者 The second version 

新版本的好处:

1.flannel daemon不需要监听任何内核的事件,只需要在机器加入、退出集群的时候维护好这些记录即可。即使 flannel daemon 挂了整个 overlay 网络还是能(在很长一段时间内)正常运行。

2.为了弥补 l2miss 和 l3miss 的缺陷,flannel这个新的版本采用的是三层路由的实现方案。

3. 宿主机上不需要配置所有的虚拟机/容器的二层MAC地址,从一个二层寻址转换成三层寻址(这个其实官方github没提....),路由数目与Host 机器数呈线性相关,官方声称做到了同一个 VNI 下每一台 Host 主机 1 route,1 arp entry and 1 FDB entry(这个官方github提了!!!,这个是个优点!!!)。

 

如何理解这个二层寻址转换为三层寻址呢(官方没提,可以不用太纠结了,反正要到最终的容器,比如通过网桥进去,而从vtep0到网桥,应该都是通过路由吧....)?参考https://www.sdnlab.com/21143.html 这个文章的内容,梳理如下

VXLAN简单来讲就是在Underlay网络(现有的3层网络)之上使用隧道技术依托UDP协议层构建的Overlay的逻辑网络,并能灵活穿透三层Underlay网络,使逻辑网络与物理网络解耦,实现灵活的组网需求,不仅仅能适配VM虚拟机环境,还能用于Container容器环境。

这里网络数据包转发的核心是 RIB 路由表、FDB 转发表、ARP 路由表,即 vxlan 要解决二层 Guest MAC 地址寻址、跨三层 Guest IP 地址寻址的问题,并实现全网高效路由分发和同步,Guest是指虚拟机或者容器,这里讨论容器生态中 Flannel 的实现方案。

The first version(handler for both "L2" and "L3" misses)

根据《Kubernetes网络权威指南》1.7.3节,得知一个VXLAN报文需要确定两个地址信息:
1.内层报文(对应目的虚拟机/容器)的MAC地址
2.外层报文(对应目的虚拟机/容器所在宿主机上的VTEP)IP地址,接备注2

备注:

1.0.9版本之前,不给VTEP设置IP和MAC地址

2.flannel VTEP的对外IP地址可通过flannel的启动参数-iface=eth0指定,若不指定则按默认网关插队网络接口对应的IP。 ------摘自《Kubernetes网络权威指南》5.3.3节 2.VXLAN,所以VTEP的对外IP就是宿主机的IP

因为目前Kubernetest只支持单网络,所以再三层网络上只有1个VXLAN网络,所以flannel会在集群的节点上新创建一个flannel.1(命令规则为flannel.[VNI],VNI默认为1)的VXLAN网卡

 原来的二层以太网帧中的MAC头部是目标虚拟机/容器的MAC地址 

 

模拟组网:

 

 

 

图中 10.20.1.4 与 10.20.1.3 通信流程:

  1. 当 Guest0 第一次发送一个目的地址 10.20.1.3 数据包的时候,进行二层转发,查询本地 Guest0 ARP 表,无记录则发送 ARP 广播 who is 10.20.1.3
  2. vxlan 开启了的本地 ARP 代答 proxy、l2miss、l3miss 功能,数据包经过 vtep0 逻辑设备时,当 Guest0 ARP 表无记录时,vxlan 触发 l2miss 事件,ARP表是用于三层IP到二层MAC转发的映射表,存储着 IP-MAC-NIC 记录,在二层转发过程中往往需要根据 IP 地址查询对应的 MAC 地址从而通过数据链路转发到目的接口中;
  3. l2miss 事件被 Flannel 的 Daemon 进程捕捉到,Daemon 查询 Etcd 存储的路由数据库并返回 10.20.1.3 的 MAC 地址 e6:4b:f9:ce:d7:7b 并存储 Host ARP 表;
  4. vtep0 命中 ARP 记录后回复 ARP Reply;
  5. Guest0 收到 ARP Reply 后存 Guest ARP 表,开始发送数据,携带目的 e6:4b:f9:ce:d7:7b 地址;
  6. 数据包经过 bridge 时查询 FDB(Forwarding Database entry) 转发表,询问 where e6:4b:f9:ce:d7:7b send to? 如未命中记录,发生 l3miss 事件,FDB 表为 2 层交换机的转发表,FDB 存储这 MAC-PORT 的映射关系,用于 MAC数据包从哪个接口出;
  7. Flannel Daemon 捕捉 l3miss 事件,并向 FDB 表中加入目的 e6:4b:f9:ce:d7:7b 的数据包发送给对端 Host 192.168.100.3 ;
  8. 此时 e6:4b:f9:ce:d7:7b 数据包流向 vtep0 接口,vtep0 开始进行 UDP 封装,填充 VNI 号为 1,并与对端 192.168.100.3 建立隧道,对端收到 vxlan 包进行拆分,根据 VNI 分发 vtep0 ,拆分后传回 Bridge,Bridge 根据 dst mac 地址转发到对应的 veth 接口上(这块就是到对端后的二层寻址),此时就完成了整个数据包的转发;
  9. 回程流程类似; 

模拟验证

环境:

  1. 2 台 Centos7.x 机器,2 张物理网卡
  2. 2 个 Bridge,2 张 vtep 网卡
  3. 2 个 Namespace,2 对 veth 接口

步骤:

  1. 创建 Namespace 网络隔离空间模拟 Guest 环境
  2. 创建 veth 接口、Bridge 虚拟交换机、vtep 接口
  3. 验证 l2miss 和 l3miss 通知事件
  4. 配置路由
  5. 验证连通性,Guest0 ping Guest1

准备环境

网口配置如下:

# Host0
[root@i-7dlclo08 ~]# ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:ca:9d:db:ff brd ff:ff:ff:ff:ff:ff promiscuity 0
    inet 192.168.100.2/24 brd 192.168.100.255 scope global dynamic eth0
       valid_lft 24182sec preferred_lft 24182sec
    inet6 fe80::76ef:824d:95ef:18a3/64 scope link
       valid_lft forever preferred_lft forever
48: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP qlen 1000
    link/ether 5a:5f:4f:3c:4d:a6 brd ff:ff:ff:ff:ff:ff promiscuity 0
    bridge forward_delay 1500 hello_time 200 max_age 2000
    inet 10.20.1.1/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::585f:4fff:fe3c:4da6/64 scope link
       valid_lft forever preferred_lft forever
50: veth0@if49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP qlen 1000
    link/ether 82:17:03:c5:a5:bf brd ff:ff:ff:ff:ff:ff link-netnsid 1 promiscuity 1
    veth
    bridge_slave
    inet6 fe80::8017:3ff:fec5:a5bf/64 scope link
       valid_lft forever preferred_lft forever
51: vtep0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN qlen 1000
    link/ether 52:2d:1f:cb:13:55 brd ff:ff:ff:ff:ff:ff promiscuity 1
    vxlan id 1 dev eth0 srcport 0 0 dstport 4789 nolearning proxy l2miss l3miss ageing 300
    bridge_slave
 
# Host1
[root@i-hh5ai710 ~]# ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:d5:9b:94:4c brd ff:ff:ff:ff:ff:ff promiscuity 0
    inet 192.168.100.3/24 brd 192.168.100.255 scope global dynamic eth0
       valid_lft 30286sec preferred_lft 30286sec
    inet6 fe80::baef:a34c:3194:d36e/64 scope link
       valid_lft forever preferred_lft forever
87: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP qlen 1000
    link/ether d6:ca:34:af:d7:fd brd ff:ff:ff:ff:ff:ff promiscuity 0
    bridge forward_delay 1500 hello_time 200 max_age 2000
    inet 10.20.1.1/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::d4ca:34ff:feaf:d7fd/64 scope link
       valid_lft forever preferred_lft forever
89: veth0@if88: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP qlen 1000
    link/ether 42:3b:18:50:10:d6 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 1
    veth
    bridge_slave
    inet6 fe80::403b:18ff:fe50:10d6/64 scope link
       valid_lft forever preferred_lft forever
90: vtep0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN qlen 1000
    link/ether 52:2f:17:7c:bc:0f brd ff:ff:ff:ff:ff:ff promiscuity 1
    vxlan id 1 dev eth0 srcport 0 0 dstport 4789 nolearning proxy l2miss l3miss ageing 300
    bridge_slave

观察 l2miss 和 l3miss 通知事件

配置ARP和FDB

[root@i-7dlclo08 ~]# ip n add 10.20.1.3 lladdr e6:4b:f9:ce:d7:7b dev vtep0    # ip n 等价于ip neighbour即查看邻居表,查看接入你所在的局域网的设备的MAC地址
[root@i-7dlclo08 ~]# bridge fdb add e6:4b:f9:ce:d7:7b dst 192.168.100.3 dev vtep0

【【【【回程路由类似!!!!,不赘述】】】】】

测试连通性

[root@i-7dlclo08 ~]# ip netns exec ns0 ping 10.20.1.3
PING 10.20.1.3 (10.20.1.3) 56(84) bytes of data.
64 bytes from 10.20.1.3: icmp_seq=1 ttl=64 time=1.04 ms
64 bytes from 10.20.1.3: icmp_seq=2 ttl=64 time=0.438 ms

配置好两端的ARP和FDB后,网络连通成功。成功配置所有互通的ARP和FDB信息后,Overlay 的数据包能成功抵达最终目的 Host 的目的虚拟机/容器网络接口上。这种方式存在明显的缺陷:

l2miss 和 l3miss 方案缺陷

  1. 每一台 Host 需要配置所有互通需要的ARP和FDB表(这块改了原文章路由的说法,不太理解为啥是路由,可以回头在看下是不是原作者笔误.......)
  2. 通过 netlink 通知学习路由的效率不高
  3. Flannel Daemon 异常后无法持续维护 ARP 和 FDB 表,从而导致网络不通

 

New version (>=0.9)

三层路由 vxlan 实现方案:为了弥补 l2miss 和 l3miss 的缺陷,flannel 改用了三层路由的实现方案。

对照上方,新版本封装一个VXLAN报文需要确定两个地址信息:
1.目的VTEP设备的MAC地址是什么----ARP表
2.目的VTEP设备的MAC对应的宿主机IP----FDB表

数据包格式:

 

 

 

理论基础

组网:

Flannel 在最新 vxlan 实现上完全去掉了 l2miss & l3miss 方式,Flannel deamon 不再监听 netlink 通知,因此也不依赖内核的 vxlan DOVE 机制。而改成主动给目的子网添加远端 Host 路由的新方式,同时为 vtep 和 bridge 各自分配三层 IP 地址,当数据包到达目的 Host 后,在内部进行三层转发,这样的好处就是 Host 不需要配置所有的 Guest 二层 MAC 地址,从一个二层寻址转换成三层寻址,路由数目与 Host 机器数呈线性相关,官方声称做到了同一个 VNI 下每一台 Host 主机 1 route,1 arp entry and 1 FDB entry。

模拟验证

环境:

  1. 2 台 Centos7.x 机器,2张网卡
  2. 2 个 Bridge,2 张 vtep 网卡
  3. 2 个 Namespace,2 对 veth 接口

步骤:

  1. 创建 Namespace 网络隔离空间模拟 Guest 环境
  2. 创建 veth 接口、Bridge 虚拟交换机、vtep 接口
  3. 配置路由
  4. 验证连通性,Guest0 ping Guest1

准备环境

网口配置如下:

路由 Host 配置

【【【【回程路由类似!!!!】】】】

测试连通性

[root@i-7dlclo08 ~]# ip netns exec ns0 ping 10.20.2.4
PING 10.20.2.4 (10.20.2.4) 56(84) bytes of data.
64 bytes from 10.20.2.4: icmp_seq=1 ttl=62 time=0.992 ms
64 bytes from 10.20.2.4: icmp_seq=2 ttl=62 time=0.518 ms

可以看到,通过增加一条三层路由 10.20.2.0/24 via 10.20.2.0 dev vtep0 onlink 使目标为 10.20.2.0/24 的目的 IP 包通过 vtep0 接口送往目的 Host1,目的 Host1 收到后,Host1的内核网络栈会发现这个数据帧里有 VXLAN Header,并且 VNI=1。所以 Linux 内核会对它进行拆包,拿到里面的内部数据帧,然后根据 VNI 的值,把它交给Host1上的 vtep0 设备,因为vtep0和br0都有ip地址,通过做三层转发,最终送往 veth0 接口(通过路由转发可以实现,不依靠二层MAC寻址啦啦啦啦啦,开始的数据包里面也没有封装目的容器的MAC地址----这块也和上面的纠结点有关,官方没提,可以忽略.....)。在 Host 多个 Guest 场景下也无需额外配置 Guest 路由,从而减少路由数量,方法变得高效。

 

VXLAN The first version和0.9version的本质区别

first version

1.在源host给目的子网添加路由,出口设备是flannel.1,但是下一跳不是目的host的VTEP IP(可以随便写一个,不会用到),因为这个版本VTEP没有配置IP。这个路由是给从网桥出来后使用的,数据会流向到flannel.1

2.源host需要知道每个目标容器的MAC地址,这个根据容器数量,导致ARP表有会很多条目。

3.源host的flannel.1查询的FDB,需要根据每个目标容器的MAC地址查询转发的VTEP IP,因为这个版本VTEP没有配置IP,所以获取的是目标host的IP,同理,这个根据容器数量,FDB表会有很多条目。

0.9 version

1.在源host给目的子网添加路由,出口设备是flannel.1,且下一跳不是目的host的VTEP IP,这个版本VTEP有配置IP。这个路由是给从网桥出来后使用的,数据会流向到flannel.1,封包时目的MAC地址是目标host VTEP的MAC地址

2.源host创建一条目的host VTEP的IP 和 目的host VTEP的MAC的记录,这个版本会给VTEP设置IP和MAC

3.源host创建一条FDB记录,内容为 目标hostVTEP的MAC和目标host的IP(the public IP of the remote flannel daemon.

导致的区别:

1.最外层都需要通过FDB获取的目的host的IP地址,但是first version二层帧中封装的是目的host容器的MAC地址,0.9version二层帧中封装的是目的host VTEP的MAC地址。

效果:

通过最外层host的IP都可以到达目的host的VTEP设备,VTEP--->cni网桥/docker网桥--->容器

 

 

UDP和VXLAN模式说明及区别

1.flannel的UDP模式说明

该模式提供的其实是一个三层的Overlay网络,即:首先对发出端的IP包进行UDP封装,然后在接收端进行接封装拿到原始IP包,进而吧这个IP包转发给目标容器。就好比,Flannel在不同宿主机上的两个容器之间打通了一条“隧道”,使得这两个容器可以直接使用IP地址进行通信,而无需关注容器和宿主机的分布情况。

UDP模式下的tun设备 flannel0 封装的是RAW IP数据包(无MAC信息),补充:TUN设备是一种工作在三层(Network Layer)的虚拟网络设备,TUN设备的功能非常简单,即:在操作系统内核和用户应用程序之间传递IP包

 

节点A和节点B指的是容器所在的宿主机,所以可以在同一个网段(则目的MAC是目标宿主机的MAC地址),也可以不在同一个网段只要IP互通即可(目的MAC是发起端宿主机路由网关的MAC地址)。

到达目的主机后,目的主机的flanneld进程将UDP包解封后得到RAW IP包,解封后的RAW IP包匹配到目的主机的路由规则,内核通过查本机的路由表将RAW IP包发送给cni0或者docker0网桥,然后网桥会扮演一个二层交换机的角色,将数据包发给正确的端口,进而通过Veth Pair设备进度到容器的Network Namespace里

2.flannel的VXLAN模式说明

VXLAN覆盖网络的设计思想是:在现有三层网络之上,“覆盖”一层虚拟的、由内核VXLAN模块负责维护的二层的Overlay网络,使得连接在这个VXLAN二层网络上的“主机”(虚拟机或容器)之间,可以像在同一个局域网(LAN)里那样自由通信。当然实际上,这些“主机”可能分布在不同的宿主机上,甚至分布在不同的物理机房。

而为了能够在二层网络上打通“隧道”,VXLAN会在宿主机上设置一个特殊的网络设备作为“隧道”的两端,这个设备就叫做VTEP,即VXLAN Tunnel End Point(虚拟隧道断点)。

而VTEP的作用,就和UDP模式中的flannel进程非常相似。只不过,它进行封装和解封装的对象是二层数据帧(Ethernet frame),且这个工作的执行流程都是在内核完成的(因为VXLAN本身就是Linux内核中的一个模块)

3.flannel的Host-gw模式说明

和VXLAN对比如下(左边是VXLAN,右边是Host-gw)

host-gw模式下,各个节点之间的跨节点网络通信要通过节点上的路由表实现,因此必须要通信双方所在的宿主机能够直接路由。这就要求host-gw模式下的机器中所有节点必须处于同一个网络内(VXLAN不也是吗.....) ,这个限制使得host-gw模式无法适用于集群规模较大且需要进行网段划分的场景。

host-gw的另外一个限制是随着集群中节点规模的增大,flannel维护主机成千上万的路由表的动态更新也是不小的压力,因为在路由方式下,路由表规则的数量是限制网络规模的一个重要因素,Calico会解决。

host-gw模式下,flannel的唯一作用就是负责主机上路由表的动态刷新。然而只能修改各个主机上的路由表,一旦主机之间隔了其他路由设备,比如三层路由器,这个包就会在路由设备上被丢掉,这样一来,host-gw模式就只能用于二层直接可达的网络,但是由于广播风暴的问题,这种网络通常是比较小规模的。近年来,也出现一些转码的设备能够构建出大规模的二层网络(这个就是我们经常听到的大二层网络)

4.flannel官方推荐使用VXLAN

Flannel may be paired with several different backends. Once set, the backend should not be changed at runtime.

VXLAN is the recommended choice. host-gw is recommended for more experienced users who want the performance improvement and whose infrastructure support it (typically it can't be used in cloud environments). UDP is suggested for debugging only or for very old kernels that don't support VXLAN.

参考:https://coreos.com/flannel/docs/0.10.0/backends.html

 

 

 

 

其他补充:

1.如果目标IP和源IP不在相同网段,则目标MAC是网关的MAC地址

MAC地址:传输过程中,每经过一台三层设备都会改变

IP地址:传输过程中,不会改变,除非做了策略,例如NAT

 

posted @ 2020-07-09 19:13  番茄土豆西红柿  阅读(574)  评论(0编辑  收藏  举报
TOP