深刻容器之構建大型容器網絡

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

背景介紹

構建一個大型混合雲容器網絡,首先須要考慮的是性能問題,還有容器網絡架構是否是通過大規模驗證,雲廠商是否是有相似方案的選擇,如何設計一個能支撐 5K 節點的容器網絡呢?其實通過大規模驗證的容器網絡組件屈指可數,其中大名鼎鼎的 cilium 公開數據顯示支持過單集羣 5k node 規模,各大雲廠商齊頭並進支持 cilium ebpf。編程

本文將包括以下幾部分:緩存

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

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

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

一、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 地址

幾種經典容器網絡模式dom

隧道封包模式: VxLan/IPIP/GRE ,經過tunnel隧道封包創建overlay 網絡,實現Pod到Pod的通訊。
vxlan.pngide

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

二、Kubernetes Service 網絡概覽

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

須要思考的問題

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

下圖顯示了 Service 負載均衡的不一樣實現性能對比(數據來源於阿里雲容器團隊)

2.一、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.二、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.一、VxLAN 隧道模式

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

VxLAN 報文:

因爲 VxLAN 報文包體較大,封解包過程性能折損較大。適合須要突破 vlan 4096 規模限制的超大規模數據中心而且 VxLAN 有必定性能優化能力。顯然大部分業務場景並無這種超大規模的擴展性需求,而性能在大多數場景下顯得相當重要,須要尋求其餘輕量級方案。

3.二、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.三、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.四、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