共計(jì) 5287 個(gè)字符,預(yù)計(jì)需要花費(fèi) 14 分鐘才能閱讀完成。
這篇文章將為大家詳細(xì)講解有關(guān)如何理解 K8s 中的 CNI 和 CNI 插件,文章內(nèi)容質(zhì)量較高,因此丸趣 TV 小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
網(wǎng)絡(luò)架構(gòu)是 K8s 中較為復(fù)雜的方面之一。K8s 網(wǎng)絡(luò)模型本身對(duì)某些特定的網(wǎng)絡(luò)功能有著一定的要求,因此,業(yè)界已經(jīng)有了不少的網(wǎng)絡(luò)方案來(lái)滿足特定的環(huán)境和要求。CNI 意為容器網(wǎng)絡(luò)的 API 接口,為了讓用戶(hù)在容器創(chuàng)建或銷(xiāo)毀時(shí)都能夠更容易地配置容器網(wǎng)絡(luò)。在本文中,作者將帶領(lǐng)大家理解典型網(wǎng)絡(luò)插件地工作原理、掌握 CNI 插件的使用。
一、CNI 是什么
首先我們介紹一下什么是 CNI,它的全稱(chēng)是 Container Network Interface,即容器網(wǎng)絡(luò)的 API 接口。
它是 K8s 中標(biāo)準(zhǔn)的一個(gè)調(diào)用網(wǎng)絡(luò)實(shí)現(xiàn)的接口。Kubelet 通過(guò)這個(gè)標(biāo)準(zhǔn)的 API 來(lái)調(diào)用不同的網(wǎng)絡(luò)插件以實(shí)現(xiàn)不同的網(wǎng)絡(luò)配置方式,實(shí)現(xiàn)了這個(gè)接口的就是 CNI 插件,它實(shí)現(xiàn)了一系列的 CNI API 接口。常見(jiàn)的 CNI 插件包括 Calico、flannel、Terway、Weave Net 以及 Contiv。
二、Kubernetes 中如何使用 CNI
K8s 通過(guò) CNI 配置文件來(lái)決定使用什么 CNI。
基本的使用方法為:
首先在每個(gè)結(jié)點(diǎn)上配置 CNI 配置文件 (/etc/cni/net.d/xxnet.conf),其中 xxnet.conf 是某一個(gè)網(wǎng)絡(luò)配置文件的名稱(chēng);
安裝 CNI 配置文件中所對(duì)應(yīng)的二進(jìn)制插件;
在這個(gè)節(jié)點(diǎn)上創(chuàng)建 Pod 之后,Kubelet 就會(huì)根據(jù) CNI 配置文件執(zhí)行前兩步所安裝的 CNI 插件;
上步執(zhí)行完之后,Pod 的網(wǎng)絡(luò)就配置完成了。
具體的流程如下圖所示:
在集群里面創(chuàng)建一個(gè) Pod 的時(shí)候,首先會(huì)通過(guò) apiserver 將 Pod 的配置寫(xiě)入。apiserver 的一些管控組件(比如 Scheduler)會(huì)調(diào)度到某個(gè)具體的節(jié)點(diǎn)上去。Kubelet 監(jiān)聽(tīng)到這個(gè) Pod 的創(chuàng)建之后,會(huì)在本地進(jìn)行一些創(chuàng)建的操作。當(dāng)執(zhí)行到創(chuàng)建網(wǎng)絡(luò)這一步驟時(shí),它首先會(huì)讀取剛才我們所說(shuō)的配置目錄中的配置文件,配置文件里面會(huì)聲明所使用的是哪一個(gè)插件,然后去執(zhí)行具體的 CNI 插件的二進(jìn)制文件,再由 CNI 插件進(jìn)入 Pod 的網(wǎng)絡(luò)空間去配置 Pod 的網(wǎng)絡(luò)。配置完成之后,Kuberlet 也就完成了整個(gè) Pod 的創(chuàng)建過(guò)程,這個(gè) Pod 就在線了。
大家可能會(huì)覺(jué)得上述流程有很多步(比如要對(duì) CNI 配置文件進(jìn)行配置、安裝二進(jìn)制插件等等),看起來(lái)比較復(fù)雜。
但如果我們只是作為一個(gè)用戶(hù)去使用 CNI 插件的話就比較簡(jiǎn)單,因?yàn)楹芏?CNI 插件都已提供了一鍵安裝的能力。以我們常用的 Flannel 為例,如下圖所示:只需要我們使用 kubectl apply Flannel 的一個(gè) Deploying 模板,它就能自動(dòng)地將配置、二進(jìn)制文件安裝到每一個(gè)節(jié)點(diǎn)上去。
安裝完之后,整個(gè)集群的 CNI 插件就安裝完成了。
因此,如果我們只是去使用 CNI 插件的話,那么其實(shí)很多 CNI 插件已經(jīng)提供了一鍵安裝的腳本,無(wú)需大家關(guān)心 Kubernetes 內(nèi)部是如何配置的以及如何調(diào)用 API 的。
三、哪個(gè) CNI 插件適合我
社區(qū)有很多的 CNI 插件,比如 Calico, flannel, Terway 等等。那么在一個(gè)真正具體的生產(chǎn)環(huán)境中,我們要選擇哪一個(gè) CNI 插件呢?
這就要從 CNI 的幾種實(shí)現(xiàn)模式說(shuō)起。我們需要根據(jù)不同的場(chǎng)景選擇不同的實(shí)現(xiàn)模式,再去選擇對(duì)應(yīng)的具體某一個(gè)插件。
通常來(lái)說(shuō),CNI 插件可以分為三種:Overlay、路由及 Underlay。
Overlay 模式的典型特征是容器獨(dú)立于主機(jī)的 IP 段,這個(gè) IP 段進(jìn)行跨主機(jī)網(wǎng)絡(luò)通信時(shí)是通過(guò)在主機(jī)之間創(chuàng)建隧道的方式,將整個(gè)容器網(wǎng)段的包全都封裝成底層的物理網(wǎng)絡(luò)中主機(jī)之間的包。該方式的好處在于它不依賴(lài)于底層網(wǎng)絡(luò);
路由模式中主機(jī)和容器也分屬不同的網(wǎng)段,它與 Overlay 模式的主要區(qū)別在于它的跨主機(jī)通信是通過(guò)路由打通,無(wú)需在不同主機(jī)之間做一個(gè)隧道封包。但路由打通就需要部分依賴(lài)于底層網(wǎng)絡(luò),比如說(shuō)要求底層網(wǎng)絡(luò)有二層可達(dá)的一個(gè)能力;
Underlay 模式中容器和宿主機(jī)位于同一層網(wǎng)絡(luò),兩者擁有相同的地位。容器之間網(wǎng)絡(luò)的打通主要依靠于底層網(wǎng)絡(luò)。因此該模式是強(qiáng)依賴(lài)于底層能力的。
了解了以上三種常用的實(shí)現(xiàn)模式之后,再根據(jù)自己的環(huán)境、需求判斷可由哪一種模式進(jìn)行實(shí)現(xiàn),再在對(duì)應(yīng)的模式中去找 CNI 插件。不過(guò)社區(qū)中有那么多插件,它們又都屬于哪種模式?如何進(jìn)行選擇呢?怎么挑選適合自己的呢?我們可以從以下 3 個(gè)方面來(lái)考慮。
1. 環(huán)境限制
不同環(huán)境中所支持的底層能力是不同的。
虛擬化環(huán)境(例如 OpenStack)中的網(wǎng)絡(luò)限制較多,比如不允許機(jī)器之間直接通過(guò)二層協(xié)議訪問(wèn),必須要帶有 IP 地址這種三層的才能去做轉(zhuǎn)發(fā),限制某一個(gè)機(jī)器只能使用某些 IP 等。在這種被做了強(qiáng)限制的底層網(wǎng)絡(luò)中,只能去選擇 Overlay 的插件,常見(jiàn)的有 Flannel-vxlan, Calico-ipip, Weave 等等;
物理機(jī)環(huán)境中底層網(wǎng)絡(luò)的限制較少,比如說(shuō)我們?cè)谕粋€(gè)交換機(jī)下面直接做一個(gè)二層的通信。對(duì)于這種集群環(huán)境,我們可以選擇 Underlay 或者路由模式的插件。Underlay 意味著我們可以直接在一個(gè)物理機(jī)上插多個(gè)網(wǎng)卡或者是在一些網(wǎng)卡上做硬件虛擬化;路由模式就是依賴(lài)于 Linux 的路由協(xié)議做一個(gè)打通。這樣就避免了像 vxlan 的封包方式導(dǎo)致的性能降低。這種環(huán)境下我們可選的插件包括 clico-bgp, flannel-hostgw, sriov 等等;
公有云環(huán)境也是虛擬化,因此底層限制也會(huì)較多。但每個(gè)公有云都會(huì)考慮適配容器,提升容器的性能,因此每家公有云可能都提供了一些 API 去配置一些額外的網(wǎng)卡或者路由這種能力。在公有云上,我們要盡量選擇公有云廠商提供的 CNI 插件以達(dá)到兼容性和性能上的最優(yōu)。比如 Aliyun 就提供了一個(gè)高性能的 Terway 插件。
環(huán)境限制考慮完之后,我們心中應(yīng)該都有一些選擇了,知道哪些能用、哪些不能用。在這個(gè)基礎(chǔ)上,我們?cè)偃タ紤]功能上的需求。
2. 功能需求
首先是安全需求;
K8s 支持 NetworkPolicy,就是說(shuō)我們可以通過(guò) NetworkPolicy 的一些規(guī)則去支持“Pod 之間是否可以訪問(wèn)”這類(lèi)策略。但不是每個(gè) CNI 插件都支持 NetworkPolicy 的聲明,如果大家有這個(gè)需求,可以選擇支持 NetworkPolicy 的一些插件,比如 Calico, Weave 等等。
第二個(gè)是是否需要集群外的資源與集群內(nèi)的資源互聯(lián)互通;
大家的應(yīng)用最初都是在虛擬機(jī)或者物理機(jī)上,容器化之后,應(yīng)用無(wú)法一下就完成遷移,因此就需要傳統(tǒng)的虛擬機(jī)或者物理機(jī)能跟容器的 IP 地址互通。為了實(shí)現(xiàn)這種互通,就需要兩者之間有一些打通的方式或者直接位于同一層。此時(shí)可以選擇 Underlay 的網(wǎng)絡(luò),比如 sriov 這種就是 Pod 和以前的虛擬機(jī)或者物理機(jī)在同一層。我們也可以使用 calico-bgp,此時(shí)它們雖然不在同一網(wǎng)段,但可以通過(guò)它去跟原有的路由器做一些 BGP 路由的一個(gè)發(fā)布,這樣也可以打通虛擬機(jī)與容器。
最后考慮的就是
K8s 的服務(wù)發(fā)現(xiàn)與負(fù)載均衡的能力。
K8s 的服務(wù)發(fā)現(xiàn)與負(fù)載均衡就是我們前面所介紹的
K8s 的 Service,但并不是所有的 CNI 插件都能實(shí)現(xiàn)這兩種能力。比如很多 Underlay 模式的插件,在 Pod 中的網(wǎng)卡是直接用的 Underlay 的硬件,或者通過(guò)硬件虛擬化插到容器中的,這個(gè)時(shí)候它的流量無(wú)法走到宿主機(jī)所在的命名空間,因此也無(wú)法應(yīng)用 kube-proxy 在宿主機(jī)配置的規(guī)則。
這種情況下,插件就無(wú)法訪問(wèn)到 K8s 的服務(wù)發(fā)現(xiàn)。因此大家如果需要服務(wù)發(fā)現(xiàn)與負(fù)載均衡,在選擇 Underlay 的插件時(shí)就需要注意它們是否支持這兩種能力。
經(jīng)過(guò)功能需求的過(guò)濾之后,能選的插件就很少了。經(jīng)過(guò)環(huán)境限制和功能需求的過(guò)濾之后,如果還剩下 3、4 種插件,可以再來(lái)考慮性能需求。
3. 性能需求
我們可以從 Pod 的創(chuàng)建速度和 Pod 的網(wǎng)絡(luò)性能來(lái)衡量不同插件的性能。
Pod 的創(chuàng)建速度
當(dāng)我們創(chuàng)建一組 Pod 時(shí),比如業(yè)務(wù)高峰來(lái)了,需要緊急擴(kuò)容,這時(shí)比如說(shuō)我們擴(kuò)容了 1000 個(gè) Pod,就需要 CNI 插件創(chuàng)建并配置 1000 個(gè)網(wǎng)絡(luò)資源。Overlay 和路由模式在這種情況下的創(chuàng)建速度是很快的,因?yàn)樗窃跈C(jī)器里面又做了虛擬化,所以只需要調(diào)用內(nèi)核接口就可以完成這些操作。但對(duì)于 Underlay 模式,由于需要?jiǎng)?chuàng)建一些底層的網(wǎng)絡(luò)資源,所以整個(gè) Pod 的創(chuàng)建速度相對(duì)會(huì)慢一些。因此對(duì)于經(jīng)常需要緊急擴(kuò)容或者創(chuàng)建大批量的 Pod 這些場(chǎng)景,我們應(yīng)該盡量選擇 Overlay 或者路由模式的網(wǎng)絡(luò)插件。
Pod 的網(wǎng)絡(luò)性能
主要表現(xiàn)在兩個(gè) Pod 之間的網(wǎng)絡(luò)轉(zhuǎn)發(fā)、網(wǎng)絡(luò)帶寬、PPS 延遲等這些性能指標(biāo)上。Overlay 模式的性能較差,因?yàn)樗诠?jié)點(diǎn)上又做了一層虛擬化,還需要去封包,封包又會(huì)帶來(lái)一些包頭的損失、CPU 的消耗等,如果大家對(duì)網(wǎng)絡(luò)性能的要求比較高,比如說(shuō)機(jī)器學(xué)習(xí)、大數(shù)據(jù)這些場(chǎng)景就不適合使用 Overlay 模式。這種情形下我們通常選擇 Underlay 或者路由模式的 CNI 插件。
相信大家通過(guò)這三步的挑選之后都能找到適合自己的網(wǎng)絡(luò)插件。
四、如何開(kāi)發(fā)自己的 CNI 插件
有時(shí)社區(qū)的插件無(wú)法滿足自己的需求,比如在阿里云上只能使用 vxlan 這種 Overlay 的插件,而 Overlay 插件的性能相對(duì)較差,無(wú)法滿足阿里云上的一些業(yè)務(wù)需求,所以阿里云上開(kāi)發(fā)了一個(gè) Terway 的插件。
如果我們自己的環(huán)境比較特殊,在社區(qū)里面又找不到合適的網(wǎng)絡(luò)插件,此時(shí)可以開(kāi)發(fā)一個(gè)自己的 CNI 插件。
CNI 插件的實(shí)現(xiàn)通常包含兩個(gè)部分:
一個(gè)二進(jìn)制的 CNI 插件去配置 Pod 網(wǎng)卡和 IP 地址。這一步配置完成之后相當(dāng)于給 Pod 上插上了一條網(wǎng)線,就是說(shuō)它已經(jīng)有自己的 IP、有自己的網(wǎng)卡了;
一個(gè) Daemon 進(jìn)程去管理 Pod 之間的網(wǎng)絡(luò)打通。這一步相當(dāng)于說(shuō)將 Pod 真正連上網(wǎng)絡(luò),讓 Pod 之間能夠互相通信。
給 Pod 插上網(wǎng)線
那么如何實(shí)現(xiàn)第一步,給 Pod 插上網(wǎng)線呢?通常是這樣一個(gè)步驟:
1. 給 Pod 準(zhǔn)備一個(gè)網(wǎng)卡
通常我們會(huì)用一個(gè)“veth”這種虛擬網(wǎng)卡,一端放到 Pod 的網(wǎng)絡(luò)空間,一端放到主機(jī)的網(wǎng)絡(luò)空間,這樣就實(shí)現(xiàn)了 Pod 與主機(jī)這兩個(gè)命名空間的打通。
2. 給 Pod 分配 IP 地址
這個(gè) IP 地址有一個(gè)要求,我們?cè)谥敖榻B網(wǎng)絡(luò)的時(shí)候也有提到,就是說(shuō)這個(gè) IP 地址在集群里需要是唯一的。如何保障集群里面給 Pod 分配的是個(gè)唯一的 IP 地址呢?
一般來(lái)說(shuō)我們?cè)趧?chuàng)建整個(gè)集群的時(shí)候會(huì)指定 Pod 的一個(gè)大網(wǎng)段,按照每個(gè)節(jié)點(diǎn)去分配一個(gè) Node 網(wǎng)段。比如說(shuō)上圖右側(cè)創(chuàng)建的是一個(gè) 172.16 的網(wǎng)段,我們?cè)侔凑彰總€(gè)節(jié)點(diǎn)去分配一個(gè) /24 的段,這樣就能保障每個(gè)節(jié)點(diǎn)上的地址是互不沖突的。然后每個(gè) Pod 再?gòu)囊粋€(gè)具體的節(jié)點(diǎn)上的網(wǎng)段中再去順序分配具體的 IP 地址,比如 Pod1 分配到了 172.16.0.1,Pod2 分配到了 172.16.0.2,這樣就實(shí)現(xiàn)了在節(jié)點(diǎn)里面 IP 地址分配的不沖突,并且不同的 Node 又分屬不同的網(wǎng)段,因此不會(huì)沖突。
這樣就給 Pod 分配了集群里面一個(gè)唯一的 IP 地址。
3. 配置 Pod 的 IP 和路由
第一步,將分配到的 IP 地址配置給 Pod 的虛擬網(wǎng)卡;
第二步,在 Pod 的網(wǎng)卡上配置集群網(wǎng)段的路由,令訪問(wèn)的流量都走到對(duì)應(yīng)的 Pod 網(wǎng)卡上去,并且也會(huì)配置默認(rèn)路由的網(wǎng)段到這個(gè)網(wǎng)卡上,也就是說(shuō)走公網(wǎng)的流量也會(huì)走到這個(gè)網(wǎng)卡上進(jìn)行路由;
最后在宿主機(jī)上配置到 Pod 的 IP 地址的路由,指向到宿主機(jī)對(duì)端 veth2 這個(gè)虛擬網(wǎng)卡上。這樣實(shí)現(xiàn)的是從 Pod 能夠到宿主機(jī)上進(jìn)行路由出去的,同時(shí)也實(shí)現(xiàn)了在宿主機(jī)上訪問(wèn)到 Pod 的 IP 地址也能路由到對(duì)應(yīng)的 Pod 的網(wǎng)卡所對(duì)應(yīng)的對(duì)端上去。
給 Pod 連上網(wǎng)絡(luò)
剛才我們是給 Pod 插上網(wǎng)線,也就是給它配了 IP 地址以及路由表。那怎么打通 Pod 之間的通信呢?也就是讓每一個(gè) Pod 的 IP 地址在集群里面都能被訪問(wèn)到。
一般我們是在 CNI Daemon 進(jìn)程中去做這些網(wǎng)絡(luò)打通的事情。通常來(lái)說(shuō)是這樣一個(gè)步驟:
首先 CNI 在每個(gè)節(jié)點(diǎn)上運(yùn)行的 Daemon 進(jìn)程會(huì)學(xué)習(xí)到集群所有 Pod 的 IP 地址及其所在節(jié)點(diǎn)信息。學(xué)習(xí)的方式通常是通過(guò)監(jiān)聽(tīng) K8s APIServer,拿到現(xiàn)有 Pod 的 IP 地址以及節(jié)點(diǎn),并且新的節(jié)點(diǎn)和新的 Pod 的創(chuàng)建的時(shí)候也能通知到每個(gè) Daemon;
拿到 Pod 以及 Node 的相關(guān)信息之后,再去配置網(wǎng)絡(luò)進(jìn)行打通。
首先 Daemon 會(huì)創(chuàng)建到整個(gè)集群所有節(jié)點(diǎn)的通道。這里的通道是個(gè)抽象概念,具體實(shí)現(xiàn)一般是通過(guò) Overlay 隧道、阿里云上的 VPC 路由表、或者是自己機(jī)房里的 BGP 路由完成的;
第二步是將所有 Pod 的 IP 地址跟上一步創(chuàng)建的通道關(guān)聯(lián)起來(lái)。關(guān)聯(lián)也是個(gè)抽象概念,具體的實(shí)現(xiàn)通常是通過(guò) Linux 路由、fdb 轉(zhuǎn)發(fā)表或者 OVS 流表等完成的。Linux 路由可以設(shè)定某一個(gè) IP 地址路由到哪個(gè)節(jié)點(diǎn)上去。fdb 轉(zhuǎn)發(fā)表是 forwarding database 的縮寫(xiě),就是把某個(gè) Pod 的 IP 轉(zhuǎn)發(fā)到某一個(gè)節(jié)點(diǎn)的隧道端點(diǎn)上去(Overlay 網(wǎng)絡(luò))。OVS 流表是由 Open vSwitch 實(shí)現(xiàn)的,它可以把 Pod 的 IP 轉(zhuǎn)發(fā)到對(duì)應(yīng)的節(jié)點(diǎn)上。
關(guān)于如何理解 K8s 中的 CNI 和 CNI 插件就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。