Porter:面向裸金屬環境的 Kubernetes 開源負載均衡器
- 2019 年 10 月 7 日
- 筆記
我們知道,在 Kubernetes 集群中可以使用 「LoadBalancer」 類型的服務將後端工作負載暴露在外部。雲廠商通常為 Kubernetes 提供雲上的 LB 插件,但這需要將集群部署在特定 IaaS 平台上。然而,許多企業用戶通常都將 Kubernetes 集群部署在裸機上,尤其是用於生產環境時。而且對於本地裸機集群,Kubernetes 不提供 LB 實施。Porter 是一個專為裸金屬 Kubernetes 集群環境而設計的開源的負載均衡器項目,可完美地解決此類問題。
1 Kubernetes 服務介紹
在 Kubernetes 集群中,網路是非常基礎也非常重要的一部分。對於大規模的節點和容器來說,要保證網路的連通性、網路轉發的高效,同時能做的 IP 和 Port 自動化分配和管理,並提供給用戶非常直觀和簡單的方式來訪問需要的應用,這是非常複雜且細緻的設計。
Kubernetes 本身在這方面下了很大的功夫,它通過 CNI、Service、DNS、Ingress 等一系列概念,解決了服務發現、負載均衡的問題,也大大簡化了用戶的使用和配置。
其中的 Service 是 Kubernetes 微服務的基礎,Kubernetes 是通過 kube-proxy 這個組件來實現服務的。kube-proxy 運行在每個節點上,監聽 API Server 中服務對象的變化,通過管理 iptables 來實現網路的轉發。用戶可以創建多種形式的 Service,比如基於 Label Selector 、Headless 或者 ExternalName 的 Service,kube-proxy 會為 Service 創建一個虛擬的 IP(即 Cluster IP),用於集群內部訪問服務。
2
暴露服務的三種方式
如果需要從集群外部訪問服務,即將服務暴露給用戶使用,Kubernetes Service 本身提供了兩種方式,一種是 NodePort,另外一種是 LoadBalancer。另外 Ingress 也是一種常用的暴露服務的方式。
NodePort
如果將服務的類型設置為 NodePort,kube-proxy 就會為這個服務申請一個 30000 以上的埠號(默認情況下),然後在集群所有主機上配置 IPtables 規則,這樣用戶就能通過集群中的任意節點加上這個分配的埠號訪問服務了,如下圖
NodePort 是最方便的暴露服務的方式,缺點也很明顯:
- 基於 SNAT 進行訪問,Pod 無法看到真正的 IP。
- NodePort 是將集群中的一個主機作為跳板訪問後端服務,所有的流量都會經過跳板機,很容易造成性能瓶頸和單點故障,難以用於生產環境。
- NodePort 埠號一般都是用大埠,不容易記憶。
NodePort 設計之初就不是用於生產環境暴露服務的方式,所以默認埠都是一些大埠。
LoadBalancer
LoadBalancer 是 Kubernetes 提倡的將服務暴露給外部的一種方式。但是這種方式需要藉助於雲廠商提供的負載均衡器才能實現,這也要求了 Kubernetes 集群必須在雲廠商上部署。LoadBalancer 的原理如下:
LoadBalancer 通過雲廠商的 LB 插件實現,LB 插件基於 Kubernetes.io/cloud-provider 這個包實現,這個包會自動選擇合適的後端暴露給 LB 插件,然後 LB 插件由此創建對應的負載均衡器,網路流量在雲服務端就會被分流,就能夠避免 NodePort 方式的單點故障和性能瓶頸。
LoadBalancer 是 Kubernetes 設計的對外暴露服務的推薦方式,但是這種方式僅僅限於雲廠商提供的 Kubernetes 服務上,對於物理部署或者非雲環境下部署的 Kubernetes 集群,這一機制就存在局限性而無法使用。
Ingress
Ingress 並不是 Kubernetes 服務本身提供的暴露方式,而是藉助於軟體實現的同時暴露多個服務的一種類似路由器的插件。Ingress 通過域名來區分不同服務,並且通過 annotation 的方式控制服務對外暴露的方式。其原理如下圖:
相比於 NodePort 和 LoadBalancer,Ingress 在企業業務場景中應該是使用的最多的,原因有:
- 相比 kube-proxy 的負載均衡,Ingress controller 能夠實現更多的功能,諸如流量控制,安全策略等。
- 基於域名區分服務,更加直觀。也不需要用到 NodePort 中的大埠號。
但是在實際場景中,Ingress 也需要解決下面的一些問題:
- Ingress 多用於 L7,對於 L4 的支援不多。
- 所有的流量都會經過 Ingress Controller,需要一個 LB 將 Ingress Controller 暴露出去。
第一個問題,Ingress 也可以用於 L4,但是對於 L4 的應用,Ingress 配置過於複雜,最好的實現就是直接用 LB 暴露出去。
第二個問題,測試環境可以用 NodePort 將 Ingress Controller 暴露出去或者直接 hostnetwork,但也不可避免有單點故障和性能瓶頸,也無法很好的使用 Ingress-controller 的 HA 特性。
3
Porter 介紹
Porter 是 KubeSphere 團隊研發的一款開源的基於 BGP 協議的雲原生負載均衡器插件。它的主要特性有:
- 基於路由器 ECMP 的負載均衡
- 基於 BGP 路由動態配置
- VIP 管理
Porter 的所有程式碼和文檔已在 GitHub 開源 ,歡迎大家關注(Star)和使用。
掃碼查看 Porter 項目
4
如何快速部署使用
Porter 目前已在如下兩種環境下進行過部署和測試,並將部署測試與使用步驟的詳細文檔記錄在 GitHub,大家可以通過以下二維碼或鏈接查看,建議大家在分享後動手部署實踐一下。
- 在物理部署的 Kubernetes 集群上部署使用 Porter (https://github.com/kubesphere/porter/blob/master/doc/deploy_baremetal.md)
- 在青雲 QingCloud 雲平台用模擬路由器的方式測試(https://github.com/kubesphere/porter/blob/master/doc/simulate_with_bird.md)
5 原理
ECMP
ECMP(Equal-Cost Multi-Pathing,等價路由)即存在多條到達同一個目的地址的相同開銷的路徑。當設備支援等價路由時,發往該目的 IP 或者目的網段的三層轉發流量就可以通過不同的路徑分擔,實現網路的負載均衡,並在其中某些路徑出現故障時,由其它路徑代替完成轉發處理,實現路由冗餘備份功能。如下圖:
藉助於路由器(虛擬路由器),對於某一個IP(對應服務的VIP),ECMP能根據一定的Hash演算法從已知的路由中來選擇下一跳(Pod),從而實現負載均衡的目的。一般的路由器(虛擬路由器)都具備 ECMP 的能力,Porter 要做的就是查詢 Kubernetes API Server,將一個服務對應的後端 Pod 資訊通過路由的方式發送給路由器。
BGP
在 Kubernetes 中,Pod 可能會漂移,對於路由器來說,一個服務 VIP 的下一跳是不固定的,等價路由的資訊會經常更新。實際上我們參考 Calico,使用了 BGP(Border Gateway Protocol,邊界網關協議)實現路由的廣播。
BGP 是互聯網上一個核心的去中心化自治路由協議,在互聯網領域用的比較多。BGP 不同於其他路由協議,BGP 使用了 L4 來保證路由資訊的安全更新。同時由於 BGP 的去中心化特性,很容易搭建一個高可用路由層,保證網路的持續性。
上圖簡單描述了 Porter 中 BGP 的實現原理。圖中左下是一個兩節點的 Kubernetes 集群,集群上方是有兩個路由器 leaf1 和 leaf2,leaf 連接了核心交換機層 spine,也同樣是兩個。
最右側是用戶,對應的路由器是 border,border 也連接了 spine,用戶和 Kubernetes 伺服器三層是可達的。Kubernetes 集群中創建了 Service,並且使用了 Porter,Porter 為其分配了一個 1.1.1.1 的 vip(或者手工指定),Porter 通過 BGP 告知 leaf1 和 leaf2,訪問 1.1.1.1 的下一跳可以是 node1,也可以是 node2。
leaf 一層也會將這個資訊告知 spine,spine 的 BGP 經過計算得知訪問 1.1.1.1 的下一跳是 leaf1,leaf2。按照同樣的邏輯,這個路由也會更新到 border,這樣用戶訪問 1.1.1.1 的完整路徑就有了。同時,由於這個圖中每一層都有 HA,所以外界訪問 1.1.1.1 的路徑就有 2*2*2*2=16 條,流量能夠在整個網路中被分流,並且任意一層一個路由器宕機都不會影響用戶的訪問。
6
架構
Porter 有兩個組件,一個核心控制器和一個部署在所有節點上的 agent。核心控制器主要功能有:
- 監控集群中的 Service 以及對應的 endpoints,獲取pod 漂移資訊
- VIP 存儲與分配
- 與外界建立 BGP協議,廣播路由
上圖展示了 Porter 核心控制器的工作原理。
agent 則是一個輕量級組件,用於監控 VIP 資源,增加 Iptables 規則讓外部流量能夠訪問 VIP,默認情況下外部流量訪問 VIP 會被內核中的 Forward 表 Drop掉。
7
面向雲原生的設計
Porter 中的所有資源都是 CRD,包括 VIP、BGPPeer、BGPConfig 等。對於習慣 kubectl 的用戶使用 Porter 將非常友好。對於想訂製 Porter 的高級用戶,也可以直接調用 Kubernetes API 來二次開發。Porter 的核心控制器很快就會支援 HA,保證 Porter 的高可用性。
8
使用注意事項
用戶訪問 VIP 的流量會通過 BGP 到達 Kubernetes 集群中的某一個節點,因為 Porter 廣播路由的路也是 node 而不是具體的 podip,podip 外部不可訪問,後續 node 到 pod 的路由是由 kube-proxy 維護的。如下圖:
流量被 SNAT 之後隨機發送給某一個 pod。由於 Porter 會根據 Service Endpoints 的變化動態調整路由,確保下一跳的 node 節點一定有 pod 存在,所以我們可以更改 kube-proxy 這一個默認行為。在 Service 上設置 ExternalTrafficPolicy=local,達到下面的效果:
這樣做有兩個好處:
- SourceIP 不會 NAT
- 流量直接走本地,網路路徑少一跳
9
未來計劃
- 支援其他簡單路由協議
- 更加方便的 VIP 管理
- BGP 的 policy 支援
- 在 Kubesphere 集成,提供 UI
10
補充
Porter 支援部署在任何 Kubernetes 集群,可作為 Kubernetes 生產環境的標準負載均衡器方案。Porter 作為 KubeSphere 的子項目,KubeSphere 是一個開源的以應用為中心的容器管理平台,支援部署在現有 Kubernetes 和任何基礎設施之上,能夠更好的管理 Kubernetes 集群與雲原生應用,歡迎掃描二維碼或點擊閱讀原文了解。
● Kubernetes Dashboard 終結者:KubeSphere
● Istio 1.3 發布,HTTP 遙測不再需要 Mixer