本地叢集使用 OpenELB 實現 Load Balancer 負載均衡
為了方便測試,準備為 Ingress 控制器配置一個 LoadBalaner 型別的 Service,由於我這是本地私有環境,所以需要部署一個支援該服務型別的負載均衡器,在社群中目前最流行的應該是 MetalLB 這個專案,現在也屬於 CNCF 沙箱專案,該專案在 2017 年底發起,經過 4 年的發展已經在社群被廣泛採用,但是我這邊在測試使用過程中一直表現不穩定,經常需要重啟控制器才能生效。所以將目光轉向了最近國內青雲開源的另外一個負載均衡器 OpenELB。
OpenELB 之前叫 PorterLB,是為物理機(Bare-metal)、邊緣(Edge)和私有化環境設計的負載均衡器外掛,可作為 Kubernetes、K3s、KubeSphere 的 LB 外掛對叢集外暴露 LoadBalancer 型別的服務,現階段是 CNCF 沙箱專案,核心功能包括:
- 基於 BGP 與 Layer 2 模式的負載均衡
- 基於路由器 ECMP 的負載均衡
- IP 地址池管理
- 使用 CRD 進行 BGP 配置
與 MetaLB 對比
OpenELB 作為後起之秀,採用了更加 Kubernetes-native 的實現方式,可以直接通過 CRD 進行配置管理,下面是關於 OpenELB 與 MetaLB 的簡單對比。
雲原生架構
在 OpenELB 中,不管是地址管理,還是 BGP 配置管理,你都可以使用 CRD 來配置。對於習慣了 Kubectl 的使用者而言, OpenELB 十分友好,在 MetalLB 中,需通過 ConfigMap 來配置,感知它們的狀態需要通過檢視監控或者日誌。
靈活的地址管理
OpenELB 通過 EIP 這個自定義資源物件來管理地址,它定義子資源 Status 來儲存地址分配狀態,這樣就不會存在分配地址時各副本發生衝突的情況。
使用 gobgp 釋出路由
不同於 MetalLB 自己實現 BGP 協議, OpenELB 採用標準的 gobgp 來發布路由,這樣做的好處如下:
- 開發成本低,且有 gobgp 社群支援
- 可以利用 gobgp 豐富特性
- 通過 BgpConf/BgpPeer CRD 動態配置 gobgp,使用者無需重啟 OpenELB 即可動態載入最新的配置資訊
- gobgp 作為 lib 使用時, 社群提供了基於 protobuf 的 API,OpenELB 在實現 BgpConf/BgpPeer CRD 時也是參照該 API,並保持相容
- OpenELB 也提供 status 用於檢視 BGP neighbor 配置,狀態資訊豐富
架構簡單,資源佔用少
OpenELB 目前只用部署 Deployment 即可,通過多副本實現高可用,部分副本崩潰後並不會影響已建立的正常連線。
BGP 模式下, Deployment 不同副本都會與路由器建立連線用於釋出等價路由,所以正常情況下我們部署兩個副本即可。在 Layer 2 模式下,不同副本之間通過 Kubernetes 提供的 Leader Election 機制選舉 Leader,進而應答 ARP/NDP。
安裝
在 Kubernetes 叢集中,您只需要安裝一次 OpenELB。安裝完成後,叢集中會安裝一個 openelb-manager Deployment,其中包含一個 openelb-manager Pod。 openelb-manager Pod 為整個 Kubernetes 叢集實現了 OpenELB 的功能。 安裝完成後,可以擴充套件openelb-manager Deployment,將多個OpenELB副本(openelb-manager Pods)分配給多個叢集節點,保證高可用。有關詳細資訊,請參閱配置多個 OpenELB 副本。
要安裝使用 OpenELB 非常簡單,直接使用下面的命令即可一鍵安裝:
# 注意如果不能獲取k8s.gcr.io映象,需要替換其中的映象 ☸ ➜ kubectl apply -f http://raw.githubusercontent.com/openelb/openelb/master/deploy/openelb.yaml
上面的資源清單會部署一個名為 openelb-manager
的 Deployment 資源物件,openelb-manager 的 Pod 為整個 Kubernetes 叢集實現了 OpenELB 的功能,為保證高可用,可以將該控制器擴充套件為兩個副本。第一次安裝的時候還會為 admission webhook 配置 https 證書,安裝完成後檢視 Pod 的狀態是否正常:
☸ ➜ kubectl get pods -n openelb-system NAME READY STATUS RESTARTS AGE openelb-admission-create--1-cf857 0/1 Completed 0 58m openelb-admission-patch--1-dhgrq 0/1 Completed 2 58m openelb-manager-848495684-nppkr 1/1 Running 1 (35m ago) 48m openelb-manager-848495684-svn7z 1/1 Running 1 (35m ago) 48m ☸ ➜ kubectl get validatingwebhookconfiguration NAME WEBHOOKS AGE openelb-admission 1 62m ☸ ➜ kubectl get mutatingwebhookconfigurations NAME WEBHOOKS AGE openelb-admission 1 62m
此外還會安裝幾個相關的 CRD 使用者 OpenELB 配置:
☸ ➜ kubectl get crd |grep kubesphere bgpconfs.network.kubesphere.io 2022-04-10T08:01:18Z bgppeers.network.kubesphere.io 2022-04-10T08:01:18Z eips.network.kubesphere.io 2022-04-10T08:01:18Z
配置
接下來我們來演示下如何使用 layer2 模式的 OpenELB,首先需要保證所有 Kubernetes 叢集節點必須在同一個二層網路(在同一個路由器下),我測試的環境一共3個節點,節點資訊如下所示:
☸ ➜ kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME master1 Ready control-plane,master 15d v1.22.8 192.168.0.111 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 containerd://1.5.5 node1 Ready <none> 15d v1.22.8 192.168.0.110 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 containerd://1.5.5 node2 Ready <none> 15d v1.22.8 192.168.0.109 <none> CentOS Linux 7 (Core) 3.10.0-1160.25.1.el7.x86_64 containerd://1.5.5
3個節點IP地址分別為 192.168.0.109、192.168.0.110、192.168.0.111。
首先需要為 kube-proxy 啟用 strictARP
,以便 Kubernetes 叢集中的所有網絡卡停止響應其他網絡卡的 ARP 請求,而由 OpenELB 處理 ARP 請求。
☸ ➜ kubectl edit configmap kube-proxy -n kube-system ...... ipvs: strictARP: true ......
然後執行下面的命令重啟 kube-proxy 元件即可:
☸ ➜ kubectl rollout restart daemonset kube-proxy -n kube-system
如果安裝 OpenELB 的節點有多個網絡卡,則需要指定 OpenELB 在二層模式下使用的網絡卡,如果節點只有一個網絡卡,則可以跳過此步驟,假設安裝了 OpenELB 的 master1 節點有兩個網絡卡(eth0 192.168.0.2 和 ens33 192.168.0.111),並且 eth0 192.168.0.2 將用於 OpenELB,那麼需要為 master1 節點新增一個 annotation 來指定網絡卡:
☸ ➜ kubectl annotate nodes master1 layer2.openelb.kubesphere.io/v1alpha1="192.168.0.2"
接下來就可以建立一個 Eip 物件來充當 OpenELB 的 IP 地址池了,建立一個如下所示的資源物件:
apiVersion: network.kubesphere.io/v1alpha2 kind: Eip metadata: name: eip-pool spec: address: 192.168.0.100-192.168.0.108 protocol: layer2 disable: false interface: ens33
這裡我們通過 address
屬性指定了 IP 地址池,可以填寫一個或多個 IP 地址(要注意不同 Eip 物件中的 IP 段不能重疊),將被 OpenELB 使用。值格式可以是:
- IP地址,例如 192.168.0.100
- IP地址/子網掩碼,例如 192.168.0.0/24
- IP地址1-IP地址2,例如192.168.0.91-192.168.0.100
protocol
屬性用來指定 Eip 物件用於哪種 OpenELB 模式,可以配置為 layer2 或 bgp,預設為 bgp 模式,我們這裡想使用 layer2 模式,所以需要顯示指定 interface
是用來指定 OpenELB 監聽 ARP 或 NDP 請求的網絡卡,該欄位僅在協議設定為 layer2 時有效,我這裡的環境是 ens33 網絡卡 disable
表示是否禁用 Eip 物件
建立完成 Eip 物件後可以通過 Status 來檢視該 IP 池的具體狀態:
☸ ➜ kubectl get eip NAME CIDR USAGE TOTAL eip-pool 192.168.0.100-192.168.0.108 0 9 ☸ ➜ kubectl get eip eip-pool -oyaml apiVersion: network.kubesphere.io/v1alpha2 kind: Eip metadata: finalizers: - finalizer.ipam.kubesphere.io/v1alpha1 name: eip-pool spec: address: 192.168.0.100-192.168.0.108 interface: ens33 protocol: layer2 status: firstIP: 192.168.0.100 lastIP: 192.168.0.108 poolSize: 9 ready: true v4: true
到這裡 LB 的地址池就準備好了,接下來我們建立一個簡單的服務,通過 LB 來進行暴露,如下所示:
# openelb-nginx.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80
這裡部署一個簡單的 nginx 服務:
☸ ➜ kubectl apply -f openelb-nginx.yaml ☸ ➜ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-7848d4b86f-zmm8l 1/1 Running 0 42s
然後建立一個 LoadBalancer
型別的 Service 來暴露我們的 nginx 服務,如下所示:
# openelb-nginx-svc.yaml apiVersion: v1 kind: Service metadata: name: nginx annotations: lb.kubesphere.io/v1alpha1: openelb protocol.openelb.kubesphere.io/v1alpha1: layer2 eip.openelb.kubesphere.io/v1alpha2: eip-pool spec: selector: app: nginx type: LoadBalancer ports: - name: http port: 80 targetPort: 80
注意這裡我們為 Service 添加了幾個 annotations 註解:
-
lb.kubesphere.io/v1alpha1: openelb
用來指定該 Service 使用 OpenELB -
protocol.openelb.kubesphere.io/v1alpha1: layer2
表示指定 OpenELB 用於 Layer2 模式 -
eip.openelb.kubesphere.io/v1alpha2: eip-pool
用來指定了 OpenELB 使用的 Eip 物件,如果未配置此註解,OpenELB 會自動使用與協議匹配的第一個可用 Eip 物件,此外也可以刪除此註解並新增spec:loadBalancerIP
欄位(例如 spec:loadBalancerIP: 192.168.0.108)以將特定 IP 地址分配給 Service。
同樣直接建立上面的 Service:
☸ ➜ kubectl apply -f openelb-nginx-svc.yaml service/nginx created ☸ ➜ kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx LoadBalancer 10.100.126.91 192.168.0.101 80:31555/TCP 4s
建立完成後可以看到 Service 服務被分配了一個 EXTERNAL-IP
,然後我們就可以通過該地址來訪問上面的 nginx 服務了:
☸ ➜ curl 192.168.0.101 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
此外 OpenElb 還支援 BGP 模式以及叢集多路由的場景,更新使用方法可以檢視官方文件 http://openelb.github.io/docs/ 瞭解更多相關資訊。
參考文件
- http://openelb.github.io/docs/
- http://kubesphere.io/zh/blogs/openelb-joins-cncf-sandbox-project/
- http://mp.weixin.qq.com/s/uFwYaPE7cVolLWxYHcgZdQ
微信公眾號
掃描下面的二維碼關注我們的微信公眾帳號,在微信公眾帳號中回覆◉加群◉即可加入到我們的 kubernetes 討論群裡面共同學習。