在Kubernetes集群中部署MetalLB實現(xiàn)負(fù)載均衡
概述
在公有云部署的kubernetes集群中,有公有云廠商提供LoadBalancer類型的Service。但是在基于本地環(huán)境部署的k8s集群是我們常用的測試環(huán)境和開發(fā)環(huán)境;需要通過NodePort和externalIPs方式將外部流量引入集群中,這就帶來了很多的不便。
尤其是我們通過helm去部署一些服務(wù)時,嘗嘗會依賴于LoadBalancer的資源類型,導(dǎo)致創(chuàng)建的services中type: LoadBalancers會一直處于Pending狀態(tài);我們不得不進(jìn)行倉庫的fetch,然后手動進(jìn)行values的修改。
Metallb 通過標(biāo)準(zhǔn)路由協(xié)議能解決該問題。MetalLB 也是 CNCF 的沙箱項目,最早發(fā)布在
https://github.com/google/metallb 開發(fā),后來遷移到 https://github.com/metallb/metallb 中。
MetalLB 通過 MetalLB hooks 監(jiān)聽SVC的變化;然后通過Speaker組件采用對應(yīng)的模式將外部流量引流到kubernetes集群node節(jié)點的可達(dá)路徑。而具體到Pod中則是通過kuber-proxy依據(jù)轉(zhuǎn)發(fā)模式(iptables或ipvs)將流量轉(zhuǎn)發(fā)到Pod中。
MetaLB負(fù)責(zé)從主機(jī)維度實現(xiàn)負(fù)載均衡,而pod副本間的負(fù)載是通過kube-proxy實現(xiàn)。MetalLB負(fù)責(zé)IP地址分配、依據(jù)設(shè)定的廣播模式進(jìn)行廣播、節(jié)點選舉、節(jié)點失效切換等功能。而引流的過程則通過ARP、NDP和BGP標(biāo)準(zhǔn)路由協(xié)議實現(xiàn)。
主要的兩大功能:
- 地址分配:用戶需要在配置中提供一個地址池,Metallb 將會在其中選取地址分配給服務(wù)。
- 地址廣播(IP外部聲明):根據(jù)不同配置,Metallb 會以二層(ARP/NDP)或者 BGP 的方式進(jìn)行地址的廣播。
工作模式:
- BGP模式(Layer 3),使用BGP協(xié)議分配地址池;運(yùn)行 BGP 的設(shè)備之間可以交換路由信息,我們可以將自己的 IP 段通過 BGP 協(xié)議告訴其他設(shè)備,這樣其他設(shè)備就能正確的路由數(shù)據(jù)包到服務(wù)器上了。BGP 需要路由器的支持。如果Calico也是使用的BGP模式,有可能會有沖突從而導(dǎo)致metallb無法正常工作。
- ARP(IPV4)/NDP(IPV6)工作模式(Layer2);使用 ARP/NDP 協(xié)議分配地址池;在服務(wù)器的內(nèi)部子網(wǎng)里找未使用的 IP,然后等其他電腦訪問這個 IP 的時候,我們回應(yīng)一個 ARP 包,其他電腦就知道這個 IP 在哪里可以通信了,盡管這個 IP 其實沒有綁定到任何網(wǎng)卡上,也有可能只是 iptables 里的一條記錄。分配的 IP 只能和服務(wù)器其他 IP 位于同一子網(wǎng),這就要求我們所有的節(jié)點必須在同一個二層網(wǎng)絡(luò)內(nèi)。
更多詳情請參考官方文檔:https://metallb.universe.tf/。
架構(gòu)
二層部署的架構(gòu)圖,參考紅帽openshift官方文檔。
上圖顯示了與 MetalLB 相關(guān)的以下概念:
- 應(yīng)用程序可以通過在 172.130.0.0/16 子網(wǎng)上具有集群 IP 的服務(wù)獲取。該 IP 地址可以從集群內(nèi)部訪問。服務(wù)也有一個外部 IP 地址,用于分配給服務(wù)的 MetalLB,即 192.168.100.200。
- 節(jié)點 1 和 3 具有應(yīng)用程序的 pod。
- speaker 守護(hù)進(jìn)程集在每個節(jié)點上運(yùn)行一個 pod。MetalLB Operator 啟動這些 pod。
- 每個 speaker pod 都是主機(jī)網(wǎng)絡(luò)的 pod。容器集的 IP 地址與主機(jī)網(wǎng)絡(luò)上節(jié)點的 IP 地址相同。
- 節(jié)點 1 上的 speaker pod 使用 ARP 聲明服務(wù)的外部 IP 地址 192.168.100.200。聲明外部 IP 地址的 speaker pod 必須與服務(wù)的端點位于同一個節(jié)點上,端點必須為 Ready 條件。
- 客戶端流量路由到主機(jī)網(wǎng)絡(luò),并連接到 192.168.100.200 IP 地址。在流量進(jìn)入節(jié)點后,服務(wù)代理會根據(jù)您為服務(wù)設(shè)置的外部流量策略,將流量發(fā)送到同一節(jié)點上的應(yīng)用 pod 或其他節(jié)點。
- 如果節(jié)點 1 不可用,則外部 IP 地址將故障轉(zhuǎn)移到另一節(jié)點。在具有應(yīng)用 pod 和服務(wù)端點實例的另一個節(jié)點上,speaker Pod 開始宣布外部 IP 地址 192.168.100.200,新節(jié)點接收客戶端流量。在圖中,唯一的候選項是節(jié)點 3。
部署
環(huán)境要求
集群版本信息如下:
支持MetalLB的CNI如下:
Network addon | Compatible |
Antrea | Yes (Tested on version 1.4 and 1.5) |
Calico | Mostly (see known issues) |
Canal | Yes |
Cilium | Yes |
Flannel | Yes |
Kube-ovn | Yes |
Kube-router | Mostly (see known issues) |
Weave Net | Mostly (see known issues) |
注意事項:
- 參考 CLOUD COMPATIBILITY https://metallb.universe.tf/installation/clouds/ 查看你的環(huán)境是否支持 MetalLB
- 使用 BGP 工作模式時,需要一臺或多臺支持 BGP 的路由器
- 由于第 2 層模式依賴于 ARP 和 NDP,客戶端必須位于沒有中斷服務(wù)的節(jié)點所在的同一子網(wǎng),以便 MetalLB 正常工作。另外,分配給該服務(wù)的 IP 地址必須在客戶端用來訪問該服務(wù)的網(wǎng)絡(luò)所在的同一子網(wǎng)中。
- 使用 L2 工作模式時,所有的節(jié)點必須在同一個二層網(wǎng)絡(luò)內(nèi);必須允許節(jié)點之間通過 7946 端口(TCP & UDP,可以配置其他端口)通信,memberlist服務(wù)監(jiān)聽在該端口;二層模式不需要將 IP 綁定到工作節(jié)點的網(wǎng)絡(luò)接口上。它的工作原理是直接響應(yīng)本地網(wǎng)絡(luò)上的 ARP 請求,將本機(jī)的 MAC 地址提供給客戶端
- 從 Kubernetes v1.14.2 開始,若 kube-proxy 使用 IPVS 模式,需要開啟 strict ARP (嚴(yán)格的ARP)模式,使用 kubectl edit configmap -n kube-system kube-proxy 修改如下:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
通過helm安裝
MetalLBKubernetes manifests、Kustomize 和 Helm 三種安裝方式;這里我們采用helm安裝:
$ helm repo add metallb https://metallb.github.io/metallb
$ helm search repo -l metallb
$ helm fetch metallb/metallb --version=0.13.4
$ tar zxvf metallb-0.13.4.tgz
#這里我們可以根據(jù)自己的需求進(jìn)行values值的修改,例如原鏡像地(quay.io)址無法拉取,我們可以先拉取然后上傳到自己的鏡像倉庫,然后修改地址
$ kubectl create namespace metallb-system
$ helm install metallb -n metallb-system ./metallb
驗證安裝,如下圖所示
在metallb-system的namespace下,會安裝兩個組件:
- controller deployment:負(fù)責(zé)監(jiān)聽service資源的變化;依據(jù)對應(yīng)的IP地址池進(jìn)行IP地址分配的控制器。
- speaker daemonset:負(fù)責(zé)監(jiān)聽service資源的變化;通過protocols維護(hù)服務(wù)間聯(lián)通,并依據(jù)具體的協(xié)議發(fā)起對應(yīng)的廣播和應(yīng)答、以及節(jié)點leader的選舉。
speaker pod 響應(yīng) IPv4 服務(wù)和 IPv6 的 NDP 請求。
通過manifest安裝
要安裝 MetalLB,使用yaml應(yīng)用清單:
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yaml
配置
由于我們的集群工作在測試環(huán)境中,我們采用的是L2工作模式下。
第 2 層模式最容易上手,并且可以在任何環(huán)境中工作——不需要花哨的路由器。
定義要分給負(fù)載均衡服務(wù)的IP地址池。
新版本metallb使用了CR(Custom Resources),這里我們通過IPAddressPool的CR,進(jìn)行地址池的定義。
如果實例中不設(shè)置IPAddressPool選擇器L2Advertisement;那么L2Advertisement默認(rèn)為該實例所有的IPAddressPool相關(guān)聯(lián)。
創(chuàng)建metallb-config-ipaddresspool.yaml:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.74.100-192.168.74.110
進(jìn)行L2關(guān)聯(lián)地址池的綁定。這里也可以使用標(biāo)簽選擇器。
創(chuàng)建metallb-config-L2Advertisement.yaml:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
測試
創(chuàng)建類型為LoadBalancer的SVC進(jìn)行測試,創(chuàng)建yaml文件tutorial-1.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
結(jié)果如下圖所示:
通過瀏覽器進(jìn)行訪問:
參考網(wǎng)址:
- https://access.redhat.com/documentation/zhcn/openshift_container_platform/4.9/html/networking/_load-balancing-with-metallb。
- https://metallb.universe.tf/。