掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
作者 | 中國(guó)移動(dòng)云能力中心PaaS產(chǎn)品部 張永曦

創(chuàng)新互聯(lián)建站秉承實(shí)現(xiàn)全網(wǎng)價(jià)值營(yíng)銷的理念,以專業(yè)定制企業(yè)官網(wǎng),成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè),重慶小程序開發(fā),網(wǎng)頁(yè)設(shè)計(jì)制作,手機(jī)網(wǎng)站開發(fā),全網(wǎng)整合營(yíng)銷推廣幫助傳統(tǒng)企業(yè)實(shí)現(xiàn)“互聯(lián)網(wǎng)+”轉(zhuǎn)型升級(jí)專業(yè)定制企業(yè)官網(wǎng),公司注重人才、技術(shù)和管理,匯聚了一批優(yōu)秀的互聯(lián)網(wǎng)技術(shù)人才,對(duì)客戶都以感恩的心態(tài)奉獻(xiàn)自己的專業(yè)和所長(zhǎng)。
首先,我們提前熱身一下,學(xué)一點(diǎn)網(wǎng)絡(luò)基礎(chǔ)知識(shí)。
維基百科的定義是這樣的“Network namespaces virtualize the network stack”,意思就是說(shuō)linux network namespace對(duì)network stack做了虛擬化。什么是network stack呢?網(wǎng)絡(luò)棧包括了網(wǎng)卡(network interface),回環(huán)設(shè)備(loopback device),路由表(routing tables)和iptables規(guī)則。打個(gè)比方,當(dāng)你登錄一臺(tái)linux服務(wù)器時(shí),你默認(rèn)用的就是Host網(wǎng)絡(luò)棧。
網(wǎng)橋是在內(nèi)核中虛擬出來(lái)的,可以將主機(jī)上真實(shí)的物理網(wǎng)卡(如eth0,eth1),或虛擬的網(wǎng)卡橋接上來(lái)。橋接上來(lái)的網(wǎng)卡就相當(dāng)于網(wǎng)橋上的端口,端口收到的數(shù)據(jù)包都提交給這個(gè)虛擬的“網(wǎng)橋”,讓其進(jìn)行轉(zhuǎn)發(fā)。
Veth Pair設(shè)備被創(chuàng)建出來(lái)后,總是以兩個(gè)虛擬網(wǎng)卡(Veth Peer)的形式成對(duì)出現(xiàn),其中一張“網(wǎng)卡”發(fā)出的數(shù)據(jù)包可以直接在出現(xiàn)在對(duì)應(yīng)的“網(wǎng)卡”上。Veth Pair常用作連接不同Network Namespace的網(wǎng)線。
VXLAN(Virtual extensible Local Area Network,虛擬擴(kuò)展局域網(wǎng)),是由IETF定義的NVO3(Network Virtualization over Layer 3)標(biāo)準(zhǔn)技術(shù)之一,是對(duì)傳統(tǒng)VLAN協(xié)議的一種擴(kuò)展。VXLAN的特點(diǎn)是將L2的以太幀封裝到UDP報(bào)文(即L2 over L4)中,并在L3網(wǎng)絡(luò)中傳輸。
VXLAN本質(zhì)上是一種隧道技術(shù),在源網(wǎng)絡(luò)設(shè)備與目的網(wǎng)絡(luò)設(shè)備之間的IP網(wǎng)絡(luò)上,建立一條邏輯隧道,將用戶側(cè)報(bào)文經(jīng)過(guò)特定的封裝后通過(guò)這條隧道轉(zhuǎn)發(fā)。從用戶的角度來(lái)看,接入網(wǎng)絡(luò)的服務(wù)器就像是連接到了一個(gè)虛擬的二層交換機(jī)的不同端口上,可以方便地通信。
邊界網(wǎng)關(guān)協(xié)議(Border Gateway Protocol,縮寫:BGP)是互聯(lián)網(wǎng)上一個(gè)核心的去中心化自治路由協(xié)議。它通過(guò)維護(hù)IP路由表或“前綴”表來(lái)實(shí)現(xiàn)自治系統(tǒng)(AS)之間的可達(dá)性,屬于矢量路由協(xié)議。BGP不使用傳統(tǒng)的內(nèi)部網(wǎng)關(guān)協(xié)議(IGP)的指標(biāo),而使用基于路徑、網(wǎng)絡(luò)策略或規(guī)則集來(lái)決定路由。
好了,經(jīng)過(guò)上一章的熱身,大家對(duì)網(wǎng)絡(luò)基礎(chǔ)知識(shí)應(yīng)該有了大致的了解。那么咱們接下來(lái)先嘗試探索一下單機(jī)容器網(wǎng)絡(luò)模型,這也是docker默認(rèn)使用的單機(jī)容器網(wǎng)絡(luò)模型。
圖1 宿主機(jī)上不同容器通過(guò)網(wǎng)橋進(jìn)行互通
單機(jī)容器網(wǎng)絡(luò)的示意圖如圖1,圖中給出了如下幾個(gè)關(guān)鍵點(diǎn):
上述就是單機(jī)容器網(wǎng)絡(luò)的基本原理,在對(duì)單機(jī)容器網(wǎng)絡(luò)模型有了初步的認(rèn)識(shí)后,接下來(lái)我們進(jìn)入正題,開始對(duì)K8S網(wǎng)絡(luò)模型的探索。
接觸過(guò)K8S的同學(xué),大致都聽說(shuō)過(guò)Flannel和Calico兩種網(wǎng)絡(luò)模型。但是,這兩種網(wǎng)絡(luò)模型具體是什么樣子,工作原理是什么,可能很多同學(xué)就比較困惑了。沒(méi)關(guān)系,接下來(lái)我們就開始對(duì)k8S網(wǎng)絡(luò)模型的探索吧!
在上一章中,介紹了單機(jī)容器網(wǎng)絡(luò)的原理。那么,要理解容器如何“跨主機(jī)通信”的原理,一定要從Flannel這個(gè)項(xiàng)目說(shuō)起。Flannel項(xiàng)目是CoreOS公司推出的容器網(wǎng)絡(luò)方案,目前它支持三種后端實(shí)現(xiàn):
UPD模式Flannel最早實(shí)現(xiàn)的一種方式,也是性能最差的,目前已被棄用。但是這種方式也是最直接,最容易理解的方式,所以我們從這種方式開始介紹。
圖2 Flannel-UDP模式跨主機(jī)通信示意圖
圖2是Flannel-UDP模式的原理圖。與單機(jī)容器網(wǎng)絡(luò)相比,這里新增了一個(gè)flannel0設(shè)備和flanneld進(jìn)程。flannel0設(shè)備是一個(gè)TUN設(shè)備,它的作用非常簡(jiǎn)單,就是在系統(tǒng)內(nèi)核和用戶應(yīng)用程序之間傳包;flanneld進(jìn)程的職責(zé),就是封裝和解封裝。數(shù)據(jù)包是如何從Node1中的container-1容器發(fā)送到Node2的container-2容器的呢?
經(jīng)過(guò)上一小節(jié)的介紹,大家對(duì)Flannel-UDP模式大致了解了吧,那聰明的你們已經(jīng)猜到為什么Flannel-UDP被棄用了吧?沒(méi)錯(cuò),因?yàn)樾侍土?,?shù)據(jù)包每次經(jīng)過(guò)flannel0設(shè)備,都會(huì)經(jīng)過(guò)內(nèi)核態(tài)-用戶態(tài)-內(nèi)核態(tài)的這一頓折騰。
圖3 TUN設(shè)備示意圖
那有沒(méi)有辦法不要這么折騰呢?有,F(xiàn)lannel-VXLAN方案就解決了這個(gè)問(wèn)題。Flannel-VXLAN方案用VXLAN技術(shù)替代了flannel0設(shè)備,讓數(shù)據(jù)包能夠在內(nèi)核態(tài)上實(shí)現(xiàn)數(shù)據(jù)包的封裝和解封裝。
圖4 Flannel-VXLan 網(wǎng)絡(luò)模型示意圖
Flannel-VXLan 網(wǎng)絡(luò)模型的原理如圖4所示,你會(huì)發(fā)現(xiàn),這和Flannel-UDP基本上的是一樣。事實(shí)也的確如此,F(xiàn)lannel-VXLAN是Flannel-UDP的升級(jí)版。這里需要交代一下他們之間的不同點(diǎn)。
此時(shí),聰明的你肯定會(huì)說(shuō),F(xiàn)lannel-VXLAN雖然效率提高了,但是還是用到了隧道技術(shù),效率還是會(huì)受到影響,能不能不用隧道技術(shù)呢?答案是能。接下來(lái)我們繼續(xù)探索Flannel-host-gw網(wǎng)絡(luò)模型,一個(gè)基于三層的網(wǎng)絡(luò)方案。老規(guī)矩,上圖。
圖5 Flannel-host-gw網(wǎng)絡(luò)模型示意圖
圖5是Flannel-host-gw網(wǎng)絡(luò)模型,相比較之前的兩個(gè)網(wǎng)絡(luò)模型,隧道設(shè)備確實(shí)沒(méi)有了,取而代之的是一堆路由規(guī)則。那,數(shù)據(jù)包又是怎么從container1到container2的呢?
肉眼可見,F(xiàn)lannel-host-gw的性能確實(shí)提高了很多,那為什么還要用Flannel-VXLAN呢?原因很明顯,F(xiàn)lannel-host-gw只支持宿主機(jī)在二層連通的網(wǎng)絡(luò),并且,K8S的規(guī)模不能太大,否則每臺(tái)機(jī)器的路由表就太多了。
經(jīng)過(guò)上一小節(jié)的介紹,大家對(duì)Flannel應(yīng)該有個(gè)大致的了解了??赡苡腥藭?huì)問(wèn),除了Flannel,K8S還有別的網(wǎng)絡(luò)模型么。當(dāng)然有了,下面我們開始探索Calico網(wǎng)絡(luò)模型。
實(shí)際上Calico網(wǎng)絡(luò)模型的解決方案,幾乎和Flannel-host-gw是一樣的。不同的是Flannel-host-gw使用etcd來(lái)維護(hù)主機(jī)的路由表,而Calico則使用BGP(邊界網(wǎng)關(guān)協(xié)議)來(lái)維護(hù)主機(jī)的路由表。BGP協(xié)議的定義看著有點(diǎn)高深,換成通俗的說(shuō)法,大家可以理解為在每個(gè)邊界網(wǎng)關(guān)都會(huì)都運(yùn)行著一個(gè)小程序,它們會(huì)交換各自的路由信息,將需要的信息更新到自己的路由表里。BGP這個(gè)能力正好可以取代Flannel-host-gw利用Etcd維護(hù)主機(jī)上路由表的功能,并且更為強(qiáng)大。
除了BGP之外,Calico另外一個(gè)不同之處就在于它不需要維護(hù)一個(gè)網(wǎng)橋,Calico網(wǎng)絡(luò)模型如6所示:
圖6 Calico網(wǎng)絡(luò)模型示意圖
圖6是Calico網(wǎng)絡(luò)模型示意圖,其中BGP Client和Felix的作用是和K8S集群其他節(jié)點(diǎn)交換路由信息,并更新Host網(wǎng)絡(luò)棧的路由信息。
由于沒(méi)有了網(wǎng)橋設(shè)備,每個(gè)對(duì)設(shè)備Host網(wǎng)絡(luò)棧的這一端,需要配置一條路由規(guī)則,將目的地址為對(duì)應(yīng)Container的數(shù)據(jù)包轉(zhuǎn)入該對(duì)設(shè)備。對(duì)應(yīng)的路由如下所示:
10.233.1.2 dev cali9c02e56 scope link
數(shù)據(jù)包是如何從Container1走到Container3的呢?過(guò)程基本上和Flannel-host-gw無(wú)異了。唯一區(qū)別就是數(shù)據(jù)包進(jìn)出容器,不再依賴網(wǎng)橋,而是直接通過(guò)宿主機(jī)路由表找到容器的另一端對(duì)設(shè)備。
Calico聽著挺強(qiáng)大的,實(shí)則和Flannel-host-gw一樣,只支持宿主機(jī)二層聯(lián)通的情況。假設(shè)Container1和Container3的宿主機(jī)在不同的子網(wǎng),那通過(guò)二層網(wǎng)絡(luò)是無(wú)法將數(shù)據(jù)包傳到下一跳的地址的。如圖7所示,Calico會(huì)在Node1創(chuàng)建這樣一條路由規(guī)則:
10.233.2.0/16 via 192.168.2.2 eth0
此時(shí)問(wèn)題就出現(xiàn)了,下一跳是192.168.2.2,和Node1不在一個(gè)子網(wǎng)里,根本就找不到。
圖7 Calico(IPIP模式)網(wǎng)絡(luò)模型示意圖
Calico的IPIP模式解決了上述問(wèn)題,在每一臺(tái)宿主機(jī)上,都會(huì)增加一個(gè)tunl0設(shè)備(IP隧道設(shè)備),并且會(huì)對(duì)應(yīng)增加如下一條路由策略:
10.233.2.0/16 via 192.168.2.2 tunl0
這樣一來(lái),Container1去往Container3的數(shù)據(jù)包就會(huì)經(jīng)過(guò)tunl0設(shè)備的處理,tunl0設(shè)備會(huì)在源IP報(bào)頭之外新增一個(gè)外部IP報(bào)頭,拿本例來(lái)說(shuō),這個(gè)外部IP報(bào)頭的src和dst分別為Node1和Node2的IP,這樣,數(shù)據(jù)包就偽裝成了從Node1發(fā)到Node2的數(shù)據(jù)包。當(dāng)數(shù)據(jù)包到達(dá)Node2之后,Node2上的tunl0會(huì)把外部IP報(bào)頭拿掉,從而拿到原始的IP包。
我知道,聰明的你此時(shí)肯定會(huì)有一個(gè)更好的想法,為什么不在Router1和Router2上也用BGP協(xié)議的方式,同步容器的IP路由信息呢?這樣宿主機(jī)上不就可以不用tunl0設(shè)備了么。這個(gè)方法確實(shí)很好,并且在一些場(chǎng)景也得到了應(yīng)用。
最后,我再介紹一下CNI網(wǎng)絡(luò)插件。CNI(Container Network Interface)顧名思義,是K8S的網(wǎng)絡(luò)接口。這個(gè)接口的作用就是當(dāng)K8S的 kubelet創(chuàng)建Pod時(shí),dockershim會(huì)預(yù)先調(diào)用Docker API創(chuàng)建并啟動(dòng)Infra容器,執(zhí)行SetUpPod的方法。這個(gè)方法會(huì)為CNI網(wǎng)絡(luò)插件準(zhǔn)備參數(shù)和環(huán)境變量,然后調(diào)用CNI插件為Infra容器配置網(wǎng)絡(luò)。CNI網(wǎng)絡(luò)插件僅需實(shí)現(xiàn)ADD和DEL兩種方法,分別對(duì)應(yīng)Pod加入K8S網(wǎng)絡(luò),以及Pod移出K8S網(wǎng)絡(luò)。
用大白話再解釋一遍,就是當(dāng)Pod創(chuàng)建時(shí),需要對(duì)網(wǎng)絡(luò)進(jìn)行一些設(shè)置,包括前邊的提到的創(chuàng)建對(duì)設(shè)備,把對(duì)設(shè)備的一端掛載到網(wǎng)橋上,添加Pod以及主機(jī)的Network Namespace的路由規(guī)則等,這些操作當(dāng)然可以由運(yùn)維人員手動(dòng)完成(不嫌累的話),CNI網(wǎng)絡(luò)插件就是一個(gè)腳本,自動(dòng)對(duì)網(wǎng)絡(luò)進(jìn)行設(shè)置。
Flannel和Calico各自都有專門的CNI插件,大家可以去Github上研究一下源碼,并親自部署一下試試。這里就不多介紹了,畢竟看再多的資料,都不如自己動(dòng)手實(shí)踐一遍理解得深刻。?

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流