1. 程式人生 > >超長乾貨丨Kubernetes網路快速入門完全指南

超長乾貨丨Kubernetes網路快速入門完全指南

Kubernetes網路一直是一個非常複雜的主題。本文將介紹Kubernetes實際如何建立網路以及如何為Kubernetes叢集設定網路。

本文不包括如何設定Kubernetes叢集。這篇文章中的所有例子都將使用Rancher 2.0叢集(其他平臺也同樣適用)。即使你打算使用其他的公有云管理Kubernetes服務,也希望你對Kubernetes網路的工作原理有更好的瞭解。

如何使用Kubernetes網路

許多Kubernetes部署指南中包含了在K8S部署中部署Kubernetes網路CNI的說明。但是如果你的K8S叢集已經執行,並且尚未部署任何網路,那麼部署網路就像在K8S上執行其提供的配置檔案一樣簡單(對於大多數網路和基本用例而言)。例如,要部署flannel:

這樣,從網路的角度來看,K8S已經可以使用。為了測試一切是否正常,我們建立了兩個Pod。

這將建立兩個pod,它們正在使用我們的驅動器。檢視其中一個容器,我們發現網路的IP地址範圍為10.42.0.0/24。

在另一個Pod進行的快速ping測試表明,網路執行正常。

與Docker網路相比,Kubernetes網路如何工作?

Kubernetes通過Docker之上的CNI管理網路,並將裝置附加到Docker。儘管有Docker Swarm的Docker也具有自己的聯網功能(例如overlay、macvlan、bridging等),但CNI也提供了類似型別的功能。

還有一點十分重要,K8S並不使用docker0(這是Docker的預設網橋),而是建立自己的網橋,名為cbr0,該網橋需要與docker0區分開來。

為什麼我們需要Overlay網路?

諸如vxlan或ipsec之類的overlay網路(如果你設定過安全VPN,你應該對此比較熟悉)可以將資料包封裝到另一個數據包中。這使得實體在另一臺計算機的範圍之外依舊可以定址。Overlay網路的替代方案包括如macvtap(lan)之類的L3解決方案,甚至包括ivtap(lan)之類的L2解決方案,但是這些方案具有一定的侷限性。

L2或L3上的任何解決方案都可以讓pod在網路上定址。這意味著pod不僅在Docker網路內部訪問,還能直接從Docker網路外部訪問。這些是公共IP地址或私有IP地址。

然而,在L2上進行通訊比較麻煩,並且你的經驗會因為網路裝置而異。某些交換機需要一些時間來註冊你的Mac地址,然後才能將其實際連線到網路的其餘部分。你還可能會遇到一些麻煩,因為系統中其他主機的neighbor(ARP) table仍在過時的快取上執行,並且始終需要使用dhcp執行而不是host-local,這樣可以避免主機之間的ip衝突。Mac地址和neighbor table問題是諸如ipvlan之類的解決方案存在的原因。這些解決方案不會註冊新的mac地址,而是在現有地址上路由流量(儘管它們也有自己的問題)。

因此,我的建議是,對於大多數使用者而言,將overlay網路作為預設解決方案應該足夠了。但是,一旦工作負載變得更加高階並提出了更具體的要求,你將需要考慮其他的解決方案,如BGP和直接路由。

Kubernetes網路如何工作?

在Kubernetes中首先要了解的是,pod實際上並不等同於容器,而是容器的集合。在同一集合的容器中共享一個網路堆疊。Kubernetes通過在暫停容器上設定網路來進行管理,你可以在你所建立的每個pod中找到這些暫停容器。所有其他pod都連線到暫停容器的網路,該容器本身除了提供網路外不執行任何操作。因此,也可以使一個容器通過localhost與不同容器中的服務進行通訊,此時該容器具有相同pod的相同定義。

除了本地通訊之外,pod之間的通訊看起來與Docker網路中的container-to-container通訊幾乎相同。

Kubernetes流量路由

我將以兩種場景為例,詳細地說明如何在Pod之間路由流量。

1、 在同一主機上路由流量:

在兩種情況下,流量不會離開主機。一是當呼叫的服務在同一節點上執行,一是單個pod中的同一個容器集合。

如果從第一個pod中的容器1呼叫localhost:80並在容器2中執行服務,則流量將通過網路裝置並將資料包轉發到其他目的地。在這種情況下,路由流量的路線很短。

如果我們想要與其他pod進行通訊,時間會更長一些。首先,流量將傳遞到cbr0,接下來cbr0將會注意到我們在同一個子網通訊,因此它會將流量轉發到目標Pod,過程如下圖所示:

2、 跨主機路由流量:

當我們離開節點時,這將變得更加複雜。現在,cbr0會將流量傳遞到下一個節點,該節點的配置由CNI管理。這些基本上只是以目標主機為閘道器的子網路由。然後,目標主機可以繼續使用自己的cbr0並將流量轉發到目標容器,如下所示:

究竟什麼是CNI?

CNI是Container Networking Interface(容器網路介面)的縮寫,基本上是一個具有定義明確的外部介面,Kubernetes可以呼叫它來提供網路功能。

你可以在以下連結中找到維護的參考外掛,其中包括容器網路官方repo中的大多數重要外掛:

https://github.com/containernetworking/plugins

CNI 3.1版不是很複雜。它包含三個必需的功能,ADD、DEL和VERSION,這些功能可以盡其所能管理網路。有關每個函式應返回和傳遞的內容的更詳細說明,您可以在此處閱讀規範:

https://github.com/containernetworking/cni/blob/master/SPEC.md

CNI之間的區別

以下我們將介紹一些最受歡迎的CNI:

Flannel

Flannel是一個簡單的網路,並且是overlay網路最簡單的設定選項。它的功能包括原生網路,但在多個網路中使用時會受到限制。對於大多數使用者來說,Flannel是Canal下面的預設網路,部署起來非常簡單,甚至還有本地網路功能,如主機閘道器。但是Flannel有一些限制,包括缺乏對網路安全策略的支援以及沒有多網路的功能。

Calico

Calico與Flannel採用不同的方法,從技術的角度來說,它不是overlay網路,而是在所有相關係統之間配置路由的系統。為此,Calico利用邊界閘道器協議(BGP),它在名為peering的過程中用於Internet。其中每方peering交換流量並參與BGP網路。BGP協議本身會在其ASN下傳播路由,不同之處在於它們是私有的,不需要再RIPE中註冊它們。

但是,在某些情況下,Calico可與overlay網路配合使用,如IPINIP。當節點位於不同網路上時使用,以便啟動兩個主機之間的流量交換。

Canal

Canal基於Flannel,但有一些Calico自己的元件,例如felix(主機代理),它可以利用網路安全策略。這些通常在Flannel中不存在。因此,它基本上通過新增安全策略來擴充套件Flannel。

Multus

Multus是一個CNI,但實際上它本身並不是網路介面。只是它編排了多個介面,並且沒有配置實際的網路,因而Pod無法單獨與Multus通訊。實際上,Multus是多裝置和多子網網路的推動者。下圖顯示了它是如何工作的,Multus本身基本上呼叫了真正的CNI而不是kubelet,並將結果傳遞迴kubelet。

Kube-Router

同樣值得一提的是kube-router,與Calico一樣,它可以與BGP和路由而不是overlay網路一起使用。就像Calico一樣,它在必要的時候可以使用IPINIP。它還能利用ipvs進行負載均衡。

設定多網路K8S叢集

如果您需要使用多個網路,則可能需要Multus。

設定Multus

我們需要做的第一件事是設定Multus。我們使用的幾乎是Multus倉庫示例中的配置,但進行了一些重要的調整。請參閱下面的示例。

首先是調整configmap。因為我們計劃使用Flannel建立預設網路,所以我們在Multus配置的delegates陣列中定義配置。這裡用紅色標記的一些重要設定是“ masterplugin”:true,用於定義Flannel網路本身的網橋。你將在接下來的步驟中瞭解為什麼我們需要這樣做。除此之外,還需要新增配置對映的安裝定義,其他則不需要調整,因為由於某些原因,此示例未完成。

關於此configmap的另一件重要事情是,這一configmap中定義的所有內容都是預設網路,這些預設網路會自動安裝到容器,而無需進一步說明。另外,如果要編輯此檔案,請注意,你要麼需要終止並重新執行守護程序的容器,要麼重新啟動節點才能使更改生效。

示例yaml檔案:


設定主要的Flannel Overlay網路

對於主要的Flannel網路,設定非常簡單。我們可以從Multus倉庫中獲取示例,然後進行部署。此處所做的調整是CNI安裝、容差的調整以及對Flannel的CNI設定所做的一些調整。例如,新增“ forceAddress”:true並刪除“ hairpinMode”:true。

這已在使用RKE設定的叢集上進行了測試,但是隻要您從主機正確安裝CNI(在本例中為/ opt / cni / bin),它就可以在其他叢集上工作。

Multus本身並沒有太大的改變。他們只註釋了initcontainer配置,你可以刪除它。之所以如此,是因為Multus將建立其delegates,並充當主要的“ CNI”。

這是修改後的Flannel daemonset:


部署了這些樣本之後,我們已經完成了很多工作,現在應該為pod分配一個IP地址。讓我們測試一下:



如你所見,我們已經成功部署了Pod,並在eth0介面(預設介面)上為其分配了IP 10.42.2.43。所有其他介面都將顯示為netX,即net1。

設定輔助網路

輔助網路還需要進行一些調整,這些調整的前提是假設你要部署vxlan。為了實際服務於輔助overlay,我們需要更改VXLAN識別符號“ VIN”,預設情況下將其設定為1,並且我們的第一個overlay網路現在已經使用了它。因此,我們可以通過在etcd伺服器上配置網路來更改此設定。我們使用自己的叢集etcd,此處標記為綠色(並且假設job在執行etcd客戶端的主機上執行),然後從本地主機(在我們的情況下,將其儲存在本地主機)中裝入金鑰(此處標記為紅色),儲存在/ etc / kubernetes / ssl資料夾中。

完整的YAML檔案示例:

接下來,我們可以實際部署輔助網路。此設定幾乎與主要網路設定相同,但有一些關鍵區別。最明顯的是,我們更改了子網,但是我們還需要更改其他一些內容。

首先,我們需要設定一個不同的dataDir,即/ var / lib / cni / flannel2,以及一個不同的subnetFile,即/run/flannel/flannel2.env。這十分必要,因為它們已經被我們的主要網路佔用。接下來,我們需要調整網橋,因為主要的Flannel overlay網路已經使用了kbr0。

其餘還需更改的配置包括將其更改為實際針對我們之前配置的etcd伺服器。在主網路中,這是通過–kube-subnet-mgr flag直接連線到K8S API來完成的。但是我們不能這樣做,因為我們還需要修改要讀取的字首。你可以在下面看到橙色標記的內容,而叢集etcd連線的設定則顯示為紅色。最後一個設定是再次指定子網檔案,在示例中以綠色標記。最後一點是,我們添加了一個網路定義。其餘部分與我們的主要網路配置相同。

有關上述步驟,請參見示例配置檔案:


完成此操作後,我們便準備好了輔助網路。

分配額外的網路

既然我們已經準備好輔助網路,那麼我們現在需要分配他。為此,我們需要先定義一個NetworkAttachmentDefinition,之後我們可以使用它將網路分配給容器。基本上,這是在初始化Multus之前,我們設定的configmap的動態替代方案。這樣,我們可以按需安裝所需的網路。在此定義中,我們需要指定網路型別(本例中是Flannel)以及必要的配置。這包括前面提到的subnetFile、dataDir和網橋名稱。

我們需要確定的最後一件事是網路的名稱,我們將其命名為flannel2。

現在,我們終於可以使用輔助網路生成第一個pod。

現在應該使用輔助網路建立新的Pod,並且我們將那些附加網路視為額外新增的網路介面。

成功啦,輔助網路分配10.5.22.4作為其IP地址。

Troubleshooting

如果該示例沒有正常工作,你需要檢視kubelet的日誌。

一個常見的問題的是缺少CNI。我第一次測試的時候,遺漏了CNI網橋,因為RKE沒有部署它。但是這個問題十分容易解決。

外部連線和負載均衡

現在我們已經建立並執行網路,接下來我們要做的是使我們的應用程式可以訪問並將其配置為高可用和可擴充套件。高可用性和可伸縮性不僅可以通過負載均衡來實現,它還我們需要具備的關鍵元件。

Kubernetes有四個概念,可以使應用程式在外部可用。

使用負載均衡器

Ingress

Ingress基本上就是具有Layer7功能的負載均衡器,特別是HTTP(s)。最常用的ingress controller是NGINX ingress。但這主要取決於你的需求以及你的使用場景。例如,你還可以選擇traefik或HA Proxy。

配置一個ingress十分簡單。在以下例子中,你將瞭解一個連結服務的例子。藍色標註的是指向服務的基本配置。綠色標註的是連結SSL證書所需的配置(需要在此之前安裝這一證書)。最後,你會看到調整了NGINX ingress的一些詳細設定。

Layer 4 負載均衡器

在Kubernetes中,使用type: LoadBalancer定義Layer 4 負載均衡器,這是一個依賴於負載均衡解決方案的服務提供程式。對於本地計算機,大概率會使用HA代理或一個路由解決方案。雲提供商會使用自己的解決方案以及專用硬體,也可以使用HA代理或路由解決方案。

最大的區別是第4層負載平衡器不瞭解高階應用程式協議(layer 7),並且僅能夠轉發流量。此級別上的大多數負載均衡器還支援SSL終止。這通常需要通過註釋進行配置,並且尚未標準化。

使用 {host,node} 埠

{host,node} Port基本上等同於docker -p port:port,尤其是hostPort。與hostPort不同,nodePort在所有節點上可用,而不是僅在執行pod的節點上可用。對於nodePort,Kubernetes首先建立一個clusterIP,然後通過該埠負載均衡流量。nodePort本身只是將埠上的流量轉發到clusterIP的iptable規則。

除了快速測試外,很少使用nodePort,只有在你希望每個節點公開埠(即用於監視)時才會在生產中使用nodePort。大多數時候,你需要使用Layer 4負載均衡器。hostPort僅用於測試,或者少數時候,將pod貼上到特定節點並在指向該節點的特定IP地址下發布。

例如,在容器規範中定義了hostPort,如下所示:

什麼是ClusterIP ?

clusterIP是Kubernetes叢集及其中所有服務的內部可訪問IP。該IP本身將負載均衡流量到與其selector規則匹配的所有Pod。在很多情況下,例如在指定型別:LoadBalancer服務或設定nodePort時,也會自動生成clusterIP。其背後的原因是所有負載均衡都是通過clusterIP進行的。

clusterIP作為一個概念是為了解決多個可定址主機以及這些主機的有效更新的問題。具有不變的單個IP比始終通過服務發現針對服務的所有性質重新獲取資料要容易得多。儘管有時在某些情況下更適合使用服務發現,但如果你想要explicit control,那麼還是建議使用clusterIP,如在某些微服務環境中。

常見的故障

如果您使用公有云環境並手動設定主機,則您的叢集可能缺少防火牆規則。例如,在AWS中,您將需要調整安全組,以允許叢集間通訊以及ingress和egress。如果不這樣做,將導致叢集無法執行。確保始終開啟主節點和worker節點之間的必要埠。直接在主機上開啟的埠(即hostPort或nodePort)也是如此。

網路安全

既然我們已經設定了所有Kubernetes網路,我們還需要確保它們具備一定的安全性。保證安全性的最低原則是為應用程式提供其執行所需的最少訪問量。這可以在一定程度上確保即使在發生安全漏洞的情況下,攻擊者也將難以深入挖掘你的網路。雖然它不能完全確保你的安全,但無疑會使攻擊者進行攻擊時變得更加困難和耗時。這很重要,因為它會使你有更多的時間做出反應並防止進一步的破壞。這裡有一個典型的例子,不同應用程式的不同exploits/漏洞的組合,這使得攻擊者只有從多個維度(例如,網路、容器、主機)到達任何攻擊面的情況下,才能進行攻擊。

這裡的選擇要麼是利用網路策略,要麼是尋求第三方安全解決方案以實現容器網路安全。有了網路策略,我們有堅實的基礎來確保流量僅在流量應流的地方進行,但這僅適用於少數幾個CNI。例如,它們可與Calico和Kube-router一起使用。Flannel不支援它,但是幸運的是,你可以移至Canal,這使得Flannel可以使用Calico的網路策略功能。對於大多數其他CNI,則沒有支援,目前尚未有支援的計劃。

但這不是唯一的問題。問題在於,網路策略規則只是針對特定埠的防火牆規則,它十分簡單。這意味著你無法應用任何高階設定。例如,如果你發現某個容器可疑,就不能按需阻止它。進一步來說,網路規則無法理解流量,因此你不知道流量的流向,並且僅限於在第3層和第4層上建立規則。最後,它還無法檢測到基於網路的威脅或攻擊,例如DDoS,DNS,SQL注入以及即使在受信任的IP地址和埠上也可能發生的其他破壞性網路攻擊。

因此,我們需要專用的容器網路安全解決方案,它可為關鍵應用程式(例如財務或合規性驅動的應用程式)提供所需的安全性。我個人喜歡NeuVector。它具有我曾在Arvato / Bertelsmann進行部署的容器防火牆解決方案,並提供了我們所需的Layer7可見性和保護。

應該注意的是,任何網路安全解決方案都必須是雲原生的,並且可以自動擴充套件和調整。部署新應用程式或擴充套件Pod時,你無需檢查iptable規則或更新任何內容。也許對於幾個節點上的簡單應用程式堆疊,你可以手動進行管理,但是對於任何企業而言,部署安全不能減慢CI / CD流水線的速度。

除了安全性和可見性之外,我還發現擁有連線和資料包級容器網路工具有助於在測試和staging期間除錯應用程式。藉助Kubernetes網路,除非您能看到流量,否則您將永遠無法真正確定所有資料包的去向以及將哪些Pod路由到其中。

選擇網路CNI的一些建議

現在已經介紹了Kubernetes網路和CNI,始終會出現一個大問題:應該選擇哪種CNI解決方案?我將嘗試提供一些有關如何做出此決定的建議。

首先,定義問題

每個專案的第一件事是儘可能詳細地定義你需要首先解決的問題。你也許想知道要部署哪種應用程式以及它們將產生什麼樣的負載。你可能會問自己的一些問題:

我的應用程式:

  • 網路是否繁忙?

  • 是否對延遲敏感?

  • 是單體架構嗎?

  • 還是微服務架構服務?

  • 需要在多個網路上嗎?

我可以承受宕機時間嗎,甚至是最小的宕機時間?

這是一個十分重要的問題,因為你需要事先確定好。如果你現在選擇一種解決方案,以後再進行切換,則需要重新設定網路並重新部署所有容器。除非你已經擁有Multus之類的東西並且可以使用多個網路,否則這將意味著您的服務會停機。在大多數情況下,如果你有計劃的維護時段,那麼事情會沒那麼嚴重,但是隨著應用程式的不斷迭代,零停機時間變得更加重要!

我的應用程式在多個網路上

這一情況在本地安裝中十分常見,實際上,如果你只想將通過專用網路和公用網路的流量分開,那麼這需要你設定多個網路或者有智慧的路由。

我是否需要CNI中的某些特定功能?

影響你做決定的另一件事是,你需要一些特定的功能,在某些CNI中可用,而其他CNI中不可用。例如,你想使用Weave或希望通過ipvs進行更為成熟的負載均衡。

需要什麼網路效能?

如果你的應用程式對延遲敏感或網路繁忙,那麼你需要避免使用任何overlay網路。Overlay在效能上並不划算,規模上也是如此。這這種情況下,提高網路效能的唯一方法是避免overlay並改用路由之類的網路實用程式。尋找網路效能時,你有幾種選擇,例如:

  • Ipvlan:它有良好的效能,但需要注意,你不能在同一主機上同時使用macv{tap,lan}。

  • Calico:這個CNI不是對使用者最友好的,但於vxlan相比,它可以為你提供更好的效能,並且可以進行擴充套件而無需擔心。

  • Kube-Router:它通過使用BGP和路由,以及支援LVS/IPVS,來提供更好的效能(這與Calico類似)。但Calico比它更為成熟。

  • 雲提供商解決方案:一些雲提供商提供了自己的網路解決方案,這些方案的好壞需要根據具體情況來確定,這裡無法一概而論。值得一提的是,Rancher的一個開源專案Submariner。它支援多個Kubernetes叢集之間的跨叢集網路連線,並且建立了必要的隧道和路徑,能為部署在需要相互通訊的多個Kubernetes叢集中的微服務提供網路連線。

我只是想要一些可行的方法!

在這樣的情況下,推薦使用canal或帶有vxlan的flannel,因為它們十分容易且有效。但是正如我之前所提到的,vxlan速度很慢,隨著應用程式的不斷髮展,它將耗費大量資源。但是對於剛剛起步的專案而言,這絕對是最簡單的方法。

做出決定

這實際上是做出決定而不是根本不做出決定的問題。如果你沒有特定的功能要求,則可以從Flannel和vxlan開始。如果您已部署到生產環境,稍後需要一些工作以進行遷移,但是從長遠來看,做出錯誤的決定總比完全不做出決定要好。

有了所有這些資訊,我希望您對Kubernetes網路的工作方式有一些相關的背景和更好的瞭解。

原文連結:

https://dzone.com/articles/how-to-understand-and-setup-kubernetes-networking