簡介
Kubernetes 對容器技術做了更多的抽象,其中最重要的一點是提出 pod 的概念,pod 是 Kubernetes 資源調度的基本單元,我們可以簡單地認為 pod 是容器的一種延伸擴展,從網絡的角度來看,pod 必須滿足以下條件:
- 同一個pod內的所有容器之間共享端口,可直接通過
localhost
+端口
來訪問 - 由於每個pod有單獨的IP,所以不需要考慮容器端口與主機端口映射以及端口沖突問題
事實上,Kubernetes進一步確定了對一個合格集群網絡的基本要求:
- 任意兩個pod之間其實是可以直接通信的,無需顯式地使用NAT進行地址的轉換;
- 任意集群節點node與任意pod之間是可以直接通信的,無需使用明顯的地址轉換,反之亦然;
- 任意pod看到自己的IP跟別人看見它所用的IP是一樣的,中間不能經過地址轉換;
也就是說,必須同時滿足以上三點的網絡模型才能適用於kubernetes,事實上,在早期的Kubernetes中,並沒有什么網絡標准,只是提出了以上基本要求,只有滿足這些要求的網絡才可以部署Kubernetes,基於這樣的底層網絡假設,Kubernetes設計了pod-deployment-service
的經典三層服務訪問機制。直到1.1發布,Kubernetes才開始采用全新的CNI(Container Network Interface)網絡標准。
網絡方案
網絡架構是Kubernetes中較為復雜、讓很多用戶頭疼的方面之一。Kubernetes網絡模型本身對某些特定的網絡功能有一定要求,但在實現方面也具有一定的靈活性。因此,業界已有不少不同的網絡方案,來滿足特定的環境和要求。
如容器網絡模型一樣,對於統一主機上的pod之間,通過docker0
網橋設備直接二層(數據鏈路層)網絡上通過MAC地址直接通信:
而跨主機的pod之間的相互通信也主要有以下兩個思路:
- 修改底層網絡設備配置,加入容器網絡IP地址的管理,修改路由器網關等,該方式主要和SDN(Software define networking)結合。
- 完全不修改底層網絡設備配置,復用原有的underlay平面網絡,解決容器跨主機通信,主要有如下兩種方式:
- 隧道傳輸(Overlay): 將容器的數據包封裝到原主機網絡的三層或者四層數據包中,然后使用主機網絡的IP或者TCP/UDP傳輸到目標主機,目標主機拆包后再轉發給目標容器。Overlay隧道傳輸常見方案包括Vxlan、ipip等,目前使用Overlay隧道傳輸技術的主流容器網絡有Flannel等;
- 修改主機路由:把容器網絡加到主機路由表中,把主機網絡設備當作容器網關,通過路由規則轉發到指定的主機,實現容器的三層互通。目前通過路由技術實現容器跨主機通信的網絡如Flannel host-gw、Calico等;
CNI
CNI (Container Network Interface),即容器網絡的 API 接口。它是 K8s 中標准的一個調用網絡實現的接口,Kubelet 通過這個標准的 API 來調用不同的網絡插件以實現不同的網絡配置方式,實現了這個接口的就是 CNI 插件,它實現了一系列的 CNI API 接口。常見的 CNI 插件包括 Calico、flannel、Terway、Weave Net 以及 Contiv。

如何使用 CNI
實現一個 CNI 網絡插件只需要一個配置文件和一個可執行文件
- 配置文件描述插件的版本、名稱、描述等基本信息;
- 可執行文件會被上層的容器管理平台調用,一個 CNI 可執行文件需要實現將容器加入到網絡的 ADD 操作以及將容器從網絡中刪除的 DEL 操作(以及一個可選的 VERSION 查看版本操作);
Kubernetes 使用 CNI 網絡插件的基本工作流程:
- kubelet 先創建 pause 容器創建對應的網絡命名空間;
- 根據配置調用具體的 CNI 插件,可以配置成 CNI 插件鏈來進行鏈式調用;
- 當 CNI 插件被調用時,它根據環境變量以及命令行參數來獲得網絡命名空間、容器的網絡設備等必要信息,然后執行 ADD 操作;
- CNI 插件給 pause 容器配置正確的網絡,pod 中其他的容器都是復用 pause 容器的網絡;
相關知識點
在對CNI插件們進行比較之前,我們可以先對網絡中會見到的相關術語做一個整體的了解。不論是閱讀本文,還是今后接觸到其他和CNI有關的內容,了解一些常見術語總是非常有用的。
- 第2層網絡: OSI(Open Systems Interconnections,開放系統互連)網絡模型的“數據鏈路”層。第2層網絡會處理網絡上兩個相鄰節點之間的幀傳遞。第2層網絡的一個值得注意的示例是以太網,其中MAC表示為子層。
- 第3層網絡: OSI網絡模型的“網絡”層。第3層網絡的主要關注點,是在第2層連接之上的主機之間路由數據包。IPv4、IPv6和ICMP是第3層網絡協議的示例。
- VXLAN:代表“虛擬可擴展LAN”。首先,VXLAN用於通過在UDP數據報中封裝第2層以太網幀來幫助實現大型雲部署。VXLAN虛擬化與VLAN類似,但提供更大的靈活性和功能(VLAN僅限於4096個網絡ID)。VXLAN是一種封裝和覆蓋協議,可在現有網絡上運行。
- Overlay網絡:Overlay網絡是建立在現有網絡之上的虛擬邏輯網絡。Overlay網絡通常用於在現有網絡之上提供有用的抽象,並分離和保護不同的邏輯網絡。
- 封裝:封裝是指在附加層中封裝網絡數據包以提供其他上下文和信息的過程。在overlay網絡中,封裝被用於從虛擬網絡轉換到底層地址空間,從而能路由到不同的位置(數據包可以被解封裝,並繼續到其目的地)。
- 網狀網絡:網狀網絡(Mesh network)是指每個節點連接到許多其他節點以協作路由、並實現更大連接的網絡。網狀網絡允許通過多個路徑進行路由,從而提供更可靠的網絡。網狀網格的缺點是每個附加節點都會增加大量開銷。
- BGP:代表“邊界網關協議”,用於管理邊緣路由器之間數據包的路由方式。BGP通過考慮可用路徑,路由規則和特定網絡策略,幫助弄清楚如何將數據包從一個網絡發送到另一個網絡。BGP有時被用作CNI插件中的路由機制,而不是封裝的覆蓋網絡。
CNI插件分析
通常來說,CNI 插件可以分為三種:Overlay、路由及 Underlay。
- Overlay 模式的典型特征是容器獨立於主機的 IP 段,這個 IP 段進行跨主機網絡通信時是通過在主機之間創建隧道的方式,將整個容器網段的包全都封裝成底層的物理網絡中主機之間的包。該方式的好處在於它不依賴於底層網絡;
- 路由模式中主機和容器也分屬不同的網段,它與 Overlay 模式的主要區別在於它的跨主機通信是通過路由打通,無需在不同主機之間做一個隧道封包。但路由打通就需要部分依賴於底層網絡,比如說要求底層網絡有二層可達的一個能力;
- Underlay 模式中容器和宿主機位於同一層網絡,兩者擁有相同的地位。容器之間網絡的打通主要依靠於底層網絡。因此該模式是強依賴於底層能力的。
插件選擇
環境限制
不同環境中所支持的底層能力是不同的。
- 虛擬化環境(例如 OpenStack)中的網絡限制較多,比如不允許機器之間直接通過二層協議訪問,必須要帶有 IP 地址這種三層的才能去做轉發,限制某一個機器只能使用某些 IP 等。在這種被做了強限制的底層網絡中,只能去選擇 Overlay 的插件,常見的有 Flannel-vxlan, Calico-ipip, Weave 等等;
- 物理機環境中底層網絡的限制較少,比如說我們在同一個交換機下面直接做一個二層的通信。對於這種集群環境,我們可以選擇 Underlay 或者路由模式的插件。Underlay 意味着我們可以直接在一個物理機上插多個網卡或者是在一些網卡上做硬件虛擬化;路由模式就是依賴於 Linux 的路由協議做一個打通。這樣就避免了像 vxlan 的封包方式導致的性能降低。這種環境下我們可選的插件包括 clico-bgp, flannel-hostgw, sriov 等等;
- 公有雲環境也是虛擬化,因此底層限制也會較多。但每個公有雲都會考慮適配容器,提升容器的性能,因此每家公有雲可能都提供了一些 API 去配置一些額外的網卡或者路由這種能力。在公有雲上,我們要盡量選擇公有雲廠商提供的 CNI 插件以達到兼容性和性能上的最優。比如 Aliyun 就提供了一個高性能的 Terway 插件。
功能需求
- 首先是安全需求;
K8s 支持 NetworkPolicy,就是說我們可以通過 NetworkPolicy 的一些規則去支持“Pod 之間是否可以訪問”這類策略。但不是每個 CNI 插件都支持 NetworkPolicy 的聲明,如果大家有這個需求,可以選擇支持 NetworkPolicy 的一些插件,比如 Calico, Weave 等等。
- 第二個是是否需要集群外的資源與集群內的資源互聯互通;
大家的應用最初都是在虛擬機或者物理機上,容器化之后,應用無法一下就完成遷移,因此就需要傳統的虛擬機或者物理機能跟容器的 IP 地址互通。為了實現這種互通,就需要兩者之間有一些打通的方式或者直接位於同一層。此時可以選擇 Underlay 的網絡,比如 sriov 這種就是 Pod 和以前的虛擬機或者物理機在同一層。我們也可以使用 calico-bgp,此時它們雖然不在同一網段,但可以通過它去跟原有的路由器做一些 BGP 路由的一個發布,這樣也可以打通虛擬機與容器。
- 最后考慮的就是 K8s 的服務發現與負載均衡的能力。
K8s 的服務發現與負載均衡就是我們前面所介紹的 K8s 的 Service,但並不是所有的 CNI 插件都能實現這兩種能力。比如很多 Underlay 模式的插件,在 Pod 中的網卡是直接用的 Underlay 的硬件,或者通過硬件虛擬化插到容器中的,這個時候它的流量無法走到宿主機所在的命名空間,因此也無法應用 kube-proxy 在宿主機配置的規則。
這種情況下,插件就無法訪問到 K8s 的服務發現。因此大家如果需要服務發現與負載均衡,在選擇 Underlay 的插件時就需要注意它們是否支持這兩種能力。
經過功能需求的過濾之后,能選的插件就很少了。經過環境限制和功能需求的過濾之后,如果還剩下 3、4 種插件,可以再來考慮性能需求。
性能需求
我們可以從 Pod 的創建速度和 Pod 的網絡性能來衡量不同插件的性能。
- Pod 的創建速度
當我們創建一組 Pod 時,比如業務高峰來了,需要緊急擴容,這時比如說我們擴容了 1000 個 Pod,就需要 CNI 插件創建並配置 1000 個網絡資源。Overlay 和路由模式在這種情況下的創建速度是很快的,因為它是在機器里面又做了虛擬化,所以只需要調用內核接口就可以完成這些操作。但對於 Underlay 模式,由於需要創建一些底層的網絡資源,所以整個 Pod 的創建速度相對會慢一些。因此對於經常需要緊急擴容或者創建大批量的 Pod 這些場景,我們應該盡量選擇 Overlay 或者路由模式的網絡插件。
- Pod 的網絡性能
主要表現在兩個 Pod 之間的網絡轉發、網絡帶寬、PPS 延遲等這些性能指標上。Overlay 模式的性能較差,因為它在節點上又做了一層虛擬化,還需要去封包,封包又會帶來一些包頭的損失、CPU 的消耗等,如果大家對網絡性能的要求比較高,比如說機器學習、大數據這些場景就不適合使用 Overlay 模式。這種情形下我們通常選擇 Underlay 或者路由模式的 CNI 插件。
主流插件介紹
Flannel
由CoreOS開發的項目Flannel,可能是最直接和最受歡迎的CNI插件。它是容器編排系統中最成熟的網絡結構示例之一,旨在實現更好的容器間和主機間網絡。隨着CNI概念的興起,Flannel CNI插件算是早期的入門。
與其他方案相比,Flannel相對容易安裝和配置。它被打包為單個二進制文件flanneld,許多常見的Kubernetes集群部署工具和許多Kubernetes發行版都可以默認安裝Flannel。Flannel可以使用Kubernetes集群的現有etcd集群來使用API存儲其狀態信息,因此不需要專用的數據存儲。
Flannel配置第3層IPv4 overlay網絡。它會創建一個大型內部網絡,跨越集群中每個節點。在此overlay網絡中,每個節點都有一個子網,用於在內部分配IP地址。在配置pod時,每個節點上的Docker橋接口都會為每個新容器分配一個地址。同一主機中的Pod可以使用Docker橋接進行通信,而不同主機上的pod會使用flanneld將其流量封裝在UDP數據包中,以便路由到適當的目標。
Flannel實現原理
了解了以上概念之后,就能說明flannel的實現原理了,為了解釋清楚,把實現原理分為以下幾個步驟:
- 數據從Web App Frontend1這個容器發出經veth0網橋轉發到宿主機的docker0網橋上
- docker0網橋根據數據包的目的地址進行轉發,若為非本機容器地址則轉發給Flannel0網卡處理
- Flannel0網卡交給flanneld這個進程處理,flanneld通過查詢etcd,找到目的容器地址,並進行轉發
- 數據包到達目的主機,經flanneld解包,最后由docker0轉發到目的容器
這樣整個數據包發送過程就解釋完成了。
當然僅僅是這樣還不夠,flannel為每個在它管理下的容器賦予了一個獨立的不會重復的ip地址,這樣跨主機容器的ip地址就不會重復了,在這個前提下才能實現以上步驟的精確轉發。
Flannel有幾種不同類型的后端可用於封裝和路由。默認和推薦的方法是使用VXLAN,因為VXLAN性能更良好並且需要的手動干預更少。
總的來說,Flannel是大多數用戶的不錯選擇。從管理角度來看,它提供了一個簡單的網絡模型,用戶只需要一些基礎知識,就可以設置適合大多數用例的環境。一般來說,在初期使用Flannel是一個穩妥安全的選擇,直到你開始需要一些它無法提供的東西。
Calico
Calico是Kubernetes生態系統中另一種流行的網絡選擇。雖然Flannel被公認為是最簡單的選擇,但Calico以其性能、靈活性而聞名。Calico的功能更為全面,不僅提供主機和pod之間的網絡連接,還涉及網絡安全和管理。Calico CNI插件在CNI框架內封裝了Calico的功能。
在滿足系統要求的新配置的Kubernetes集群上,用戶可以通過應用單個manifest文件快速部署Calico。如果您對Calico的可選網絡策略功能感興趣,可以向集群應用其他manifest,來啟用這些功能。
盡管部署Calico所需的操作看起來相當簡單,但它創建的網絡環境同時具有簡單和復雜的屬性。與Flannel不同,Calico不使用overlay網絡。相反,Calico配置第3層網絡,該網絡使用BGP路由協議在主機之間路由數據包。這意味着在主機之間移動時,不需要將數據包包裝在額外的封裝層中。BGP路由機制可以本地引導數據包,而無需額外在流量層中打包流量。
除了性能優勢之外,在出現網絡問題時,用戶還可以用更常規的方法進行故障排除。雖然使用VXLAN等技術進行封裝也是一個不錯的解決方案,但該過程處理數據包的方式同場難以追蹤。使用Calico,標准調試工具可以訪問與簡單環境中相同的信息,從而使更多開發人員和管理員更容易理解行為。
除了網絡連接外,Calico還以其先進的網絡功能而聞名。 網絡策略是其最受追捧的功能之一。此外,Calico還可以與服務網格Istio集成,以便在服務網格層和網絡基礎架構層中解釋和實施集群內工作負載的策略。這意味着用戶可以配置強大的規則,描述pod應如何發送和接受流量,提高安全性並控制網絡環境。
如果對你的環境而言,支持網絡策略是非常重要的一點,而且你對其他性能和功能也有需求,那么Calico會是一個理想的選擇。此外,如果您現在或未來有可能希望得到技術支持,那么Calico是提供商業支持的。一般來說,當您希望能夠長期控制網絡,而不是僅僅配置一次並忘記它時,Calico是一個很好的選擇。
Canal
Canal也是一個有趣的選擇,原因有很多。
首先,Canal 是一個項目的名稱,它試圖將Flannel提供的網絡層與Calico的網絡策略功能集成在一起。然而,當貢獻者完成細節工作時卻發現,很明顯,如果Flannel和Calico這兩個項目的標准化和靈活性都已各自確保了話,那集成也就沒那么大必要了。結果,這個官方項目變得有些“爛尾”了,不過卻實現了將兩種技術部署在一起的預期能力。出於這個原因,即使這個項目不復存在,業界還是會習慣性地將Flannel和Calico的組成稱為“Canal”。
由於Canal是Flannel和Calico的組合,因此它的優點也在於這兩種技術的交叉。網絡層用的是Flannel提供的簡單overlay,可以在許多不同的部署環境中運行且無需額外的配置。在網絡策略方面,Calico強大的網絡規則評估,為基礎網絡提供了更多補充,從而提供了更多的安全性和控制。
確保集群滿足必要的系統要求(https://docs.projectcalico.or...)后,用戶需要應用兩個manifest才能部署Canal,這使得其配置比單獨的任何一個項目都困難。如果企業的IT團隊計划改變他們的網絡方案,且希望在實施改變之前能先對網絡策略進行一些實驗並獲取一些經驗,那么Canal是一個不錯的選擇。
一般來說,如果你喜歡Flannel提供的網絡模型,但發現Calico的一些功能很誘人,那么不妨嘗試一下Canal。從安全角度來看,定義網絡策略規則的能力是一個巨大的優勢,並且在許多方面是Calico的殺手級功能。能夠將該技術應用到熟悉的網絡層,意味着您可以獲得更強大的環境,且可以省掉大部分的過渡過程。
Weave
Weave是由Weaveworks提供的一種Kubernetes CNI網絡選項,它提供的模式和我們目前為止討論的所有網絡方案都不同。Weave在集群中的每個節點之間創建網狀overlay網絡,參與者之間可以靈活路由。這一特性再結合其他一些獨特的功能,在某些可能導致問題的情況下,Weave可以智能地路由。
為了創建網絡,Weave依賴於網絡中每台主機上安裝的路由組件。然后,這些路由器交換拓撲信息,以維護可用網絡環境的最新視圖。當需要將流量發送到位於不同節點上的pod時,Weave路由組件會自動決定是通過“快速數據路徑”發送,還是回退到“sleeve”分組轉發的方法。
快速數據路徑依靠內核的本機Open vSwitch數據路徑模塊,將數據包轉發到適當的pod,而無需多次移入和移出用戶空間。Weave路由器會更新Open vSwitch配置,以確保內核層具有有關如何路由傳入數據包的准確信息。相反,當網絡拓撲不適合快速數據路徑路由時,sleeve模式可用作備份。它是一種較慢的封裝模式,在快速數據路徑缺少必要的路由信息或連接的情況下,它可以來路由數據包。當流量通過路由器時,它們會了解哪些對等體與哪些MAC地址相關聯,從而允許它們以更少的跳數、更智能地路由后續流量。當網絡更改導致可用路由改變時,這一相同的機制可以幫助每個節點進行自行更正。
與Calico一樣,Weave也為Kubernetes集群提供網絡策略功能。設置Weave時,網絡策略會自動安裝和配置,因此除了添加網絡規則之外,用戶無需進行其他配置。一個其他網絡方案都沒有、Weave獨有的功能,是對整個網絡的簡單加密。雖然這會增加相當多的網絡開銷,但Weave可以使用NaCl加密(http://nacl.cr.yp.to)來為sleeve流量自動加密所有路由流量,而對於快速數據路徑流量,因為它需要加密內核中的VXLAN流量,Weave會使用IPsec ESP來加密快速數據路徑流量。
對於那些尋求功能豐富的網絡、同時希望不要增加大量復雜性或管理難度的人來說,Weave是一個很好的選擇。它設置起來相對容易,提供了許多內置和自動配置的功能,並且可以在其他解決方案可能出現故障的場景下提供智能路由。網狀拓撲結構確實會限制可以合理容納的網絡的大小,不過對於大多數用戶來說,這也不是一個大問題。此外,Weave也提供收費的技術支持,可以為企業用戶提供故障排除等等技術服務。
開發CNI 插件
有時社區的插件無法滿足自己的需求,比如在阿里雲上只能使用 vxlan 這種 Overlay 的插件,而 Overlay 插件的性能相對較差,無法滿足阿里雲上的一些業務需求,所以阿里雲上開發了一個 Terway 的插件。
如果我們自己的環境比較特殊,在社區里面又找不到合適的網絡插件,此時可以開發一個自己的 CNI 插件。
CNI 插件的實現通常包含兩個部分:
- 一個二進制的 CNI 插件去配置 Pod 網卡和 IP 地址。這一步配置完成之后相當於給 Pod 上插上了一條網線,就是說它已經有自己的 IP、有自己的網卡了;
- 一個 Daemon 進程去管理 Pod 之間的網絡打通。這一步相當於說將 Pod 真正連上網絡,讓 Pod 之間能夠互相通信。
給 Pod 插上網線
配置網卡
通常我們會用一個 “veth” 這種虛擬網卡,一端放到 Pod 的網絡空間,一端放到主機的網絡空間,這樣就實現了 Pod 與主機這兩個命名空間的打通。
分配 IP 地址
這個 IP 地址有一個要求,如何保障集群里面給 Pod 分配的是個唯一的 IP 地址?
一般來說我們在創建整個集群的時候會指定 Pod 的一個大網段,按照每個節點去分配一個 Node 網段。比如說上圖右側創建的是一個 172.16 的網段,我們再按照每個節點去分配一個 /24 的段,這樣就能保障每個節點上的地址是互不沖突的。然后每個 Pod 再從一個具體的節點上的網段中再去順序分配具體的 IP 地址,比如 Pod1 分配到了 172.16.0.1,Pod2 分配到了 172.16.0.2,這樣就實現了在節點里面 IP 地址分配的不沖突,並且不同的 Node 又分屬不同的網段,因此不會沖突。
這樣就給 Pod 分配了集群里面一個唯一的 IP 地址。
配置 Pod 的 IP 和路由
- 第一步,將分配到的 IP 地址配置給 Pod 的虛擬網卡;
- 第二步,在 Pod 的網卡上配置集群網段的路由,令訪問的流量都走到對應的 Pod 網卡上去,並且也會配置默認路由的網段到這個網卡上,也就是說走公網的流量也會走到這個網卡上進行路由;
- 最后在宿主機上配置到 Pod 的 IP 地址的路由,指向到宿主機對端 veth1 這個虛擬網卡上。這樣實現的是從 Pod 能夠到宿主機上進行路由出去的,同時也實現了在宿主機上訪問到 Pod 的 IP 地址也能路由到對應的 Pod 的網卡所對應的對端上去。
連接網絡
剛才我們是給 Pod 插上網線,也就是給它配了 IP 地址以及路由表。那怎么打通 Pod 之間的通信呢?也就是讓每一個 Pod 的 IP 地址在集群里面都能被訪問到。
一般我們是在 CNI Daemon 進程中去做這些網絡打通的事情。通常來說是這樣一個步驟:
- 首先 CNI 在每個節點上運行的 Daemon 進程會學習到集群所有 Pod 的 IP 地址及其所在節點信息。學習的方式通常是通過監聽 K8s APIServer,拿到現有 Pod 的 IP 地址以及節點,並且新的節點和新的 Pod 的創建的時候也能通知到每個 Daemon;
- 拿到 Pod 以及 Node 的相關信息之后,再去配置網絡進行打通。
- 首先 Daemon 會創建到整個集群所有節點的通道。這里的通道是個抽象概念,具體實現一般是通過 Overlay 隧道、阿里雲上的 VPC 路由表、或者是自己機房里的 BGP 路由完成的;
- 第二步是將所有 Pod 的 IP 地址跟上一步創建的通道關聯起來。關聯也是個抽象概念,具體的實現通常是通過 Linux 路由、fdb 轉發表或者OVS 流表等完成的。Linux 路由可以設定某一個 IP 地址路由到哪個節點上去。fdb 轉發表是 forwarding database 的縮寫,就是把某個 Pod 的 IP 轉發到某一個節點的隧道端點上去(Overlay 網絡)。OVS 流表是由 Open vSwitch 實現的,它可以把 Pod 的 IP 轉發到對應的節點上。
結 語
Kubernetes采用的CNI標准,讓Kubernetes生態系統中的網絡解決方案百花齊放。更多樣的選擇,意味着大多數用戶將能夠找到適合其當前需求和部署環境的CNI插件,同時還可以在環境發生變化時也能找到新的解決方案。
不同企業之間的運營要求差異很大,因此擁有一系列具有不同復雜程度和功能豐富性的成熟解決方案,大大有助於Kubernetes在滿足不同用戶獨特需求的前提下,仍然能夠提供一致的用戶體驗。
參考