從美圖容器優化實踐談Kubernetes網絡方案設計

李連榮,美圖高級系統研發工程師,曾建立支持千萬的長連接服務,從零開始在建立美圖的容器化服務,並主導完成美圖容器化的網絡方案。在網絡、存儲方面有非常深厚的造詣。

目前,我們的 Kubernetes 集群選擇使用 Calico 作為基礎網絡方案。

選擇 Calico 網絡方案的挑戰

Calico 是一套基於路由(BGP)的 SDN,它通過路由轉發的方式實現容器的跨主機通信。Calico 將每個節點虛擬為一個“路由器”併為之分配獨立的虛擬網段,該路由器為當前節點上的容器提供路由服務。

更多 Calico 項目介紹可參閱 https://www.projectcalico.org/ 下面以具體網絡為例介紹其中的設計與難點。

从美图容器优化实践谈Kubernetes网络方案设计

以上圖為例,如果節點 192.168.1.2 分配的虛擬網段是 10.233.1.0/24,其上運行了一個容器 10.233.1.2,其路由信息如下:

10.233.1.2 0.0.0.0 255.255.255.255 UH 0 0 0 cali814214d5913

當物理機收到目標地址為10.233.1.2 的IP 數據包時會轉發到網口 cali814214d5913,而 cali814214d5913 是通過 veth-pair 創建的網卡,它與本機上 IP 地址為 10.233.1.2 的容器互通,因此,IP 地址為 10.233.1.2 容器就可以收到相應的 IP 數據包。

當位於節點 192.168.1.3 上的容器 10.233.2.2 給 10.233.1.2 發送 IP 數據包時,需要知道 10.233.1.2 所在的物理節點的 IP,並添加以下路由規則:

10.233.1.0/16 192.168.1.2 eth0

Calico 通過 BGP 實現節點間相互學習路由規則。節點 192.168.1.2與節點192.168.1.3 建立 BGP 鄰居,節點 192.168.1.3 可以通過 BGP 學習到上面的路由規則。當容器 10.233.2.2 發送 IP 數據包給 10.233.1.2 時,會根據上面的路由規則轉發到節點 192.168.1.2,並由節點 192.168.12 轉發給 10.233.1.2,進而實現容器的跨主機通信。

但是當兩個容器所在的節點處於不同的子網時,如10.233.3.2,其所在的節點192.168.2.2與節點192.168.1.2處於不同的子網,此時無法在192.168.2.2上添加以下路由:

10.233.1.0/16 192.168.1.2 eth0

這是因為物理機 192.168.2.2與物理機 192.168.1.2 鏈路層不通。為了解決這個問題,Calico 選擇了 IPIP。IPIP 是將虛擬網絡的 IP 數據包封裝到物理網絡的 IP 數據包裡傳輸。啟用 IPIP 後,節點上會出現相應的虛擬網卡,通常是 tunl0,節點1 92.168.2.2 可以添加以下路由規則:

10.233.1.0/16 192.168.1.2 tunl0

與之前的路由的區別在網口換成了 tunl0。當 10.233.3.2 發送 IP 數據包給10.233.1.2 時,其所在的節點會將 IP 數據包轉發到網口 tunl0,轉發到 tunl0 的 IP 數據包會被 IPIP 驅動接管。IPIP 驅動會將每個 IP 數據包封裝到物理網絡的 IP 數據包內(目標地址是下一跳地址,即 192.168.1.2,Payload 是虛擬機發出的原始 IP 數據包)發送出去。

由於該 IP 數據包的目標地址是節點 192.168.1.2,因此,可以經過物理網關進行轉發。運行在節點 192.168.1.2 上 IPIP 服務接收到該物理網絡 IP 數據包後將其 Payload 取出,再根據節點 192.168.1.2 上路由規則轉發給相應的容器,進而實現了容器的跨子網通信。

Calico 網絡方案存在的問題

通過 Calico 的工作原理可以看出,Calico 存在以下問題:

  • 使用 IPIP 時,需要嵌套 IP 協議,多餘的打包和拆包動作會帶來的性能開銷。

  • 使用 IPIP 時,嵌套的 IP 協議頭導致實際有效的 MTU 長度變小,也會影響實際的帶寬利用率。

  • 由於集群外的節點無法學習集群內的路由信息,故無法直接訪問集群內的容器。

根據 Calico 的工作原理可知,Calico 為了解決容器的跨子網通信選擇了 IPIP,也正是因為引入了 IPIP 才引發了一系列的性能問題,那麼,為什麼 Calico 會選擇 IPIP 協議呢?

為了理解這個問題,我們先看一下傳統的物理網絡是如何解決跨子網通信的。仍以上圖為例,物理機 192.168.2.3 訪問物理機 192.168.1.2 的步驟如下:

  • 物理機 192.168.2.3 檢測到目標 IP 與自己處於不同的子網,因此,通過默認路由規則發送給其所在網關 192.168.2.1。

  • 物理網關 192.168.2.1 通過路由協議可以知道網關 192.168.2.1 可以轉發 IP 包給物理 192.168.1.2,因此,將相應的 IP 包轉發給網關 192.168.1.1。

  • 物理網關 192.168.1.1 再將 IP 包轉發給物理機 192.168.1.2。


我們再來看一下 Calico 網絡。如果沒有 IPIP,容器 10.233.4.2 訪問容器 10.233.1.2 的步驟如下:

  • 宿主機 192.168.2.3 檢測到目標 IP 與自己處於不同的子網,因此,會將目標地址為 10.233.1.2 的 IP 包轉發給其所在網關 192.168.2.1。

  • 網關 192.168.2.1 沒有匹配的路由規則,因此 drop 該 IP 包並會返回目標不可達。

如果引入 IPIP,容器 10.233.4.2 訪問容器 10.233.1.2 的步驟如下:

  • 宿主機 192.168.2.3 匹配到路由規則 “10.233.1.0/16 192.168.1.2 tunl0”。

  • 宿主機 192.168.2.3 將該容器發出的 IP 包通過 tunl0 端口轉發到物理機192.168.1.2。

  • IPIP 驅動將容器發出的 IP 包(目標地址 10.233.1.2)作為物理網絡 IP 包(目標地址 192.168.1.2)的 Payload 發出。

  • 宿主機 192.168.2.3 按照物理網絡的傳輸方式將物理網絡 IP 包發送到宿主機 192.168.1.2。

  • 宿主機 192.168.1.2 上 IPIP 驅動接收到該 IP 包之後解包並將該 Payload 作為 IP 包轉發給容器 10.233.1.2。

因此,在物理網關不能為虛擬網絡提供路由服務的前提下,Calico 選擇使用 IPIP 的方式來解決容器的跨子網通信。

如果通過某種方法,讓物理網關能夠學習到 Calico 虛擬網絡的路由規則,那麼物理網關就可以為虛擬網絡提供路由服務,Calico 就可以在不引入 IPIP 的前提下實現容器的跨子網通信,但是,Calico 為什麼沒有選擇這種方式呢?

這是因為 Calico 的主要應用場景是公有云,公有云具備以下特性:

  • 多數公有云廠商可以提供一個穩定的大二層環境,其內的主機可以工作在同一個子網段,也就不存在跨子網通信的問題

  • 不是所有的公有云廠商都可以提供 BGP 路由學習的接口,如果雲廠商不提供 BGP 接口,Calico 就無法同步虛擬網絡路由規則給公有云

因此,在這個前提下,Calico 選擇 IPIP 方式是非常合理的。

對於私有云場景:

  • 不是所有的私有云環境都支持大二層,對 Calico 跨子網通信的需求是非常強烈的。

  • 所有硬件(包括網關)都在可控範圍內,只要物理網關支持 BGP 協議,Calico 就可以同步路由規則給物理網關。

因此,對於私有云場景,通過讓 Calico 同步虛擬網絡路由規則給物理網關的方式來解決跨子網通信會是更好的選擇。

性能提升方案

其實 Calico 的文檔中提到了一種同步路由規則給物理網關的方式,具體可以參考如下鏈接:

https://docs.projectcalico.org/v2.6/usage/external-connectivity

本文參考這種設計,將虛擬網絡路由規則同步給物理網關,虛擬網絡與物理網絡建立 BGP 鄰居的方式有兩種:

  • 方案一:各節點分別物理網關建立 BGP 鄰居

  • 方案二:中心化組件與物理網關建立 BGP 鄰居

下面針對兩種方案進行分析。

方案一

如下圖所示,方案一需要每個 SDN 節點分別與其所在的物理網關建立 BGP 鄰居。由於每個 SDN 節點作為本機容器的網關,如果運行在該物理機上 Calico 服務能夠與物理網關建立 BGP,並將自己的路由規則同步給物理網關,那麼,物理網關就可以學習虛擬網絡的路由規則。

从美图容器优化实践谈Kubernetes网络方案设计

運行在節點上的 SDN 服務可以通過編碼或者腳本實現自動建立 BGP 鄰居的邏輯,但是,這也需要物理網關的支持。如果物理網關不支持自動建立 BGP 鄰居,僅僅是在 SDN 端實現是沒有意義的。

傳統的 BGP 路由器需要逐個配置 BGP 鄰居,這對容器化集群來說是不可接受到。因為容器化集群的規模一般都比較大,在集群使用過程中也會經常的調整節點,如擴容、縮容、機器故障等。如果每次調整節點都需要運維手動完成 BGP 鄰居的配置,運維成本是巨大的,而且容易因誤操作而影響集群穩定性,因此,需要網關支持自動建立 BGP 鄰居。

要實現自動建立 BGP 鄰居需要使用支持 Dynamic Neighbors 功能的路由器。傳統的路由器在配置 BGP 鄰居時需要指定明確的 IP 地址,而支持 Dynamic Neighbors 的路由器可以指定一個 IP 網段,該路由器可以自動接受指定網段內BGP設備發起的建立鄰居的請求。

集群部署前先配置好路由器的 Dynamic Neighbors,調整集群節點時運行在節點上的 SDN 服務主動與之建立 BGP 鄰居,並將其所在節點的路由信息同步給物理網關。例如,運行在物理機 192.168.1.2 上的 SDN 服務自動與物理網關 192.168.1.1 建立 BGP 鄰居(eBGP)並將以下路由規則同步給物理網關:

10.233.1.0/24 192.168.1.2 eth0 

物理網關 192.168.1.1 學習到以上規則之後會通過 BGP 或者其它路由同步協議同步給物理網關 192.168.2.1,通過這種方式,整個物理網絡都可以學習上以上規則。集群的容器要發送數據到 10.233.1.0/24 網段時,直接通過其宿主機將數據包發送給物理網關,物理網關即可根據其學到的虛擬網絡路由信息轉發到目標主機,最後,再由目標主機轉發給相應的容器。

方案二

方案二需要引入中心化組件,本文稱之為 BGP Speaker,其網絡結構如下:

从美图容器优化实践谈Kubernetes网络方案设计

BGP Speaker 運行在 SDN 集群內,它負責收集 SDN 集群內的路由信息並通過BGP 同步給物理網關。由於該模塊可以收集 SDN 集群內的全部路由信息,故不再需要每個 SDN 節點單獨與物理網關建立 BGP 鄰居,也就不再依賴物理網關的的 Dynamic Neighbors 功能。

如下圖所示,BGP Speaker 主要分為兩部分:observer 和 publisher。

  • observer:負責收集 SDN 集群的路由信息。

  • publisher:將 observer 收集到的路由信息同步給物理網關。

从美图容器优化实践谈Kubernetes网络方案设计

Calico 將 SDN 集群相關的信息(包括配置信息、每個節點的虛擬網段等)保存在 etcd 裡,而 etcd 的支持 watch,因此,observer 可以通過watch方式實時獲取 Calico 集群的節點信息。observer 主要關注每個 SDN 節點劃分的虛擬網段信息,並根據獲取到的虛擬網段信息生成對應的路由規則,如節點 192.168.1.2 劃分的虛擬網段是 10.233.1.0/24,observer 會生成以下路由規則:

10.233.1.0/24 192.168.1.2 eth0

publisher 實現了 BGP 協議,它與物理網關建立 BGP 鄰居(eBGP),主要工作是將 observer 收集到的路由信息同步給物理網關。由於 publisher 需要將不同節點的路由信息同步給物理網關,因此,publisher 對物理網關來講,實際上是個 BGP Route Reflector。

gobgp 提供了開源的 BGP 協議庫,支持完整的 BGP 協議,可以作為 publisher的基礎庫。另外,BGP 是雙向的,publisher 不僅可以將自己持有的路由信息同步給物理路由器,物理路由器也會同步路由信息給 publisher,由於 SDN 不需要了解物理網絡的路由信息,因此,publisher 可以過濾掉這些路由信息。

由於 BGP Speaker 是中心化部署的,因此 BGP Spaker 的高可用程度會直接影響 SDN 集群的穩定性。BGP Speaker 直接從 SDN 集群的 etcd 存儲中獲取集群信息,其自身不需要保存任何數據(包括生成的路由信息),故 BGP Speaker是無狀態的,因此,只需要在 SDN 集群內部署多套 BGP Speaker 即可實現高可用。

多套 BGP Speaker 之間相互不感知,各自獨立運行。部署 BGP Speaker時,還可以根據物理網絡的拓撲結構將 BGP Speaker 部署在不同的機架或者機房,保證某個機架或機房出現故障時 SDN 集群仍可正常工作。

安全隱患

以上兩種方案都可以實現物理網絡與虛擬網絡的互通,但兩種方案都是虛擬網絡通過 BGP 協議自動的同步路由規則給物理網關,如果虛擬網絡產生了錯誤的路由規則或者產生的路由規則與物理網絡衝突,就會影響集群所處物理網絡的運行狀態;如果同一物理網絡內部署了多套 SDN 集群且這多套 SDN 的網段有衝突時,也會造成虛擬網絡的路由規則紊亂,影響 SDN 的穩定性。

因此,還需要採取一些措施來保證 SDN 之間以及 SDN 與物理網絡之間不衝突。

確保 SDN 與物理網絡不衝突

現在的物理網關大多都支持路由過濾,也就是說當網關通過 BGP 學習到新的路由規則時,可以根據一定的規則進行過濾,只有滿足要求的路由規則,才會同步到自己的路由表。部署容器化集群時,應先規劃好 SDN 的網絡地址,要保證 SDN 的網絡地址與物理網絡不衝突。

配置物理網關時,可以通過設置過濾規則來保證 SDN 不能修改其所屬網段以外的任何任何路由規則(例如,限制 SDN 只能更新目標地址處於 10.233.0.0/16 網段內的路由規則),通過這種方式,可以確保 SDN 不會影響物理網絡穩定性。

確保 SDN 之間不衝突

物理網絡與虛擬網絡互通後,部署在同一個物理網絡內的多個 SDN 集群的路由信息都會同步到物理網關,如果不同 SDN 的網絡地址有重疊,就會引發衝突,導致 SDN 網絡無法穩定工作,因此,在部署 SDN 集群時,還需要為不同的 SDN 集群分配不同的網絡地址(這些地址都與物理網絡不衝突)。配置網關時,限制每個 SDN 只能同步處於自己網絡地址內的路由規則。

總結

Calico 存在性能問題的根本原因是物理網絡與虛擬網絡不互通,本文設計了兩種方案實現物理網絡與虛擬網絡的互通,解決了 Calico 引入 IPIP 和 NAT 帶來的性能問題,也帶來了一定的安全隱患,但是,可以通過額外的保障措施排除安全隱患,保證物理網絡與 SDN 網絡的穩定運行。


分享到:


相關文章: