k8s网络
一、同一宿主機(jī)的兩個容器間通信
通過 Veth Pair 設(shè)備 + 宿主機(jī)網(wǎng)橋的方式,實(shí)現(xiàn)了跟同一宿主機(jī)上其他容器通信。
訪問流程:當(dāng)容器1想要跟容器2通信時,IP包會被轉(zhuǎn)發(fā)到容器1的eth0這個網(wǎng)卡上,通過二層網(wǎng)絡(luò)直接發(fā)往目的地,但是二層交換設(shè)備需要MAC地址進(jìn)行轉(zhuǎn)發(fā)(這個 eth0 網(wǎng)卡,是一個 Veth Pair,一段在容器內(nèi)一段在docker0網(wǎng)橋上,此時該虛擬網(wǎng)卡是docker0的一個從設(shè)備)。因此發(fā)送ARP數(shù)據(jù)包,docker0把 ARP 廣播轉(zhuǎn)發(fā)到其他被“插”在 docker0 上的虛擬網(wǎng)卡上,找到容器2的mac地址,然后docker0將mac地址返回給容器1,docker0根據(jù)mac地址,在它的 CAM 表(即交換機(jī)通過 MAC 地址學(xué)習(xí)維護(hù)的端口和 MAC 地址的對應(yīng)表)里查到對應(yīng)的端口(Port),然后將數(shù)據(jù)包轉(zhuǎn)發(fā)到該端口上,此時數(shù)據(jù)包流入容器2的eth0上(容器2的網(wǎng)卡也是Veth Pair)
?
二、跟其他宿主機(jī)通信
當(dāng)跟容器外的宿主機(jī)通信時,首先經(jīng)過 docker0 網(wǎng)橋出現(xiàn)在宿主機(jī)上(類似上面的分析)。然后根據(jù)宿主機(jī)的路由表里的直連路由規(guī)則,對 10.168.0.3 的訪問請求就會交給宿主機(jī)的 eth0去處理,然后將這個數(shù)據(jù)包轉(zhuǎn)發(fā)到10.168.0.3宿主機(jī)的eth0上。
?
三、容器跨主機(jī)通信
Overlay Network(覆蓋網(wǎng)絡(luò)):通過軟件的方式,創(chuàng)建一個整個集群公用的網(wǎng)橋,將所有容器連在這個網(wǎng)橋上。每個宿主機(jī)上都有一個特殊的網(wǎng)橋,能將數(shù)據(jù)包發(fā)到正確的宿主機(jī)上。
?
Flannel?
目前,Flannel 支持三種后端實(shí)現(xiàn),分別是:
1、VXLAN;
2、host-gw;
3、UDP。
3.1 flannel UDP模式
當(dāng)容器1和容器2通信時。容器1發(fā)起ip包,源地址為容器1的ip地址,目的地址為容器2的ip地址。而容器2的地址并不在docker0的網(wǎng)橋上,因此由默認(rèn)路由規(guī)則處理,然后出現(xiàn)在宿主機(jī)
上。宿主機(jī)跟劇路由規(guī)則,將IP包轉(zhuǎn)發(fā)到flannel0上,flannel0將這個ip包交給flannel進(jìn)程也就是flanneld(flannel0是一個tunnel設(shè)備,這里內(nèi)核態(tài)變?yōu)橛脩魬B(tài))。flanneld將這個ip包封裝成一個UDP包,UDP包的源地址為Node1的ip地址,目的地址為Node2的ip地址,每臺宿主機(jī)上的 flanneld,都監(jiān)聽著一個 8285 端口,所以 flanneld 只要把 UDP 包發(fā)往 Node 2的8235端口即可。Node2的flanneld從UDP包里解析出容器1發(fā)給容器2的IP包,flanneld 會直接把這個 IP 包發(fā)送給它所管理的TUN 設(shè)備,即 flannel0 設(shè)備。Linux 內(nèi)核網(wǎng)絡(luò)棧就會負(fù)責(zé)處理這個 IP 包,具體的處理方法,就是通過本機(jī)的路由表來尋找這個 IP 包的下一步流向。Linux 內(nèi)核就會按照這條路由規(guī)則,把這個 IP 包轉(zhuǎn)發(fā)給docker0網(wǎng)橋,docker0 網(wǎng)橋會扮演二層交換機(jī)的角色,將數(shù)據(jù)包發(fā)送給正確的端口,進(jìn)而通過 Veth Pair設(shè)備進(jìn)入到容器2 的 Network Namespace 里。
這里如何知道UDP包的目的IP地址呢?
在flannel管理的網(wǎng)絡(luò)里面,每個宿主機(jī)上的容器都屬于分配給這個宿主機(jī)的子網(wǎng)。而這些子網(wǎng)和宿主機(jī)的對應(yīng)關(guān)系存放在etcd數(shù)據(jù)庫里面,所以,flanneld 進(jìn)程在處理由 flannel0 傳入ip包時,可以根據(jù)目的地址找到對應(yīng)的子網(wǎng),從而找到對應(yīng)的宿主機(jī),在etcd中找到對應(yīng)宿主機(jī)的ip地址。
?
?UDP 模式有嚴(yán)重的性能問題:
相比于兩臺主機(jī)直接通信,flannel UDP多了一個步驟,flanneld的處理過程。由于使用了flannel0這個tunnel設(shè)備,僅在發(fā)送IP包的過程,就經(jīng)歷了三次內(nèi)核態(tài)和用戶態(tài)的數(shù)據(jù)拷貝。如下圖:
?
3.2 flannel VXLAN模式
(解決flannel UDP內(nèi)核態(tài)用戶態(tài)互相轉(zhuǎn)換效率問題)
VXLAN 可以完全在內(nèi)核態(tài)實(shí)現(xiàn)上述封裝和解封裝的工作,從而通過與前面相似的“隧道”機(jī)制,構(gòu)建出覆蓋網(wǎng)絡(luò)(Overlay Network)。
而為了能夠在二層網(wǎng)絡(luò)上打通“隧道”,XLAN 會在宿主機(jī)上設(shè)置一個特殊的網(wǎng)絡(luò)設(shè)備作為“隧道”的兩端。這個設(shè)備就叫作 VTEP,即:VXLAN Tunnel End Point。
而 VTEP 設(shè)備的作用,其實(shí)跟前面的 flanneld 進(jìn)程非常相似。只不過,它進(jìn)行封裝和解封裝的對象,是二層數(shù)據(jù)幀(Ethernet frame);而且這個工作的執(zhí)行流程,全部是在內(nèi)核里完成的(因?yàn)?VXLAN 本身就是 Linux 內(nèi)核中的一個模塊)。
?
與前面UDP模式類似,當(dāng)容器1發(fā)出請求后,這個目的地址是容器2的ip地址,首先會出現(xiàn)在docker0網(wǎng)橋上,然后被路由到本機(jī)flannel.1設(shè)備進(jìn)行處理,也就是來到了隧道的入口,我們把這個ip稱為“原始ip包”。
為了能將原始ip包封裝并發(fā)送到正確的宿主機(jī),VXLAN就需要找到這條隧道的出口,即目的宿主機(jī)的VTEP設(shè)備。這個設(shè)備就是每臺宿主機(jī)上的flanneld進(jìn)程負(fù)責(zé)維護(hù)的。
比如,當(dāng) Node 2 啟動并加入 Flannel 網(wǎng)絡(luò)之后,在 Node 1(以及所有其他節(jié)點(diǎn))上,flanneld 就會添加一條如下所示的路由規(guī)則:凡是發(fā)往 10.1.16.0/24 網(wǎng)段的 IP 包,都需要經(jīng)過 flannel.1 設(shè)備發(fā)出,并且,它最后被發(fā)往的網(wǎng)關(guān)地址是:10.1.16.0。
然后根據(jù)ARP表(flanneld進(jìn)程在Node2節(jié)點(diǎn)啟動時,自動加在Node1上的),找到目的VTEP設(shè)備的ip地址對應(yīng)的MAC地址。
?有了目的VTEP設(shè)備的MAC地址,Linux內(nèi)核將原始ip包封裝成“內(nèi)部數(shù)據(jù)幀”,二層幀格式如下:
然后,Linux 內(nèi)核會把這個數(shù)據(jù)幀封裝進(jìn)一個UDP 包里發(fā)出去。
此時,flannel.1扮演一個網(wǎng)橋的角色,在二層網(wǎng)絡(luò)進(jìn)行UDP包的轉(zhuǎn)發(fā)。而在 Linux 內(nèi)核里面,“網(wǎng)橋”設(shè)備進(jìn)行轉(zhuǎn)發(fā)的依據(jù),來自于一個叫作 FDB(ForwardingDatabase)的轉(zhuǎn)發(fā)數(shù)據(jù)庫。這個 flannel.1“網(wǎng)橋”對應(yīng)的 FDB 信息,也是 flanneld 進(jìn)程負(fù)責(zé)維護(hù)的。它的內(nèi)容可以通過 bridge fdb 命令查看到發(fā)往我們前面提到的“目的 VTEP 設(shè)備”的二層數(shù)據(jù)幀,應(yīng)該通過 flannel.1 設(shè)備,發(fā)往 IP 地址為 10.168.0.3 的主機(jī)。顯然,這臺主機(jī)正是 Node 2,UDP 包要發(fā)往的目的地(目的宿主機(jī)ip)就找到了。
所以接下來的流程,就是一個正常的、宿主機(jī)網(wǎng)絡(luò)上的封包工作。
Node2接收到數(shù)據(jù)幀后,內(nèi)核網(wǎng)會發(fā)現(xiàn)這個數(shù)據(jù)幀有絡(luò)棧里面有VXLAN Header,并且VNI=1.所以Linux內(nèi)核會對它進(jìn)行拆包,拿到內(nèi)部數(shù)據(jù)幀,然后根據(jù)VIN的值,把它交給Node2上的flannel.1設(shè)備。flannel.1會進(jìn)一步拆包,取出原始ip包。接下來回到上面講的單機(jī)容器網(wǎng)絡(luò)處理流程,最終ip包到容器2的network namespace中。
?
3.3 Flannel host-gw 模式
當(dāng)你設(shè)置 Flannel 使用 host-gw 模式之后,flanneld 會在宿主機(jī)上創(chuàng)建這樣一條規(guī)則,以Node 1 為例:目的 IP 地址屬于 10.244.1.0/24 網(wǎng)段的IP 包,應(yīng)該經(jīng)過本機(jī)的 eth0 設(shè)備發(fā)出去(即:dev eth0);并且,它下一跳地址(next-hop)是 10.168.0.3(即:via 10.168.0.3)
?當(dāng)容器1要跟容器2通信的時候,IP包會從網(wǎng)絡(luò)層傳到鏈路層,在數(shù)據(jù)幀上封裝Node2的MAC地址,因此,該ip可以通過Node1的eth0發(fā)到Node2,然后再發(fā)送到容器2
?flannel host-gw 模式必須要求集群宿主機(jī)之間是二層聯(lián)通的。
?
3.4 Calico
Calico 項(xiàng)目提供的網(wǎng)絡(luò)解決方案,與 Flannel 的 host-gw 模式,幾乎是完全一樣的。Calico 也會在每臺宿主機(jī)上,添加一個格式如下所示的路由規(guī)則:
Calico 項(xiàng)目使用BGP(邊界網(wǎng)關(guān)協(xié)議)來自動地在整個集群中分發(fā)路由信息。BGP是一個 Linux 內(nèi)核原生就支持的、專門用在大規(guī)模數(shù)據(jù)中心里維護(hù)不同的“自治系統(tǒng)”之間路由信息的、無中心的路由協(xié)議。AS 1 里面的主機(jī) 10.10.0.2,要訪問AS 2 里面的主機(jī) 172.17.0.3 的話。它發(fā)出的ip包,就會先到達(dá)自治系統(tǒng) AS 1 上的路由器 Router1。Router 1 的路由表里,有這樣一條規(guī)則,即:目的地址是172.17.0.2 包,應(yīng)該經(jīng)過 Router 1 的的 C 接口,發(fā)往網(wǎng)關(guān) Router 2(即:自治系統(tǒng) AS 2 上的路由器)。
?負(fù)責(zé)把自治系統(tǒng)連接在一起的路由器,我們就把它形象地稱為:邊界網(wǎng)關(guān)。
?假如我們的網(wǎng)絡(luò)拓?fù)浣Y(jié)果非常復(fù)雜,可能是由多個自治系統(tǒng)組成的復(fù)合自治系統(tǒng)。這時就可以用BGP協(xié)議。使用BGP之后,可以認(rèn)為在每個邊界網(wǎng)關(guān)上都運(yùn)行著一個小程序,他們會將各自的路由表信息,通過TCP傳輸給其他邊界網(wǎng)關(guān)。而其他邊界網(wǎng)關(guān)上的這個小程序會收到這些數(shù)據(jù)進(jìn)行分析,然后將需要的信息添加到自己的路由表里。所謂 BGP,就是在大規(guī)模網(wǎng)絡(luò)中實(shí)現(xiàn)節(jié)點(diǎn)路由信息共享的一種協(xié)議。
Calico 項(xiàng)目的架構(gòu)就非常容易理解了。它由三個部分組成(它不會在宿主機(jī)上創(chuàng)建任何網(wǎng)橋設(shè)備。):
1、Calico 的 CNI 插件。這是 Calico 與 Kubernetes 對接的部分。
2、Felix。它是一個 DaemonSet,負(fù)責(zé)在宿主機(jī)上插入路由規(guī)則(即:寫入 Linux 內(nèi)核的 FIB 轉(zhuǎn)發(fā)信息庫),以及維護(hù) Calico 所需的網(wǎng)絡(luò)設(shè)備等工作。
3、BIRD。它就是 BGP 的客戶端,專門負(fù)責(zé)在集群里分發(fā)路由規(guī)則信息。
Calico 的 CNI 插件會為每個容器設(shè)置一個 Veth Pair 設(shè)備,然后把其中的一端放置在宿主機(jī)上(它的名字以 cali 前綴開頭)。此外,由于 Calico 沒有使用 CNI 的網(wǎng)橋模式,Calico 的 CNI 插件還需要在宿主機(jī)上為每個容器的 Veth Pair 設(shè)備配置一條路由規(guī)則,用于接收傳入的 IP 包。比如,宿主機(jī) Node 2 上的 Container 4 對應(yīng)的路由規(guī)則,如下所示:
即:發(fā)往 10.233.2.3 的 IP 包,應(yīng)該進(jìn)入 cali5863f3 設(shè)備。
有了這樣的 Veth Pair 設(shè)備之后,容器發(fā)出的 IP 包就會經(jīng)過 Veth Pair 設(shè)備出現(xiàn)在宿主機(jī)上。然后,宿主機(jī)網(wǎng)絡(luò)棧就會根據(jù)路由規(guī)則的下一跳 IP 地址,把它們轉(zhuǎn)發(fā)給正確的網(wǎng)關(guān)。接下來的流程就跟 Flannel host-gw 模式完全一致了。其中,這里最核心的“下一跳”路由規(guī)則,就是由 Calico 的 Felix 進(jìn)程負(fù)責(zé)維護(hù)的。這些路由規(guī)則信息,則是通過 BGP Client 也就是 BIRD 組件,使用 BGP 協(xié)議傳輸而來的。
?
當(dāng)Node1和Node2不在一個子網(wǎng)時,就需要為 Calico 打開 IPIP 模式。
?
?當(dāng)容器1要訪問容器3時,路由規(guī)則的下一跳地址仍然是 Node 2 的 IP 地址,但這一次,要負(fù)責(zé)將 IP 包發(fā)出去的設(shè)備,變成了 tunl0。注意,是 T-U-N-L-0,而不是 Flannel UDP 模式使用的 T-U-N-0(tun0),這兩種設(shè)備的功能是完全不一樣的。Calico 使用的這個 tunl0 設(shè)備,是一個 IP 隧道(IP tunnel)設(shè)備。IP 包進(jìn)入 IP 隧道設(shè)備之后,就會被 Linux 內(nèi)核的 IPIP 驅(qū)動接管。IPIP 驅(qū)動會將這個 IP 包直接封裝在一個宿主機(jī)網(wǎng)絡(luò)的 IP 包中,如下所示:
其中,經(jīng)過封裝后的新的 IP 包的目的地址(圖 5 中的 Outer IP Header 部分),正是原 IP 包的下一跳地址,即 Node 2 的 IP 地址:192.168.2.2。這樣,
原先從容器到 Node 2 的 IP 包,就被偽裝成了一個從 Node 1 到 Node 2 的 IP 包。由于宿主機(jī)之間已經(jīng)使用路由器配置了三層轉(zhuǎn)發(fā),也就是設(shè)置了宿主機(jī)之間的“下一跳”。所以這個 IP 包在離開 Node 1 之后,就可以經(jīng)過路由器,最終“跳”到 Node 2 上。
這時,Node 2 的網(wǎng)絡(luò)內(nèi)核棧會使用 IPIP 驅(qū)動進(jìn)行解包,從而拿到原始的 IP 包。然后,原始 IP 包就會經(jīng)過路由規(guī)則和 Veth Pair 設(shè)備到達(dá)目的容器內(nèi)部。
?
小結(jié):
三層和隧道的異同:
相同之處是都實(shí)現(xiàn)了跨主機(jī)容器的三層互通,而且都是通過對目的 MAC 地址的操作來實(shí)現(xiàn)的;不同之處是三層通過配置下一條主機(jī)的路由規(guī)則來實(shí)現(xiàn)互通,隧道則是通過通過在 IP 包外再封裝一層 MAC 包頭來實(shí)現(xiàn)。
三層的優(yōu)點(diǎn):少了封包和解包的過程,性能肯定是更高的。
三層的缺點(diǎn):需要自己想辦法維護(hù)路由規(guī)則。
隧道的優(yōu)點(diǎn):簡單,原因是大部分工作都是由 Linux 內(nèi)核的模塊實(shí)現(xiàn)了,應(yīng)用層面工作量較少。
隧道的缺點(diǎn):主要的問題就是性能低。
轉(zhuǎn)載于:https://www.cnblogs.com/girl1314/p/10709037.html
總結(jié)
- 上一篇: Spring AOP功能和目标
- 下一篇: CLOUD配置审批流发消息