Kubernetes的容器網路通訊機制

科技中通發表於2020-07-24

(歡迎進入?中通快遞官網瞭解更多資訊)


1

簡介

容器化的近幾年的飛速發展可以預見,以Docker為代表的輕量級容器虛擬化技術,將成為今後企業應用釋出的標準形態,而以Kubernetes(K8S)為代表的雲原生編排系統,將成為分散式叢集架構的核心。隨著容器虛擬化技術的興起與微服務理念的普及,雲端計算正向著“雲原生”(Cloud Native)的方向發展。為了適應這個趨勢,網路也需要進行相應的改造以更好地支撐雲原生平臺。Kubernetes網路一直是一個非常複雜的主題,本文介紹了Kubernetes網路模型和通訊機制。

2

Docker容器網路

Docker容器的隔離特性依賴於Linux核心虛擬化技術,所以Docker對Linux核心的特性有很強的依賴。這裡介紹一下Docker使用到的與Linux網路有關虛擬化技術:網路名稱空間、Veth裝置對、網橋。

2.1. 網路名稱空間

Linux核心為了提供對系統資源的封裝和隔離,提供了多種Namespace,比如:IPC,Mount,PID,Network,User等等,一個程式可以在某一個Namespace下執行,只能看到自己所在的Namespace下的資源,Docker使用了這些功能來實現容器間的隔離。其中的Network Namespace就實現了整個網路棧的隔離,在不同的NetworkNamespace下,有獨立的網路卡、IP地址、埠號、路由表、iptables規則等等。每個Docker容器在建立的時候都會建立一個屬於自己的網路名稱空間。    

圖表 1 Linux下的網路名字空間


2.2. veth裝置對

容器有了不同的網路名稱空間,保證了它們之間的網路隔離,但這個網路空間內只有一個Loopback介面,無法和外部通訊,我們還需要將容器用某種方法連線起來,實現互通。Linux kernel提供了一個叫做veth pair的機制,可以建立兩個虛擬的網路卡,它們之間有一個雙向的管道可以互相通訊,類似於兩個網路卡間使用網線直連。透過ip命令可以將這兩個網路卡加入到不同的namespace中去,兩個namespace間的程式可以透過這兩塊網路卡實現網路通訊。

圖表 2 veth裝置對的連線

2.3. 網橋

透過veth對,可以實現兩個namespace中的通訊,但是多個容器多個namespace的情況下,就不能採用這樣的方法。這時需要Kernel提供的虛擬網橋裝置了。Linux網橋是一個簡單的2層裝置,可以想象成一個軟交換機,把多個網路卡新增到這個軟交換機上,就組成一個網路。
根據這個原理,我們可以在主機上建立一個網橋裝置,對於每一個新的容器,為其建立一對veth網路卡,將其中的一個埠加入到容器所在的namespace中配置好IP地址,同時把另一個埠新增到網橋裝置中。所有的容器就可以透過主機上的網橋來進行報文的轉發了。比如下面的圖中建立了3個不同的網路名字空間,每個名字空間使用一個veth對連線到br0的網橋上。

圖表 3使用網橋連線不同的網路名字空間

這個網路內部已經聯通,還需要能夠訪問外部世界或者被外部世界訪問。Linux網橋雖然是一個二層裝置,但是它可以配置一個IP,作為虛擬網路的閘道器,發往這個IP的報文會進入到host的網路協議棧,利用host上的路由表、iptables等工具,就可以實現容器的虛擬網路到外部網路的訪問。

如下圖所示: Docker預設的情況下會在主機上建立一個叫做docker0的網橋,並設定IP,並使用iptables來實現虛擬網路的NAT功能以及埠對映。docker1、docker2兩個容器發出的對外訪問的報文首先會經過docker0的NAT閘道器,然後主機將報文中的源地址(172.17.0.xxx)改成物理網路卡IP地址(10.10.0.186)然後發出去。

圖表 4 Docker的預設網路結構
 
3

Kubernetes網路

Kubernetes在物理節點上基本沿用了上面介紹的Docker預設網路結構,但它作為容器的編排系統和容器的叢集,在此基礎上還有著自己一套叢集網路模型:

  1. 每個Pod都有叢集內的唯一IP地址,在Pod啟動的時候會自動分配一個IP。
  2. 叢集內部所有的Pod之間可以直接透過IP地址進行訪問,不需要NAT地址轉換。
  3. Node上的agent可以直接訪問其上執行的Pod


3.1 CNI

Kubernetes作為容器的編排框架,在網路層面,並沒有進入更底層的具體容器互通互聯的網路解決方案的設計中,比如:一個Pod應該配置什麼IP,如何配置主機節點使之符合網路模型。Kubernetes沒有提供明確的實現方案,而是提供了一個CNI標準介面,依靠開源社群、各大網路廠商、雲服務提供商等,以外掛的形式來實現具體底層的網路連線。
CNI外掛包括兩部分:CNI Plugin和IPAM Plugin。CNI Plugin用來配置容器的網路,介面實際上很簡單,主要就是:新增網路、刪除網路。當容器建立的時候呼叫新增網路的介面,讓CNI plugin將容器新增到CNI plugin構建的網路中;當容器銷燬時呼叫刪除網路的介面,讓CNI plugin將容器從網路中刪除。而IPAM Plugin是負責給容器分配全域性唯一IP。

現在CNI的外掛非常多,物理機上部署常用Flannel、Calico、Cilium等,而AWS、GCE、阿里雲等雲服務商都提供了自己的CNI外掛,直接使用雲上的網路資源。管理員應該根據實際的需求和物理網路特徵選擇不同的CNI外掛來實現Kubernetes規定的網路模型。

3.2. Pod內部容器的通訊

一個Pod可以包含多個容器,同一個Pod內的容器共享同一個網路名稱空間,共享同一個Linux協議棧。所以同一Pod內的容器,就和它們在同一臺機器上一樣,它們甚至可以用localhost地址訪問彼此的埠。一般會把高度耦合的,或者之間的通訊十分頻繁的容器放在一個Pod內部,實現他們之間的高效訪問。

3.3. 節點內部的Pod之間的通訊

節點上Docker容器底層的網路結構和上面介紹一樣,所有的容器透過veth對,接入一個docker0網橋。只要他們都是在一個網段,那麼就可以直接使用對方的IP地址進行通訊。

圖表 5同一節點內的Pod間通訊


如上圖,Pod1和Pod2可以直接透過IP1和IP2進行互相的通行。

3.4. Pod間網路互通

Kubernetes網路模型要求節點之間的Pod可以直接透過對方的IP進行訪問。但節點上的容器都位於docker0網橋中,形成了一個個獨立的網路。由於外部網路並不知道這些網路的存在,所以他們的地址無法在外部網路中直接互通。如果要實現節點間Pod可以直接使用IP互聯,需要滿足兩個條件:
a) 在整個Kubernetes叢集中對Pod的IP分配進行規劃,不能有衝突。

b) 找到一種辦法,能夠把Pod發出的報文正確的轉發到目標節點和Pod上。

由於CNI外掛負責了Pod的IP分配,所以它可以保證給每個Pod分配一個唯一的IP地址。此外它透過Kubernetes清楚地知道每個Pod位於哪個節點上,所以能夠把Pod發出的報文轉發到正確的目標節點上。不同的CNI外掛使用了很多方案來實現Pod間報文的轉發,但總體分為兩大類:
a) Underlay方式:利用當前資料中心網路基礎轉發架構,配置L3層交換機、路由器、伺服器上的路由等資訊,打通所有節點上的容器網路來實現各個節點間pod的通訊

b) Overlay方式: 基於VXLAN、GRE、Geneve等在基礎網路上建立一層疊加的虛擬網路,節點的所有Pod接入這個虛擬網路實現互通。

  •  Underl ay網路(基於路由)

將叢集每個節點的docker網橋規劃成一個網路,並且將所有的節點打造成路由器(Linux伺服器本來就可以作為路由器使用),使用BGP等動態路由協議來同步每個節點上的Pod網路資訊,更新節點上路由表。節點根據路由表對報文進行正確的轉發。下圖描述了路由的過程:

圖表 6使用L3路由來轉發Pod間報文

Pod1內的容器把報文發向自己所在的docker0網橋的IP,這個網橋對於容器來說相當於是一個閘道器,報文最終來到主機Node1節點的協議棧,協議棧透過路由表確定報文的下一 ,如果目標IP是Pod2,下一條應該是目標Pod所在的節點Node2的IP。透過物理網路將報文轉發到Node2節點上後,Node2根據路由表資訊再將報文轉發到Pod所在的docker網橋閘道器上,再由閘道器轉發到目標Pod。
節點中的路由表是關鍵的資訊,如果路由表不正確,沒有匹配的記錄,報文只能被丟棄。
這種方案的優點是無需對原始報文再次封裝,透過核心的路由轉發,效率比較高;缺點是在超大的叢集規模下,路由表會變的很大,效能會下降,並且所有的節點都必須在一個網路內才能直 接路由。

  • Overlay網路

其原理是在當前網路上,再構建一個覆蓋網路,透過這個網路來轉發Pod之間的報文。從報文角度上看,就是把Pod的報文封裝一次,在實際網路上傳送到對方節點。Flannel的overlay模式就是使用這種方案。
從具體實現上看,Flannel透過路由的配置,把docker0網橋出來的報文轉發到一個flannel0的tun虛擬網路卡上,tun虛擬網路卡收到的資料實際上傳送給了flanneld後臺服務。flanneld收到Pod發出的報文後,對其進行封裝,透過物理網路傳送到目標Pod對應的節點上去,對方節點上的flanneld收到後對其進行解封裝,然後再透過tun虛擬網路卡將報文轉發到目標Pod所在的docker網橋,網橋最終轉發給Pod。不同的封裝方法,構造了不同的overlay網路,Flannel自己實現了一個簡單的基於UDP的封裝協議,整體網路結構如下圖:

圖表 7 Overlay網路模型(Flannel)

Flannel還支援使用vxlan方式進行封裝,使用的是kernel提供的vxlan虛擬網路卡,流程和上述類似,但不再需要tun網路卡和flanneld程式進行報文封裝和傳送,kernel會建立一個vxlan的虛擬網路卡,docker0流量只需要匯入這個vxlan網路卡既可。

3.5. Calico

Calico 是一個典型的基於路由的underlay方案,Calico 在每一個計算節點利用 Linux Kernel 實現了一個高效的 vRouter 來負責資料轉發,而每個vRouter 透過 BGP 協議負責把自己上執行的 workload 的路由資訊像整個 Calico 網路內傳播——小規模部署可以直接互聯,大規模下可透過指定的 BGP route reflector來完成。這樣保證最終所有的 workload 之間的資料流量都是透過 IP 路由的方式完成互聯的。此外,Calico 基於 iptables 還提供了豐富而靈活的網路Policy,保證透過各個節點上的 ACLs 來提供 Workload 的多租戶隔離、安全組以及其他可達性限制等功能。

3.6.Flannel

前面已經介紹過,Flannel透過給每臺宿主機分配一個子網的方式為容器提供虛擬網路,它基於LinuxTUN/TAP,使用多種型別的封裝方案來建立overlay網路,並藉助etcd維護網路的分配情況。封裝方式支援UDP,VXLAN。此外Flannel也支援host-gw這樣的underlay方案。

3.7. Cilium

Cilium 是一個基於 eBPF 和 XDP 的高效能容器網路方案。Cilium同樣實現了基於路由的underlay模式和基於VXLAN和Geneve的overlay模式,由於使用了eBPF+XDP技術,資料處理轉發的速度提高了數倍。eBPF和XDP是Kernel的新特性,eBPF允許使用者態程式將報文處理程式碼插入到Kernel核心態,由核心來執行報文的定製化過濾。而XDP類似DPDK可以旁路掉核心協議棧,直接對報文進行定製化處理。

圖表 8 Cilium

3.8.多CNI網路

一般情況下Kubernetes叢集只需配置一個叢集網路,每個Pod只有一個虛擬網路卡和IP地址。multus可以為執行在Kubernetes的POD提供多個網路介面,它可以將多個CNI外掛組合在一起為POD配置不同型別的網路;最新的multus還支援使用Kubernetes CDR為不同功能的POD提供不同數目的單個或者多網路配置,為Kubernetes下面的網路解決方案提供了更加廣闊的空間。multus支援幾乎所有的CNI plugin,比如Flannel、Calico、Weave、Cilium等等。

它使用"delegates"的概念將多個CNI外掛組合起來,並且指定一個master plugin作為Pod的主網路並且被Kubernetes所感知。


圖表 9 Multus Pod多介面

4

總結

網路永遠是個非常複雜的話題,網路虛擬化和容器虛擬化更是對網路提出很多的挑戰。各種網路解決方案層出不窮。這篇文章是對Docker和Kubernetes網路模型的原理介紹,希望能幫助您對Kubernetes網路的工作方式有更好的瞭解。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69960698/viewspace-2706800/,如需轉載,請註明出處,否則將追究法律責任。

相關文章