Flannel中vxlan backend的原理和實(shí)現(xiàn)

這次分享介紹Flannel中的vxlan backend,包含兩方面內(nèi)容:

?????? 深入理解內(nèi)核中的VXLAN原理:使用iproute2和bridge等原生工具來搭建一個(gè)基于VXLAN的Overlay網(wǎng)絡(luò)。

?????? 理解Flannel使用vxlan backend時(shí)的工作原理: 有了前面對內(nèi)核VXLAN原理的理解,通過分析Flannel部分源碼來從根本上掌握其vxlan backend的原理。

一、VXLAN的原理

? ? ? ? Virtual eXtensible Local Area Network(VXLAN)是一個(gè)在已有的3層物理網(wǎng)絡(luò)上構(gòu)建2層邏輯網(wǎng)絡(luò)的協(xié)議。

?????? 在2012年底的v3.7.0之后,Linux Kernel加入了VXLAN協(xié)議支持,作者:Stephen Hemminger,所以如果要使用Linux Kernel中的VXLAN支持,最低內(nèi)核版本3.7+(推薦3.9+)。

?????? Stephen Hemminger同時(shí)也實(shí)現(xiàn)了iproute2、bridge等工具,用以管理Linux中復(fù)雜的網(wǎng)絡(luò)配置,目前在絕大多數(shù)Linux發(fā)行版中都是默認(rèn)支持的。

?????? VXLAN本質(zhì)上是一種tunnel(隧道)協(xié)議,用來基于3層網(wǎng)絡(luò)實(shí)現(xiàn)虛擬的2層網(wǎng)絡(luò)。泛泛地說,tunnel協(xié)議有點(diǎn)像今天電話會議,通過可視電話連接不同的會議室讓每個(gè)人能夠直接交談,就好像坐在一個(gè)會議室里一樣。很多tunnel協(xié)議,如GRE也有類似VXLAN中VNI的用法。

????? tunnel協(xié)議的另外一個(gè)重要的特性就是軟件擴(kuò)展性,是軟件定義網(wǎng)絡(luò)(Software-defined Network,SDN)的基石之一。

????? Flannel中有兩個(gè)基于tunnel協(xié)議的backend:UDP(默認(rèn)實(shí)現(xiàn))和VXLAN,本質(zhì)上都是tunnel協(xié)議,區(qū)別僅僅在于協(xié)議本身和實(shí)現(xiàn)方式。

?????? 這里順便提一句:tunnel協(xié)議在比較老的內(nèi)核中已經(jīng)有支持,我印象中v2.2+就可以使用tunnel來創(chuàng)建虛擬網(wǎng)絡(luò)了,因此UDP backend適合在沒有vxlan支持的linux版本中使用,但性能會相比vxlan backend差一些。

?以上是一些背景介紹,下面開始介紹VXLAN的內(nèi)核支持

圖1. VXLAN可以在分布多個(gè)網(wǎng)段的主機(jī)間構(gòu)建2層虛擬網(wǎng)絡(luò)

圖2. VXLAN基本原理:套路還是tunnel那一套,區(qū)別僅僅在于tunnel協(xié)議本身的實(shí)現(xiàn)

?????? 為了說明圖1和圖2中談到的VXLAN原理,這里在兩臺不同網(wǎng)段的VPS上手動(dòng)搭建一個(gè)Overlay Network,并在兩個(gè)節(jié)點(diǎn)上分別運(yùn)行了Docker Container,當(dāng)我們看到容器之間使用虛擬網(wǎng)絡(luò)的IP完成直接通信時(shí),實(shí)驗(yàn)就成功了。

圖3 手動(dòng)搭建vxlan虛擬網(wǎng)絡(luò)的網(wǎng)絡(luò)拓?fù)?/p>

圖3中提到一個(gè)VTEP的概念,全稱VXLAN Tunnel Endpoint,本質(zhì)上就是前面提到的tunnel中的endpoint

現(xiàn)在正式開始手動(dòng)搭建圖 3中的虛擬網(wǎng)絡(luò)

第一步、創(chuàng)建docker bridge

?????? 默認(rèn)的docker bridge地址范圍是172.17.0.1/24(比較老的版本是172.17.42.1/24), 而本實(shí)驗(yàn)中兩個(gè)節(jié)點(diǎn)node1和node2的子網(wǎng)要求分別為: 192.1.78.1/24,192.1.87.1/24 。

????? 修改docker daemon啟動(dòng)參數(shù),增加以下參數(shù)后重啟docker daemon:

node1: --bip=192.1.78.1/24

node2: --bip=192.1.87.1/24

?????? 這時(shí)node1和node2的容器之間還不能直接通信, node1也不能跨主機(jī)和node2上的容器直接通信,反之node2也無法直接和node1上的容器通信.。

第二步、創(chuàng)建VTEPs

在node1上執(zhí)行以下命令:

PREFIX=vxlan

IP=$external-ip-of-node-1

DESTIP=$external-ip-of-node-2

PORT=8579

VNI=1

SUBNETID=78

SUBNET=192.$VNI.0.0/16

VXSUBNET=192.$VNI.$SUBNETID.0/32

DEVNAME=$PREFIX.$VNI

ip link delete $DEVNAME

ip link add $DEVNAME type vxlan id $VNI dev eth0 local $IP dstport $PORT nolearning

echo '3' > /proc/sys/net/ipv4/neigh/$DEVNAME/app_solicit

ip address add $VXSUBNET dev $DEVNAME

ip link set $DEVNAME up

ip route delete $SUBNET dev $DEVNAME scope global

ip route add $SUBNET dev $DEVNAME scope global

node2上執(zhí)行以下命令:

PREFIX=vxlan

IP=$external-ip-of-node-2

DESTIP=$external-ip-of-node-1

VNI=1

SUBNETID=87

PORT=8579

SUBNET=192.$VNI.0.0/16

VXSUBNET=192.$VNI.$SUBNETID.0/32

DEVNAME=$PREFIX.$VNI

ip link delete $DEVNAME

ip link add $DEVNAME type vxlan id $VNI dev eth0 local $IP dstport $PORT nolearning

echo '3' > /proc/sys/net/ipv4/neigh/$DEVNAME/app_solicit

ip -d link show

ip addr add $VXSUBNET dev $DEVNAME

ip link set $DEVNAME up

ip route delete $SUBNET dev $DEVNAME scope global

ip route add $SUBNET dev $DEVNAME scope global

第三步、為VTEP配置forward table

# node1

$ bridge fdb add $mac-of-vtep-on-node-2 dev $DEVNAME dst $DESTIP

#?node2

$ bridge fdb add $mac-of-vtep-on-node-1 dev $DEVNAME dst $DESTIP

第四步、配置Neighbors,IPv4中為ARP Table

# node1

$ ip neighbor add $ip-on-node-2 lladdr $mac-of-vtep-on-node-2 dev vxlan.1

# node2

$ ip neighbor add $ip-on-node-1 lladdr $mac-of-vtep-on-node-1 dev vxlan.1

????? 注意:ARP表一般不會手動(dòng)更新,在VXLAN的實(shí)現(xiàn)中由對應(yīng)的Network Agent監(jiān)聽L3 MISS來 動(dòng)態(tài)更新;這里手動(dòng)添加ARP entry僅僅是為了測試;另外,如果跨主機(jī)訪問多個(gè)IP, 每個(gè)跨主機(jī)的IP就都需要配置對應(yīng)的ARP entry。

????? 以上操作都需要root權(quán)限,完成后整個(gè)Overlay Network就搭建成功了,下面通過測試兩種連通性來總結(jié)本實(shí)驗(yàn):

node1容器與node2上的容器直接通信(容器與跨主機(jī)容器間直接通信)

node1與node2上容器直接通信;node2與node1上容器直接通信(主機(jī)和跨主機(jī)容器之間通信)

????? 先看容器與跨主機(jī)容器間直接通信的測試。

現(xiàn)在node1和node2上分別起一個(gè)busybox:

node1$ docker run -it --rm busybox sh

node1$ ip a

1: lo: mtu 65536 qdisc noqueue qlen 1

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

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

6: eth0@if7: mtu 1500 qdisc noqueue

link/ether 02:42:c0:01:4e:02 brd ff:ff:ff:ff:ff:ff

inet 192.1.78.2/24 scope global eth0

? valid_lft forever preferred_lft forever

inet6 fe80::42:c0ff:fe01:4e02/64 scope link

? valid_lft forever preferred_lft forever

node2$ docker run -it --rm busybox sh

node2$ ip a

1: lo: mtu 65536 qdisc noqueue qlen 1

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

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

10: eth0@if11: mtu 1500 qdisc noqueue

link/ether 02:42:c0:01:57:02 brd ff:ff:ff:ff:ff:ff

inet 192.1.87.2/24 scope global eth0

? valid_lft forever preferred_lft forever

inet6 fe80::42:c0ff:fe01:5702/64 scope link

? valid_lft forever preferred_lft forever

接下來讓我們來享受一下容器之間的連通性。

node1@busybox$ ping -c1 192.1.87.2

PING 192.1.87.2 (192.1.87.2): 56 data bytes

64 bytes from 192.1.87.2: seq=0 ttl=62 time=2.002 ms

node2@busybox$ ping -c1 192.1.78.2

PING 192.1.78.2 (192.1.78.2): 56 data bytes

64 bytes from 192.1.78.2: seq=0 ttl=62 time=1.360 ms

然后看主機(jī)和跨主機(jī)容器之間連通性的測試。

node1$ ping -c1 192.1.87.2

PING 192.1.87.2 (192.1.87.2) 56(84) bytes of data.

64 bytes from 192.1.87.2: icmp_seq=1 ttl=63 time=1.49 ms

node2$ ping -c1 192.1.78.2

PING 192.1.78.2 (192.1.78.2) 56(84) bytes of data.

64 bytes from 192.1.78.2: icmp_seq=1 ttl=63 time=1.34 ms

具體實(shí)驗(yàn)的截屏可以訪問:https://asciinema.org/a/bavkebqxc4wjgb2zv0t97es9y 。

二、Flannel中vxlan backend實(shí)現(xiàn)

?弄清楚了kernel中vxlan的原理后,就不難理解Flannel的機(jī)制了。

注意:

使用vxlan backend時(shí),數(shù)據(jù)是由Kernel轉(zhuǎn)發(fā)的,F(xiàn)lannel不轉(zhuǎn)發(fā)數(shù)據(jù),僅僅動(dòng)態(tài)設(shè)置ARP entry

而udp backend會承擔(dān)數(shù)據(jù)轉(zhuǎn)發(fā)工具(這里不展開介紹其實(shí)現(xiàn)),UDP backend自帶了一個(gè)C實(shí)現(xiàn)的proxy,連接不同節(jié)點(diǎn)上的tunnel endpoints 這里討論的源碼基于最新穩(wěn)定版v0.7.0。

vxlan backend啟動(dòng)時(shí)會動(dòng)態(tài)啟動(dòng)兩個(gè)并發(fā)任務(wù):

監(jiān)聽Kernel中L3 MISS并反序列化成Golang對象

根據(jù)L3 MISS和子網(wǎng)配置(etcd)來自動(dòng)更新本地neighbor配置

關(guān)于源碼,請看:http://dwz.cn/5MXKuC

最后,F(xiàn)lannel的實(shí)現(xiàn)中有一個(gè)小細(xì)節(jié),在0.7.0中剛剛加入,即VTEP的IP加上了/32位的掩碼避免了廣播,此前的版本都是/16掩碼,解決了VXLAN網(wǎng)絡(luò)中由于廣播導(dǎo)致的“網(wǎng)絡(luò)風(fēng)暴”的問題。

三、總結(jié)一下

Flannel中有多種backend,其中vxlan backend通過內(nèi)核轉(zhuǎn)發(fā)數(shù)據(jù),而udp backend通過用戶態(tài)進(jìn)程中的proxy轉(zhuǎn)發(fā)數(shù)據(jù)

Flannel在使用vxlan backend的時(shí)候,短暫啟停flanneld不會造成網(wǎng)絡(luò)中斷,而udp backend會

很多第三方的網(wǎng)絡(luò)測試表明,udp backend比vxlan backend網(wǎng)絡(luò)的性能差大概1個(gè)數(shù)量級,一般來說只要內(nèi)核支持(v3.9+),建議選擇vxlan backend

Flannel中使用vxlan backend時(shí),建議升級到0.7+,因?yàn)榇饲暗陌姹径即嬖跐撛诘木W(wǎng)絡(luò)風(fēng)暴問題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容