Kubernetes主流網(wǎng)絡(luò)方案:Flannel 網(wǎng)絡(luò)分析
前言
Flannel是kubernetes的CNI網(wǎng)絡(luò)插件之一,實(shí)質(zhì)上是一種主機(jī) overlay網(wǎng)絡(luò) 。flannel支持多種網(wǎng)絡(luò)轉(zhuǎn)發(fā)模式,常用的是vxlan、hostgw等,我們這里以常用的 udp VXLAN協(xié)議講解。
1
Flannel 特點(diǎn)
使集群中的不同Node主機(jī)創(chuàng)建的Docker容器都具有全集群唯一的虛擬IP地址。
建立一個(gè)覆蓋網(wǎng)絡(luò)(overlay network),通過(guò)這個(gè)覆蓋網(wǎng)絡(luò),將數(shù)據(jù)包原封不動(dòng)的傳遞到目標(biāo)容器。覆蓋網(wǎng)絡(luò)是建立在另一個(gè)網(wǎng)絡(luò)之上并由其基礎(chǔ)設(shè)施支持的虛擬網(wǎng)絡(luò)。覆蓋網(wǎng)絡(luò)通過(guò)將一個(gè)分組封裝在另一個(gè)分組內(nèi)來(lái)將網(wǎng)絡(luò)服務(wù)與底層基礎(chǔ)設(shè)施分離。在將封裝的數(shù)據(jù)包轉(zhuǎn)發(fā)到端點(diǎn)后,將其解封裝。
創(chuàng)建一個(gè)新的虛擬網(wǎng)卡flannel0接收docker網(wǎng)橋的數(shù)據(jù),通過(guò)維護(hù)路由表,對(duì)接收到的數(shù)據(jù)進(jìn)行封包和轉(zhuǎn)發(fā)(vxlan)。
etcd保證了所有node上flanned所看到的配置是一致的。同時(shí)每個(gè)node上的flanned監(jiān)聽(tīng)etcd上的數(shù)據(jù)變化,實(shí)時(shí)感知集群中node的變化。
2
各個(gè)組件的解釋
Cni0 ?:網(wǎng)橋設(shè)備,每創(chuàng)建一個(gè)pod都會(huì)創(chuàng)建一對(duì) veth pair。其中一端是pod中的eth0,另一端是Cni0網(wǎng)橋中的端口(網(wǎng)卡)。Pod從網(wǎng)卡eth0發(fā)出的流量都會(huì)發(fā)送到Cni0網(wǎng)橋設(shè)備的端口(網(wǎng)卡)上。
Cni0 設(shè)備獲得的ip地址是該節(jié)點(diǎn)分配到的網(wǎng)段的第一個(gè)地址。
Flannel.1 : overlay網(wǎng)絡(luò)的設(shè)備,用來(lái)進(jìn)行 vxlan 報(bào)文的處理(封包和解包)。不同node之間的pod數(shù)據(jù)流量都從overlay設(shè)備以隧道的形式發(fā)送到對(duì)端。
Flanneld :flannel在每個(gè)主機(jī)中運(yùn)行flanneld作為agent,它會(huì)為所在主機(jī)從集群的網(wǎng)絡(luò)地址空間中,獲取一個(gè)小的網(wǎng)段subnet,本主機(jī)內(nèi)所有容器的IP地址都將從中分配。同時(shí)Flanneld監(jiān)聽(tīng)K8s集群數(shù)據(jù)庫(kù),為flannel.1設(shè)備提供封裝數(shù)據(jù)時(shí)必要的mac,ip等網(wǎng)絡(luò)數(shù)據(jù)信息。
3
不同node上的pod的通信流程
pod中產(chǎn)生數(shù)據(jù),根據(jù)pod的路由信息,將數(shù)據(jù)發(fā)送到Cni0
Cni0 根據(jù)節(jié)點(diǎn)的路由表,將數(shù)據(jù)發(fā)送到隧道設(shè)備flannel.1
?Flannel.1查看數(shù)據(jù)包的目的ip,從flanneld獲得對(duì)端隧道設(shè)備的必要信息,封裝數(shù)據(jù)包。
Flannel.1將數(shù)據(jù)包發(fā)送到對(duì)端設(shè)備。對(duì)端節(jié)點(diǎn)的網(wǎng)卡接收到數(shù)據(jù)包,發(fā)現(xiàn)數(shù)據(jù)包為overlay數(shù)據(jù)包,解開(kāi)外層封裝,并發(fā)送內(nèi)層封裝到flannel.1設(shè)備。
Flannel.1設(shè)備查看數(shù)據(jù)包,根據(jù)路由表匹配,將數(shù)據(jù)發(fā)送給Cni0設(shè)備。
Cni0匹配路由表,發(fā)送數(shù)據(jù)給網(wǎng)橋上對(duì)應(yīng)的端口。
測(cè)試集群 k8s定義的flannel網(wǎng)絡(luò)(POD CIDR) 為172.20.0.0/16。
下面用用案例解釋網(wǎng)絡(luò)內(nèi)不同POD間通信的一個(gè)網(wǎng)絡(luò)實(shí)現(xiàn)吧

10.19.114.100 - pod1 路由kubectl -n stack exec -it api-0 -- baship route showdefault via 172.20.0.1 dev eth0172.20.0.0/24 dev eth0 proto kernel scope link src 172.20.0.73172.20.0.0/16 via 172.20.0.1 dev eth0

10.19.114.101 - pod2 路由kubectl -n stack exec -it redis-64c6c549ff-5plcq -- baship route showdefault via 172.20.1.1 dev eth0172.20.0.0/16 via 172.20.1.1 dev eth0172.20.1.0/24 dev eth0 proto kernel scope link src 172.20.1.11

由此可看出,默認(rèn)POD 網(wǎng)卡網(wǎng)關(guān)走 .1 網(wǎng)關(guān),而網(wǎng)關(guān)即為cni0 的IP,下一步分析流量到了宿主機(jī)之后的走向~
10.19.114.100 宿主機(jī)路由#ip route -ndefault via 10.19.114.1 dev eth010.19.114.0/24 dev eth0 proto kernel scope link src 10.19.114.10010.250.250.0/24 dev eth1 proto kernel scope link src 10.250.250.100172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1172.20.0.0/24 dev cni0 proto kernel scope link src 172.20.0.1172.20.1.0/24 via 172.20.1.0 dev flannel.1 onlink172.20.2.0/24 via 172.20.2.0 dev flannel.1 onlink
10.19.114.101 宿主機(jī)路由#ip route -ndefault via 10.19.114.1 dev eth010.19.114.0/24 dev eth0 proto kernel scope link src 10.19.114.10110.250.250.0/24 dev eth1 proto kernel scope link src 10.250.250.101172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1172.20.0.0/24 via 172.20.0.0 dev flannel.1 onlink172.20.1.0/24 dev cni0 proto kernel scope link src 172.20.1.1172.20.2.0/24 via 172.20.2.0 dev flannel.1 onlink
由如上路由可知,據(jù)最小匹配原則,匹配到上面的一條路由表項(xiàng)。從10.19.114.100 上去往172.20.1.0/24 網(wǎng)段的包,發(fā)送172.20.1.0 網(wǎng)關(guān),網(wǎng)關(guān)設(shè)備是flannel.1
flannel.1為vxlan設(shè)備,當(dāng)數(shù)據(jù)包來(lái)到flannel.1時(shí),需要將數(shù)據(jù)包封裝起來(lái)。此時(shí)的dst ip 為172.20.1.11,src ip為172.20.0.73。數(shù)據(jù)包繼續(xù)封裝需要知道172.20.1.11 ?ip地址對(duì)應(yīng)的mac地址。此時(shí),flannel.1不會(huì)發(fā)送arp請(qǐng)求去獲得172.20.1.11 的mac地址,而是由Linux kernel將一個(gè)“L3 Miss”事件請(qǐng)求發(fā)送的用戶空間的flanned程序。Flanned程序收到內(nèi)核的請(qǐng)求事件之后,從etcd查找能夠匹配該地址的子網(wǎng)的flannel.1設(shè)備的mac地址,即發(fā)往的pod所在host中flannel.1設(shè)備的mac地址。Flannel在為Node節(jié)點(diǎn)分配ip網(wǎng)段時(shí)記錄了所有的網(wǎng)段和mac等信息,所以能夠知道。
#ip neigh |grep 172172.20.2.0 dev flannel.1 lladdr 82:c4:0e:f2:00:6f PERMANENT172.20.1.0 dev flannel.1 lladdr 42:6e:8b:9b:e2:73 PERMANENT
到這里,vxlan的內(nèi)層數(shù)據(jù)包就完成了封裝。格式是這樣的:
VXLAN的轉(zhuǎn)發(fā)過(guò)程主要依賴于FDB(Forwarding Database)實(shí)現(xiàn), VXLAN設(shè)備根據(jù)MAC地址來(lái)查找相應(yīng)的VTEP IP地址,繼而將二層數(shù)據(jù)幀封裝發(fā)送至相應(yīng)VTEP。
#/sbin/bridge fdb show dev flannel.142:6e:8b:9b:e2:73 dst 10.19.114.101 self permanentba:8b:ce:f3:b8:51 dst 10.19.114.101 self permanent42:6f:c7:06:3e:a0 dst 10.19.114.102 self permanent82:c4:0e:f2:00:6f dst 10.19.114.102 self permanent
kernel需要查看node上的fdb(forwarding database)以獲得內(nèi)層封包中目的vtep設(shè)備所在的node地址。因?yàn)橐呀?jīng)從arp table中查到目的設(shè)備mac地址為42:6e:8b:9b:e2:73,同時(shí)在fdb中存在該mac地址對(duì)應(yīng)的node節(jié)點(diǎn)的IP地址。如果fdb中沒(méi)有這個(gè)信息,那么kernel會(huì)向用戶空間的flanned程序發(fā)起”L2 MISS”事件。flanneld收到該事件后,會(huì)查詢etcd,獲取該vtep設(shè)備對(duì)應(yīng)的node的”Public IP“,并將信息注冊(cè)到fdb中。
當(dāng)內(nèi)核查看fdb獲得了發(fā)往機(jī)器的ip地址后,arp得到mac地址,之后就能完成vxlan的外層封裝。

具體可以通過(guò)wireshark抓包分析

10.19.114.101節(jié)點(diǎn)的eth0網(wǎng)卡接收到vxlan設(shè)備包,kernal將識(shí)別出這是一個(gè)vxlan包,將包拆開(kāi)之后轉(zhuǎn)給節(jié)點(diǎn)上的flannel.1設(shè)備。這樣數(shù)據(jù)包就從發(fā)送節(jié)點(diǎn)到達(dá)目的節(jié)點(diǎn),flannel.1設(shè)備將接收到一個(gè)如下的數(shù)據(jù)包
目的地址為172.20.1.11,到達(dá)10.19.114.101 flannel.1后查找自己的路由表,根據(jù)路由表完成轉(zhuǎn)發(fā),由下圖可知,flannel.1將去往172.20.1.0/24的流量轉(zhuǎn)發(fā)到cni0上去。。

查看cni0網(wǎng)橋信息, cni0 網(wǎng)絡(luò)通過(guò)綁定pod 的網(wǎng)卡和宿主機(jī)網(wǎng)卡,通過(guò)veth實(shí)現(xiàn)通信
#brctl showbridge name bridge id STP enabled interfacescni0 8000.a656432b14cf no veth1f7db117veth3ee31d24veth521bc030veth5a59ced4veth649412bdveth65bbf59fveth6ed62916veth7e8e7733veth9787b6baveth98c762b8vethaf05d94bvethc07c69cdvethdf62bdedvethe2cf7392vethf4995a29docker0 8000.024216a031b6 no
由下圖可知 172.20.1.11 的POD 網(wǎng)卡 對(duì)應(yīng) link-netnsid 0

由下圖可知 172.20.1.11 的POD 網(wǎng)卡 在宿主機(jī)上的veth 為 vethf4995a29

所以在cni0網(wǎng)橋上掛載的pod的veth pair為vethf4995a29 , eth0@if21和vethf4995a29@if3組成的一對(duì)veth,pair。從而將流量注入到pod的eth0網(wǎng)卡上。
- END -
?推薦閱讀? 大白話理解Session和Cookie是什么? 堡壘機(jī)是干什么的? 看完這篇你就懂了 DevOps、CI、CD到底是什么?十分鐘理解 為什么不建議把數(shù)據(jù)庫(kù)部署在Docker容器內(nèi)? 一文搞懂藍(lán)綠發(fā)布、灰度發(fā)布和滾動(dòng)發(fā)布 為什么不建議把數(shù)據(jù)庫(kù)部署在Docker容器內(nèi)? 如何在Kubernetes上部署MySQL數(shù)據(jù)庫(kù)
點(diǎn)亮,服務(wù)器三年不宕機(jī)

