k8s對(duì)Pods之間如何進(jìn)行組網(wǎng)通信提出了要求,k8s對(duì)集群的網(wǎng)絡(luò)有以下要求:
k8s網(wǎng)絡(luò)模型設(shè)計(jì)基礎(chǔ)原則:每個(gè)Pod都擁有一個(gè)獨(dú)立的 IP地址,而且 假定所有 Pod 都在一個(gè)可以直接連通的、扁平的網(wǎng)絡(luò)空間中 。 所以不管它們是否運(yùn)行在同 一 個(gè) Node (宿主機(jī))中,都要求它們可以直接通過(guò)對(duì)方的 IP 進(jìn)行訪問(wèn)。設(shè)計(jì)這個(gè)原則的原因 是,用戶不需要額外考慮如何建立 Pod 之間的連接,也不需要考慮將容器端口映射到主機(jī)端口等問(wèn)題。 由于 Kubemetes 的網(wǎng)絡(luò)模型假設(shè) Pod 之間訪問(wèn)時(shí)使用的是對(duì)方 Pod 的實(shí)際地址,所以一個(gè) 鑒于上面這些要求,我們需要解決四個(gè)不同的網(wǎng)絡(luò)問(wèn)題::
下面我們一一進(jìn)行討論每種網(wǎng)絡(luò)問(wèn)題,以及如何解決。 二、容器和容器之間的網(wǎng)絡(luò)image.png
container模式指定新創(chuàng)建的Docker容器和已經(jīng)存在的一個(gè)容器共享一個(gè)網(wǎng)絡(luò)命名空間,而不是和宿主機(jī)共享。新創(chuàng)建的Docker容器不會(huì)創(chuàng)建自己的網(wǎng)卡,配置自己的 IP,而是和一個(gè)指定的容器共享 IP、端口范圍等 每個(gè)Pod容器有有一個(gè)pause容器其有獨(dú)立的網(wǎng)絡(luò)命名空間,在Pod內(nèi)啟動(dòng)Docker容器時(shí)候使用 –net=container就可以讓當(dāng)前Docker容器加入到Pod容器擁有的網(wǎng)絡(luò)命名空間(pause容器) image.png 三、Pod與Pod之間的網(wǎng)絡(luò)image.png
那么是如何做到的?這多虧了使用linux虛擬以太網(wǎng)設(shè)備或者說(shuō)是由兩個(gè)虛擬接口組成的veth對(duì)使不同的網(wǎng)絡(luò)命名空間鏈接起來(lái),這些虛擬接口分布在多個(gè)網(wǎng)絡(luò)命名空間上(這里是指多個(gè)Pod上)。 為了讓多個(gè)Pod的網(wǎng)絡(luò)命名空間鏈接起來(lái),我們可以讓veth對(duì)的一端鏈接到root網(wǎng)絡(luò)命名空間(宿主機(jī)的),另一端鏈接到Pod的網(wǎng)絡(luò)命名空間。 每對(duì)Veth就像一根接插電纜,連接兩側(cè)并允許流量在它們之間流動(dòng);這種veth對(duì)可以推廣到同一個(gè)Node上任意多的Pod上,如上圖這里展示使用veth對(duì)鏈接每個(gè)Pod到虛擬機(jī)的root網(wǎng)絡(luò)命名空間。 下面我們看如何使用網(wǎng)橋設(shè)備來(lái)讓通過(guò)veth對(duì)鏈接到root命名空間的多個(gè)Pod進(jìn)行通信。 linux以太網(wǎng)橋(Linux Ethernet bridge)是一個(gè)虛擬的2層網(wǎng)絡(luò)設(shè)備,目的是把多個(gè)以太網(wǎng)段鏈接起來(lái),網(wǎng)橋維護(hù)了一個(gè)轉(zhuǎn)發(fā)表,通過(guò)檢查轉(zhuǎn)發(fā)表通過(guò)它傳輸?shù)臄?shù)據(jù)包的目的地并決定是否將數(shù)據(jù)包傳遞到連接到網(wǎng)橋的其他網(wǎng)段,網(wǎng)橋代碼通過(guò)查看網(wǎng)絡(luò)中每個(gè)以太網(wǎng)設(shè)備特有的MAC地址來(lái)決定是傳輸數(shù)據(jù)還是丟棄數(shù)據(jù)。 image.png 網(wǎng)橋?qū)崿F(xiàn)了ARP協(xié)議用來(lái)根據(jù)給定的ip地址找到對(duì)應(yīng)機(jī)器的數(shù)據(jù)鏈路層的mac地址,一開(kāi)始轉(zhuǎn)發(fā)表為空,當(dāng)一個(gè)數(shù)據(jù)幀被網(wǎng)橋接受后,網(wǎng)橋會(huì)廣播該幀到所有的鏈接設(shè)備(除了發(fā)送方設(shè)備),并且把響應(yīng)這個(gè)廣播的設(shè)備記錄到轉(zhuǎn)發(fā)表;隨后發(fā)往相同ip地址的流量會(huì)直接從轉(zhuǎn)發(fā)表查找正確的mac地址,然后轉(zhuǎn)發(fā)包到對(duì)應(yīng)的設(shè)備。 image.png 如上圖顯示了兩個(gè)Pod通過(guò)veth對(duì)鏈接到root網(wǎng)絡(luò)命名空間,并且通過(guò)網(wǎng)橋進(jìn)行通信 3.1 同一個(gè)Node中的Pod之間的一次通信鑒于每個(gè)Pod有自己獨(dú)立的網(wǎng)絡(luò)命名空間,我們使用虛擬以太網(wǎng)設(shè)備把多個(gè)Pod的命名空間鏈接到了root命名空間,并且使用網(wǎng)橋讓多個(gè)Pod之間進(jìn)行通信,下面我們看如何在兩個(gè)pod之間進(jìn)行通信: image.png
3.2 不同Node中的Pod之間通信k8s網(wǎng)絡(luò)模型需要每個(gè)pod必須通過(guò)ip地址可以進(jìn)行訪問(wèn),每個(gè)pod的ip地址總是對(duì)網(wǎng)絡(luò)中的其他pod可見(jiàn),并且每個(gè)pod看待自己的ip與別的pod看待的是一樣的(雖然他沒(méi)規(guī)定如何實(shí)現(xiàn)),下面我們看不同Node間Pod如何交互 k8s中每個(gè)集群中的每個(gè)Node都會(huì)被分配了一個(gè)CIDR塊(無(wú)類(lèi)別域間路由選擇,把網(wǎng)絡(luò)前綴都相同的連續(xù)地址組成的地址組稱(chēng)為CIDR地址塊)用來(lái)給該Node上的Pod分配IP地址。(保證pod的ip不會(huì)沖突) image
每個(gè)Node都知道如何把數(shù)據(jù)包轉(zhuǎn)發(fā)到其內(nèi)部運(yùn)行的Pod,當(dāng)一個(gè)數(shù)據(jù)包到達(dá)Node后,其內(nèi)部數(shù)據(jù)流就和Node內(nèi)Pod之間的流轉(zhuǎn)類(lèi)似了。 對(duì)于如何來(lái)配置網(wǎng)絡(luò),k8s在網(wǎng)絡(luò)這塊自身并沒(méi)有實(shí)現(xiàn)網(wǎng)絡(luò)規(guī)劃的具體邏輯,而是制定了一套CNI(Container Network Interface)接口規(guī)范,開(kāi)放給社區(qū)來(lái)實(shí)現(xiàn)。 例如AWS,亞馬遜為k8s維護(hù)了一個(gè)容器網(wǎng)絡(luò)插件,使用CNI插件來(lái)讓亞馬遜VPC(虛擬私有云)環(huán)境中的Node與Node直接進(jìn)行交互. CoreOS的Flannel是k8s中實(shí)現(xiàn)CNI規(guī)范較為出名的一種實(shí)現(xiàn)。 3.2.1 VXLAN
image.png
從這個(gè)報(bào)文中可以看到三個(gè)部分: image.png
3.2.1 FlannelFlannel是CoreOS團(tuán)隊(duì)針對(duì)Kubernetes設(shè)計(jì)的一個(gè)網(wǎng)絡(luò)規(guī)劃實(shí)現(xiàn),簡(jiǎn)單來(lái)說(shuō),它的功能有以下幾點(diǎn):
image.png
如上圖,總的來(lái)說(shuō)就是建立VXLAN 隧道,通過(guò)UDP把IP封裝一層直接送到對(duì)應(yīng)的節(jié)點(diǎn),實(shí)現(xiàn)了一個(gè)大的 VLAN。 4.Pod與Service之間的網(wǎng)絡(luò)上面展示了Pod之間如何通過(guò)他們自己的ip地址進(jìn)行通信,但是pod的ip地址是不持久的,當(dāng)集群中pod的規(guī)模縮減或者pod故障或者node故障重啟后,新的pod的ip就可能與之前的不一樣的。所以k8s中衍生出來(lái)Service來(lái)解決這個(gè)問(wèn)題。 k8s中 Service管理了一系列的Pods,每個(gè)Service有一個(gè)虛擬的ip,要訪問(wèn)service管理的Pod上的服務(wù)只需要訪問(wèn)你這個(gè)虛擬ip就可以了,這個(gè)虛擬ip是固定的,當(dāng)service下的pod規(guī)模改變、故障重啟、node重啟時(shí)候,對(duì)使用service的用戶來(lái)說(shuō)是無(wú)感知的,因?yàn)樗麄兪褂玫膕ervice的ip沒(méi)有變。 當(dāng)數(shù)據(jù)包到達(dá)Service虛擬ip后,數(shù)據(jù)包會(huì)被通過(guò)k8s給該servcie自動(dòng)創(chuàng)建的負(fù)載均衡器路由到背后的pod容器。下面我們看看具體是如何做到的 4.1 netfilter為了實(shí)現(xiàn)負(fù)載均衡,k8s依賴linux內(nèi)建的網(wǎng)絡(luò)框架-netfilter。Netfilter是Linux提供的內(nèi)核態(tài)框架,允許使用者自定義處理接口實(shí)現(xiàn)各種與網(wǎng)絡(luò)相關(guān)的操作。 Netfilter為包過(guò)濾,網(wǎng)絡(luò)地址轉(zhuǎn)換和端口轉(zhuǎn)換提供各種功能和操作,以及提供禁止數(shù)據(jù)包到達(dá)計(jì)算機(jī)網(wǎng)絡(luò)內(nèi)敏感位置的功能。在linux內(nèi)核協(xié)議棧中,有5個(gè)跟netfilter有關(guān)的鉤子函數(shù),數(shù)據(jù)包經(jīng)過(guò)每個(gè)鉤子時(shí),都會(huì)檢查上面是否注冊(cè)有函數(shù),如果有的話,就會(huì)調(diào)用相應(yīng)的函數(shù)處理該數(shù)據(jù)包 | | Incoming ↓+-------------------+| NF_IP_PRE_ROUTING |+-------------------+ | | ↓+------------------+| | +----------------+| routing decision |-------->| NF_IP_LOCAL_IN || | +----------------++------------------+ | | | | ↓ | +-----------------+ | | local processes | | +-----------------+ | | | | ↓ ↓ +---------------+ +-----------------+ | NF_IP_FORWARD | | NF_IP_LOCAL_OUT | +---------------+ +-----------------+ | | | | ↓ |+------------------+ || | || routing decision |<----------------+| |+------------------+ | | ↓+--------------------+| NF_IP_POST_ROUTING |+--------------------+ | | Outgoing ↓
netfilter是工作在那一層? 4.2 iptablesiptables是運(yùn)行在用戶態(tài)的用戶程序,其基于表來(lái)管理規(guī)則,用于定義使用netfilter框架操作和轉(zhuǎn)換數(shù)據(jù)包的規(guī)則。根據(jù)rule的作用分成了好幾個(gè)表,比如用來(lái)過(guò)濾數(shù)據(jù)包的rule就會(huì)放到filter表中,用于處理地址轉(zhuǎn)換的rule就會(huì)放到nat表中,其中rule就是應(yīng)用在netfilter鉤子上的函數(shù),用來(lái)修改數(shù)據(jù)包的內(nèi)容或過(guò)濾數(shù)據(jù)包。目前iptables支持的表有下面這些:
在k8s中,iptables規(guī)則由kube-proxy控制器配置,該控制器監(jiān)視K8s API服務(wù)器的更改。當(dāng)對(duì)Service或Pod的虛擬IP地址進(jìn)行修改時(shí),iptables規(guī)則也會(huì)更新以便讓service能夠正確的把數(shù)據(jù)包路由到后端Pod。 iptables規(guī)則監(jiān)視發(fā)往Service虛擬IP的流量,并且在匹配時(shí),從可用Pod集合中選擇隨機(jī)Pod IP地址,iptables規(guī)則將數(shù)據(jù)包的目標(biāo)IP地址從Service的虛擬IP更改為選定的Pod的ip??偟膩?lái)說(shuō)iptables已在機(jī)器上完成負(fù)載平衡,并將指向Servcie的虛擬IP的流量轉(zhuǎn)移到實(shí)際的pod的IP。 在從service到pod的路徑上,IP地址來(lái)自目標(biāo)Pod。 在這種情況下,iptables再次重寫(xiě)IP頭以將Pod IP替換為Service的IP,以便Pod認(rèn)為它一直與Service的虛擬IP通信。 4.3 IPVSk8s的最新版本(1.11)包括了用于集群內(nèi)負(fù)載平衡的第二個(gè)選項(xiàng):IPVS。 IPVS(IP Virtual Server)也構(gòu)建在netfilter之上,并實(shí)現(xiàn)傳輸層負(fù)載平衡(屬于Linux內(nèi)核的一部分)。 IPVS包含在LVS(Linux虛擬服務(wù)器)中,它在主機(jī)上運(yùn)行,并在真實(shí)服務(wù)器集群前充當(dāng)負(fù)載均衡器。 IPVS可以將對(duì)基于TCP和UDP的服務(wù)的請(qǐng)求定向到真實(shí)服務(wù)器,并使真實(shí)服務(wù)器的服務(wù)在單個(gè)IP地址上顯示為虛擬服務(wù)。這使得IPVS非常適合Kubernetes服務(wù)。 聲明Kubernetes服務(wù)時(shí),您可以指定是否要使用iptables或IPVS完成群集內(nèi)負(fù)載平衡。 IPVS專(zhuān)門(mén)用于負(fù)載平衡,并使用更高效的數(shù)據(jù)結(jié)構(gòu)(哈希表),與iptables相比,允許幾乎無(wú)限的規(guī)模。在創(chuàng)建IPVS負(fù)載時(shí),會(huì)發(fā)生以下事情:在Node上創(chuàng)建虛擬IPVS接口,將Service的IP地址綁定到虛擬IPVS接口,并為每個(gè)Service額IP地址創(chuàng)建IPVS服務(wù)器。將來(lái),期望IPVS成為集群內(nèi)負(fù)載平衡的默認(rèn)方法。 4.4 Pod到Service的一個(gè)包的流轉(zhuǎn)image
4.5 Service到Pod的一個(gè)包的流轉(zhuǎn)image
5.Internet與Service之間的網(wǎng)絡(luò)到目前為止,我們已經(jīng)了解了如何在Kubernetes集群中路由流量。下面我們希望將服務(wù)暴露給外部使用(互聯(lián)網(wǎng))。 這需要強(qiáng)調(diào)兩個(gè)相關(guān)的問(wèn)題:(1)從k8s的service訪問(wèn)Internet,以及(2)從Internet訪問(wèn)k8s的service. 5.1 k8s流量到Internet從Node到公共Internet的路由流量是特定于網(wǎng)絡(luò)的,實(shí)際上取決于網(wǎng)絡(luò)配置。為了使本節(jié)更具體,下面使用AWS VPC討論具體細(xì)節(jié)。 在AWS中,k8s集群在VPC內(nèi)運(yùn)行,其中每個(gè)Node都分配了一個(gè)可從k8s集群內(nèi)訪問(wèn)的私有IP地址。要使群集外部的流量可訪問(wèn),需要將Internet網(wǎng)關(guān)連接到VPC。 Internet網(wǎng)關(guān)有兩個(gè)目的:在VPC路由表中提供可以路由到Internet的流量的目標(biāo),以及為已分配公共IP地址的任何實(shí)例執(zhí)行網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)。 NAT轉(zhuǎn)換負(fù)責(zé)將群集專(zhuān)用的節(jié)點(diǎn)內(nèi)部IP地址更改為公共Internet中可用的外部IP地址。 通過(guò)Internet網(wǎng)關(guān),Node可以將流量路由到Internet。不幸的是,有一個(gè)小問(wèn)題。 Pod具有自己的IP地址,該IP地址與承載Pod的Node的IP地址不同,并且Internet網(wǎng)關(guān)上的NAT轉(zhuǎn)換僅適用于Node的 IP地址,因?yàn)樗恢繬ode上正在運(yùn)行那些Pod - Internet網(wǎng)關(guān)不是容器感知的。讓我們?cè)俅慰纯磌8s如何使用iptables解決這個(gè)問(wèn)題。 本質(zhì)都是使用NAT來(lái)做 5.1.1 Node到Internetimage
5.2 Internet到k8simage.png 讓Internet流量進(jìn)入k8s集群,這特定于配置的網(wǎng)絡(luò),可以在網(wǎng)絡(luò)堆棧的不同層來(lái)實(shí)現(xiàn):
5.2.1 第四層流量入口:NodePort讓外網(wǎng)訪問(wèn)k8s內(nèi)部的服務(wù)的第一個(gè)方法是創(chuàng)建一個(gè)NodePort類(lèi)型的Service, 對(duì)于NodePort類(lèi)型的Service,我們可以通過(guò)任何Node的ip和端口號(hào)來(lái)訪問(wèn)NodePort服務(wù)。 創(chuàng)建NodePort類(lèi)型的服務(wù): image.png 如下圖,服務(wù)暴露在兩個(gè)節(jié)點(diǎn)的端口30123上,到達(dá)任何一個(gè)端口的鏈接會(huì)被重定向到一個(gè)隨機(jī)選擇的Pod。 image.png 如何做到的? NodePort是靠kube-proxy服務(wù)通過(guò)iptables的nat轉(zhuǎn)換功能實(shí)現(xiàn)的,kube-proxy會(huì)在運(yùn)行過(guò)程中動(dòng)態(tài)創(chuàng)建與Service相關(guān)的iptables規(guī)則,這些規(guī)則實(shí)現(xiàn)了NodePort的請(qǐng)求流量重定向到kube-proxy進(jìn)程上對(duì)應(yīng)的Service的代理端口上。 kube-proxy接受到Service的請(qǐng)求訪問(wèn)后,會(huì)從service對(duì)應(yīng)的后端Pod中選擇一個(gè)進(jìn)行訪問(wèn)(RR) 但 NodePort 還沒(méi)有完全解決外部訪問(wèn) Service 的所有問(wèn)題,比如負(fù)載均衡問(wèn)題,假如我們 的集群中有 10 個(gè) Node,則此時(shí)最好有一個(gè)負(fù)載均衡器,外部的請(qǐng)求只需訪問(wèn)此負(fù)載均衡器的 IP 地址,由負(fù)載均衡器負(fù) 責(zé)轉(zhuǎn)發(fā)流量到后面某個(gè) Node 的 NodePort 上 5.2.2 第四層流量入口:LoadBalancer該方式是NodePort方式的擴(kuò)展,這使得Service可以通過(guò)一個(gè)專(zhuān)用的負(fù)載均衡器來(lái)訪問(wèn),這個(gè)是由具體云服務(wù)提供商來(lái)提供的,負(fù)載均衡器將流量重定向到所有節(jié)點(diǎn)的端口上,如果云提供商不支持負(fù)載均衡,則退化為NodePort類(lèi)型 創(chuàng)建k8s service時(shí),可以選擇指定LoadBalancer。 LoadBalancer的實(shí)現(xiàn)由云控制器提供,該控制器知道如何為您的service創(chuàng)建負(fù)載均衡器。 創(chuàng)建service后,它將公布負(fù)載均衡器的IP地址。 作為最終用戶,可以開(kāi)始將流量定向到負(fù)載均衡器以開(kāi)始與提供的service進(jìn)行通信。 創(chuàng)建一個(gè)負(fù)載均衡服務(wù): image.png 借助AWS,負(fù)載均衡器可以識(shí)別其目標(biāo)組中的Node,并將平衡群集中所有節(jié)點(diǎn)的流量。 一旦流量到達(dá)Node,之前在整個(gè)群集中為Service安裝的iptables規(guī)則將確保流量到達(dá)感興趣的Service的Pod上。 下面看下LoadBalancer到Service的一個(gè)數(shù)據(jù)包的流轉(zhuǎn)過(guò)程: image
上圖顯示了承載Pod的三個(gè)Node前面的網(wǎng)絡(luò)負(fù)載平衡器。首先流量被傳到的Service的負(fù)載均衡器(1)。一旦負(fù)載均衡器收到數(shù)據(jù)包(2),它就會(huì)隨機(jī)選擇一個(gè)VM。這里我們故意選擇了沒(méi)有Pod運(yùn)行的node:node 2。在這里,node上運(yùn)行的iptables規(guī)則將使用kube-proxy安裝在集群中的內(nèi)部負(fù)載平衡規(guī)則將數(shù)據(jù)包定向到正確的Node 中的Pod。 iptables執(zhí)行正確的NAT并將數(shù)據(jù)包轉(zhuǎn)發(fā)到正確的Pod(4)。 需要注意的是每個(gè)服務(wù)需要?jiǎng)?chuàng)建自己獨(dú)有的負(fù)載均衡器,下面要講解的一種方式所有服務(wù)只需要一個(gè)公開(kāi)服務(wù)。 5.2.3 第七層流量入口:Ingress Controller這是一個(gè)與上面提到的兩種方式完全不同的機(jī)制,通過(guò)一個(gè)公開(kāi)的ip地址來(lái)公開(kāi)多個(gè)服務(wù),第7層網(wǎng)絡(luò)流量入口是在網(wǎng)絡(luò)堆棧的HTTP / HTTPS協(xié)議范圍內(nèi)運(yùn)行,并建立在service之上。 image.png 如上圖,不像負(fù)載均衡器每個(gè)服務(wù)需要一個(gè)公開(kāi)ip,ingress所有服務(wù)只需要一個(gè)公網(wǎng)ip,當(dāng)客戶端向Ingress發(fā)送http請(qǐng)求時(shí)候,ingress會(huì)根據(jù)請(qǐng)求的主機(jī)名和路徑?jīng)Q定請(qǐng)求轉(zhuǎn)發(fā)到那個(gè)服務(wù)。 創(chuàng)建Ingress資源: image.png 如上定義了一個(gè)單一規(guī)則的Ingress,確保Ingress控制器接受的所有請(qǐng)求主機(jī)kubia.example.com的http請(qǐng)求被發(fā)送到端口80上的kubia-nodeport服務(wù)上。 工作原理: 這里Ingress并沒(méi)把請(qǐng)求轉(zhuǎn)發(fā)給Service,而是自己選擇一個(gè)一個(gè)Pod來(lái)訪問(wèn)。 image.png 第7層負(fù)載均衡器的一個(gè)好處是它們具有HTTP感知能力,因此它們了解URL和路徑。 這允許您按URL路徑細(xì)分服務(wù)流量。 它們通常還在HTTP請(qǐng)求的X-Forwarded-For標(biāo)頭中提供原始客戶端的IP地址。 本文參考自:https://blog.csdn.net/liangzhiyang/article/details/106349195 |
|
來(lái)自: 邸彥強(qiáng) > 《技術(shù)》