深入容器之構建大型容器網路

語言: CN / TW / HK

好未來技術 團隊出品, 專注於容器底層基礎設施建設

背景介紹

構建一個大型混合雲容器網路,首先需要考慮的是效能問題,還有容器網路架構是不是經過大規模驗證,雲廠商是不是有類似方案的選擇,如何設計一個能支撐 5K 節點的容器網路呢?其實經過大規模驗證的容器網路元件屈指可數,其中大名鼎鼎的 cilium 公開資料顯示支援過單叢集 5k node 規模,各大雲廠商齊頭並進支援 cilium ebpf。

本文將包括如下幾部分:

  • Kubernetes Pod 網路概覽
  • Kubernetes Service 網路概覽
  • 構建一個大型容器網路

閱讀本文你將瞭解到我司容器網路的進化路線,從容器小叢集成長為大叢集的新一代容器網路架構;您還將發現老容器叢集潛在的網路架構缺陷,除舊迎新恆久不變,一代更比一代強。

『深入容器』系列文章第一篇,請收藏與關注系列文章,歡迎加入我們。

1、Kubernetes Pod 網路概覽

在使用 Kubernetes 編排應用時,您必須改變對應用和其主機的網路的思維方式。使用 Kubernetes 時,您需要考慮的是 Pod、Service 和外部客戶端的通訊方式,而不是主機或虛擬機器的連線方式。
Kubernetes 的高階軟體定義網路 (SDN) 支援在同一區域級叢集中的不同地區之間路由和轉發 Pod、Service、Node 的資料包。

IP 地址相關的術語
Kubernetes 網路模型在很大程度上依賴於 IP 地址。Service、Pod、容器和 Node 使用 IP 地址和埠進行通訊。Kubernetes 提供不同型別的負載均衡,用於將流量定向到正確的 Pod。

相關術語:

  • ClusterIP:分配給 Service 的 IP 地址,此地址會在 Service 的生命週期內保持不變
  • Pod IP:分配給 Pod 的 IP 地址,大部分情況生命週期隨 Pod 的銷燬而終止
  • Node IP:分配給節點的 IP 地址

幾種經典容器網路模式

隧道封包模式: VxLan/IPIP/GRE ,通過tunnel隧道封包建立overlay 網路,實現Pod到Pod的通訊。
vxlan.png

路由模式:通過對映目標容器網段和主機IP的關係,Pod 之間的通訊資料包通過路由錶轉發到相應節點上。
route.png

2、Kubernetes Service 網路概覽

Kubernetes 的 Service 到底是個啥 ?其實 Kubernetes 的 Service 主要解決的是 Pod IP 短生命週期帶來的問題,Service clutserIP 就是 node side Loadbalancer。

需要思考的問題

  • 當一個應用擁有多個 Pod 時如何去做負載均衡
  • 會話保持如何去處理
  • 某個容器銷燬後短生命週期的 IP 變更如何去處理

下圖顯示了 Service 負載均衡的不同實現效能對比(資料來源於阿里雲容器團隊)

2.1、iptables 與 IPVS 的實現

iptables的實現

iptables 的 Serivce 實現誕生於 kubernetes 1.2 版本,iptables 和 -j DNAT 為 Service 提供負載均衡的規則。

iptables 規則更新的缺點:

  • 更新時延:規則更新是全量更新,缺乏增量,增加/刪除一條規則,需要整體修改 netfilter 規則表
  • 可擴充套件性:iptables 增加規則的時延,隨著規則數的增加呈指數級上升,同時因為全量提交的過程中做了保護會出現 kernel lock 問題
  • 可用性不足:服務擴容/縮容時,iptables 規則的重新整理會導致連線中斷,服務不可用。

iptables 的更新時延統計:

  • 5k service (40k 規則),每增加一條 iptables 規則需要 11min
  • 20k service (160k 規則),每增加一條 iptables 規則需要 5h

IPVS 的 Service 實現

顯然由於 iptabes 的缺點只能執行在小規模叢集下,2018 年華為容器團隊使用 IPVS 取代 iptables 實現大規模 Service 負載均衡,社群 GA 於 kubernetes 1.11 版本。IPVS 與 iptables 都是基於 netfilter 框架實現,規則儲存於 hash 表中,規則更新的時延不會隨著基數上升而不可用。

iptabes VS IPVS 規則增加時延(資料來源於華為容器團隊)

核心 conntrack 競態問題

kubeproxy 的 IPVS 模式,由於 IPVS 缺乏 SNAT 模組,利用 nf_conntrack/iptables 實現 SNAT,IPVS 使用 ipset 來儲存需要 DROP 或 masquared 的流量的源或目標地址。
iptables 依賴 netfilter 和 kernel conntrack 連線跟蹤模組,Linux 低版本核心在進行源網路地址轉換 (SNAT) 時存在已知的競態問題,這可能導致 SYN 資料包被丟棄。

規避建議

  • iptables 需要開啟 random-fully 選項埠隨機,緩解 SNAT 埠競爭情況
  • Pod 容器環境開啟 DNS single-request-open 選項禁用並行查詢
  • 由於常用容器映象 alpine 系統的 musl libc 限制,導致無法生效 single-request-open 禁用並行查詢,故不建議使用 alpine 系統

2.2、eBPF 的實現

近年來 BPF 以瘋狂的速度發展,應用範圍從核心效能分析擴充套件到了網路領域。 這是由於 BPF 提供了強大、高效的可程式設計性。
Linux 核心社群在 2018 年宣佈了 bpfilter ,它將取代 iptables 的長期核心實現,由 Linux BPF 提供支援的網路過濾,同時保證無中斷。

BPF 主要推動者:

  • Facebook 率先使用 BPF/XDP 代替 IPVS 實現負載均衡,Facebook 從 IPVS 遷移到 BPF 後效能提高了幾倍
  • 大名鼎鼎的 Brendan Gregg(《效能之鼎》作者),一直在利用 BPF 用於效能分析和跟蹤的能力
  • kubernetes 網路元件 Cilium 使用 BPF 實現容器網路與 Serivce 負載均衡,專案發起者為十年以上 Linux 網路模組維護者

早期的 bpfilter 與 iptables 的比較 (資料來源於 cilium 團隊)

用 Cilium/BPF 替換 kube-proxy
Cilium 裡基於 BPF 實現了一個連線跟蹤器,完全替換了 nf_conntrack。基於 BPF 的 SNAT 實現中,用一個 LRU BPF map 存放 Service 和 backend pods 的對映資訊。SNAT 會替換 src_ip和src_port,由於不同客戶端的 src_port 可能是相同的,如果只替換 src_ip,不同客戶端的應答包在反向轉換時就會失敗。因此這種情況下需要做 src_port 轉換。目前做法是先進行 hash,如果 hash 失敗則呼叫 prandom() 隨機選擇一個埠。

重複利用
通過過期 NAT entry 的快速重複利用(fast recycling)技術。如果一個連線斷開時,不會直接刪除對應的 entry,而是進行標記為過期;如果有新的連線剛好命中了這個 entry,會將其標記為正常,以達到重複利用這個 entry 的目的。

DSR 模式
之前跨宿主機轉發是 SNAT 模式,Cilium 1.8+ 開始支援 DSR 模式。DSR 的好處是 backend pods 直接將包回給客戶端,回包不再經過當前節點轉發。

3、構建大型容器網路

3.1、VxLAN 隧道模式

構建大型容器網路最經典的方式是用 VxLAN 方式構建大型 overlay 網路,從 Google 到阿里雲底層皆使用 VxLAN 方式構建資料中心網路,使用MAC in UDP的方法進行封裝,對端進行解封。
基於 VxLAN 的高度可擴充套件性,可以繞過物理網路進行大規模網路擴充套件,cilium 基於 bpf 實現了多雲 VxLAN 網路(clustermesh),簡單部署即可實現多雲互聯互通的容器網路。

VxLAN 報文:

由於 VxLAN 報文包體較大,封解包過程效能折損較大。適合需要突破 vlan 4096 規模限制的超大規模資料中心並且 VxLAN 有一定效能優化能力。顯然大部分業務場景並沒有這種超大規模的擴充套件性需求,而效能在大多數場景下顯得至關重要,需要尋求其他輕量級方案。

3.2、BGP Router 模式

Facebook 選擇了 BGP 用於構建大型資料中心,BGP 是 自治系統 間的路由協議,BGP 分為 eBGP 和 iBGP 自治系統間,邊界路由器之間使用 eBGP 廣播路由。邊界路由器通過 iBGP 將學習到的路由資訊匯入到內部網路,BGP 協議的其中一個缺點是收斂過程慢。

如果不考慮具體的 BGP 方案,很難討論容器網路的 bgp 配置。然而 BGP 方案設計超出的本文章的討論範圍。如果您對此主題感興趣,請參閱 BGP in the Data Center (O’Reilly,2017)。

下面將討論容器網路實施 bgp 路由模式的幾種通用方案,適用於從單叢集小規模節點到數箇中型叢集的網路互聯互通再到與物理網路 bgp 融合的逐步演進方案,可根據不同應用規模和場景選擇對應方案。

全網格 Full-mesh

Full-mesh (全網格) 對於小於 100 個節點的小型部署非常有效。Full-mesh 模式的代表 kuberouter 和 calico,把每個 node 都當成 router。啟用 BGP 時 Calico 的預設行為是建立一個完整的內部 BGP(iBGP)連線網格,其中每個節點彼此對等路由資訊,直接路由的方式效能相當不錯。

路由反射器 Route reflectors

在更大的規模下,Full-mesh 的效率會降低,所以建議使用 Route reflectors(路由反射器),來減少每個節點上使用的 BGP 對等體的數量。
在這個模型中,一些節點充當 Route reflectors(路由反射器),並被配置為在它們之間建立一個完整的網格。其他節點隨後被配置為對應 Route reflectors(路由反射器)的子集進行對等(通常為 2 個用於冗餘),與全網相比減少了 BGP 對等連線的總數。該模式適用於多個容器叢集的互聯互通,利用 bgp 路由協議構建 3 層容器網路。

RR 模式的注意事項:

  • BGP 只允許在任何 L2 網路上執行,RR 模式不可以與 VxLan 共用
  • 跨 VLAN 網路情況則需要配置 IPIP 隧道,有一定效能折損
  • 在大規模應用下,RR 所在節點將可能成為效能瓶頸點

頂架式 Top of Rack (ToR)

Cilium 的 BGP 頂架式方案,純物理網路,適用於約 2k nodes 單叢集規模。該模式需要與資料中心網路工程師進行大量測試,我們目前使用該方案推進容器網路升級。

三層分層體系結構

  • 節點通過第 2 層交換機連線到物理網路
  • 通過 bird 軟體向物理網路宣佈每個節點的 PodCIDR
  • 對於每個 node,不要從物理網路匯入路由宣告

在這個設計裡,BGP 連線如下所示:

注:這裡 node 上使用 host-local 的 IPAM 地址管理方式,每個節點分配個/24 子網的 PodCIDR

核心路由器從 bird 那裡學習 PodCIDR 的路由,Pod IP 地址就可以在整個網路中路由。bird 不向核心路由器學習路由資訊,這讓每個節點上路由表非常乾淨簡潔。每個節點只需向節點的預設閘道器(核心路由器)傳送 pod 出口流量,並讓核心路由器進行路由。

BGP 鄰居規模上限問題

  • 通過 bird 上報路由的方式,規模受限於物理網路裝置的 bgp 鄰居數量上限和 IP 地址分配策略
  • 也可通過 gobgp 開源庫, 開發 ibgp 路由上報程式,由上報程式向核心路由器統一上報所有的 PodCIDR,從而減少 ibgp 鄰居數量

3.3、IPVlan L2 直通模式

IPVlan L2 模式 和 macvlan 類似,都是從一個主機介面虛擬出多個虛擬網路介面。一個重要的區別就是所有的虛擬介面都有相同的 mac 地址和不同的 IP 地址,而macvlan則是不同的 IP 同時不同的 mac 地址。需要注意的是地方是IPVlan L2同網路子介面的生成的IP, mac 地址是一樣的。

Linux kernel 3.19 首次支援 IPVlan,各大廠商推薦使用的版本是 >= 4.19 核心程式碼目錄:/drivers/net/ipvlan/

IPVlan 網路的應用
阿里雲基於 cilium cni channing 的擴充套件能力(aws 也是使用該方式),使得阿里雲的容器網路外掛 terway 能和 cilium 整合從而支援 bpf。因為 IPVlan L2 模式具備獨立的網路 namespace,並不共享 host 的網路 namespace,利用 tc 將 Service 流量劫持重定向到 host 網路 namespace 下達到相容節點側的 Service 負載均衡的目的,有興趣的可以閱讀阿里雲的( Kubernetes網路的IPVlan方案 )。
IPVlan L2 模式資料路徑非常簡潔,Pod 網路通訊不從 host 網路 namespace 下通過,直通物理子網絡卡。由於網路堆疊不從節點的 iptables 或路由表通過,因此可以繞過 kubernets conntrack競爭 問題,令人頭疼的 DNS 超時問題大部分是由 conntrack 引起的。

(來源於阿里雲容器團隊)

TC 劫持重定向 Service 流量的命令

tc filter add dev $ENIA egress proto ip u32 \
    match ip dst $SERVICE_CIDR \
	action tunnel_key unset pipe \
	action tc_mirred ingress redirect dev ipvl_a0

由於阿里雲 terway 的方案使用的是 Cilium1.8 系列版本,未持續跟進升級 Cilium 版本,實現方式繫結阿里雲配套的網路產品,故目前只適合在阿里雲上時候。但該方案資料路徑簡潔,與 Cilium 相容的方式打通資料路徑,有較大的架構優勢,未來將向該方案靠攏。

3.4、NodeLocal DNS

NodeLocal DNSCache 通過在叢集節點上作為 DaemonSet 執行 dns 快取代理來提高叢集 DNS 效能。 叢集優先 DNS 模式的 Pod 可以連線到 CoreDNS 的 ClusterIP 進行 DNS 查詢。
通過 kube-proxy 新增的 iptables 規則將其轉換為 CoreDNS 端點。 藉助這種新架構,Pods 將可以訪問在同一節點上執行的 dns 快取代理,從而避免了 iptables DNAT 規則和連線跟蹤。

主要動機

  • 擁有本地快取將有助於改善延遲,降低 CoreDNS 服務的查詢數量
  • 跳過 iptables DNAT 和連線跟蹤將有助於減少 conntrack 競爭 並避免 UDP DNS 條目填滿 conntrack 表

localdns.png

值得注意的是 NodeLocal DNS 與 MacVlan、IPVlan L2 等獨立的網路 namespace 並不相容,上文有提到阿里雲使用 TC 劫持重定向 Service 流量達到相容目的。

參考附錄

  • (2017) BGP in the Data Center https://www.oreilly.com/library/view/bgp-in-the/9781491983416/
  • (2018) 華為雲在 K8S 大規模場景下的 Service 效能優化實踐 https://zhuanlan.zhihu.com/p/37230013
  • (2018) 為什麼核心使用 BPF 替換 iptables https://cilium.io/blog/2018/04/17/why-is-the-kernel-community-replacing-iptables
  • (2019) 利用 eBPF 支撐大規模 Kubernetes Service https://arthurchiao.art/blog/cilium-scale-k8s-service-with-bpf-zh
  • (2019) Kubernetes 網路的 IPVlan 方案 https://kernel.taobao.org/2019/11/ipvlan-for-kubernete-net/
  • (2020) 阿里雲如何在生產環境中構建高效能雲原生 Pod 網路 https://www.alibabacloud.com/blog/how-does-alibaba-cloud-build-high-performance-cloud-native-pod-networks-in-production-environments_596590
  • (2020) 騰訊雲繞過 conntrack,使用 eBPF 增強 IPVS 優化 K8s 網路效能 https://cloud.tencent.com/developer/article/1687922
分享到: