在Kubernetes集群中部署MetalLB實(shí)現(xiàn)負(fù)載均衡

概述
在公有云部署的kubernetes集群中,有公有云廠商提供LoadBalancer類(lèi)型的Service。但是在基于本地環(huán)境部署的k8s集群是我們常用的測(cè)試環(huán)境和開(kāi)發(fā)環(huán)境;需要通過(guò)NodePort和externalIPs方式將外部流量引入集群中,這就帶來(lái)了很多的不便。
尤其是我們通過(guò)helm去部署一些服務(wù)時(shí),嘗嘗會(huì)依賴(lài)于LoadBalancer的資源類(lèi)型,導(dǎo)致創(chuàng)建的services中type: LoadBalancers會(huì)一直處于Pending狀態(tài);我們不得不進(jìn)行倉(cāng)庫(kù)的fetch,然后手動(dòng)進(jìn)行values的修改。
Metallb 通過(guò)標(biāo)準(zhǔn)路由協(xié)議能解決該問(wèn)題。MetalLB 也是 CNCF 的沙箱項(xiàng)目,最早發(fā)布在
https://github.com/google/metallb 開(kāi)發(fā),后來(lái)遷移到 https://github.com/metallb/metallb 中。
MetalLB 通過(guò) MetalLB hooks 監(jiān)聽(tīng)SVC的變化;然后通過(guò)Speaker組件采用對(duì)應(yīng)的模式將外部流量引流到kubernetes集群node節(jié)點(diǎn)的可達(dá)路徑。而具體到Pod中則是通過(guò)kuber-proxy依據(jù)轉(zhuǎn)發(fā)模式(iptables或ipvs)將流量轉(zhuǎn)發(fā)到Pod中。
MetaLB負(fù)責(zé)從主機(jī)維度實(shí)現(xiàn)負(fù)載均衡,而pod副本間的負(fù)載是通過(guò)kube-proxy實(shí)現(xiàn)。MetalLB負(fù)責(zé)IP地址分配、依據(jù)設(shè)定的廣播模式進(jìn)行廣播、節(jié)點(diǎn)選舉、節(jié)點(diǎn)失效切換等功能。而引流的過(guò)程則通過(guò)ARP、NDP和BGP標(biāo)準(zhǔn)路由協(xié)議實(shí)現(xiàn)。
主要的兩大功能:
- 地址分配:用戶(hù)需要在配置中提供一個(gè)地址池,Metallb 將會(huì)在其中選取地址分配給服務(wù)。
 - 地址廣播(IP外部聲明):根據(jù)不同配置,Metallb 會(huì)以二層(ARP/NDP)或者 BGP 的方式進(jìn)行地址的廣播。
 
工作模式:
- BGP模式(Layer 3),使用BGP協(xié)議分配地址池;運(yùn)行 BGP 的設(shè)備之間可以交換路由信息,我們可以將自己的 IP 段通過(guò) BGP 協(xié)議告訴其他設(shè)備,這樣其他設(shè)備就能正確的路由數(shù)據(jù)包到服務(wù)器上了。BGP 需要路由器的支持。如果Calico也是使用的BGP模式,有可能會(huì)有沖突從而導(dǎo)致metallb無(wú)法正常工作。
 - ARP(IPV4)/NDP(IPV6)工作模式(Layer2);使用 ARP/NDP 協(xié)議分配地址池;在服務(wù)器的內(nèi)部子網(wǎng)里找未使用的 IP,然后等其他電腦訪問(wèn)這個(gè) IP 的時(shí)候,我們回應(yīng)一個(gè) ARP 包,其他電腦就知道這個(gè) IP 在哪里可以通信了,盡管這個(gè) IP 其實(shí)沒(méi)有綁定到任何網(wǎng)卡上,也有可能只是 iptables 里的一條記錄。分配的 IP 只能和服務(wù)器其他 IP 位于同一子網(wǎng),這就要求我們所有的節(jié)點(diǎn)必須在同一個(gè)二層網(wǎng)絡(luò)內(nèi)。
 
更多詳情請(qǐng)參考官方文檔:https://metallb.universe.tf/。
架構(gòu)
二層部署的架構(gòu)圖,參考紅帽openshift官方文檔。

上圖顯示了與 MetalLB 相關(guān)的以下概念:
- 應(yīng)用程序可以通過(guò)在 172.130.0.0/16 子網(wǎng)上具有集群 IP 的服務(wù)獲取。該 IP 地址可以從集群內(nèi)部訪問(wèn)。服務(wù)也有一個(gè)外部 IP 地址,用于分配給服務(wù)的 MetalLB,即 192.168.100.200。
 - 節(jié)點(diǎn) 1 和 3 具有應(yīng)用程序的 pod。
 - speaker 守護(hù)進(jìn)程集在每個(gè)節(jié)點(diǎn)上運(yùn)行一個(gè) pod。MetalLB Operator 啟動(dòng)這些 pod。
 - 每個(gè) speaker pod 都是主機(jī)網(wǎng)絡(luò)的 pod。容器集的 IP 地址與主機(jī)網(wǎng)絡(luò)上節(jié)點(diǎn)的 IP 地址相同。
 - 節(jié)點(diǎn) 1 上的 speaker pod 使用 ARP 聲明服務(wù)的外部 IP 地址 192.168.100.200。聲明外部 IP 地址的 speaker pod 必須與服務(wù)的端點(diǎn)位于同一個(gè)節(jié)點(diǎn)上,端點(diǎn)必須為 Ready 條件。
 - 客戶(hù)端流量路由到主機(jī)網(wǎng)絡(luò),并連接到 192.168.100.200 IP 地址。在流量進(jìn)入節(jié)點(diǎn)后,服務(wù)代理會(huì)根據(jù)您為服務(wù)設(shè)置的外部流量策略,將流量發(fā)送到同一節(jié)點(diǎn)上的應(yīng)用 pod 或其他節(jié)點(diǎn)。
 - 如果節(jié)點(diǎn) 1 不可用,則外部 IP 地址將故障轉(zhuǎn)移到另一節(jié)點(diǎn)。在具有應(yīng)用 pod 和服務(wù)端點(diǎn)實(shí)例的另一個(gè)節(jié)點(diǎn)上,speaker Pod 開(kāi)始宣布外部 IP 地址 192.168.100.200,新節(jié)點(diǎn)接收客戶(hù)端流量。在圖中,唯一的候選項(xiàng)是節(jié)點(diǎn) 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)  | 
注意事項(xiàng):
- 參考 CLOUD COMPATIBILITY https://metallb.universe.tf/installation/clouds/ 查看你的環(huán)境是否支持 MetalLB
 - 使用 BGP 工作模式時(shí),需要一臺(tái)或多臺(tái)支持 BGP 的路由器
 - 由于第 2 層模式依賴(lài)于 ARP 和 NDP,客戶(hù)端必須位于沒(méi)有中斷服務(wù)的節(jié)點(diǎn)所在的同一子網(wǎng),以便 MetalLB 正常工作。另外,分配給該服務(wù)的 IP 地址必須在客戶(hù)端用來(lái)訪問(wèn)該服務(wù)的網(wǎng)絡(luò)所在的同一子網(wǎng)中。
 - 使用 L2 工作模式時(shí),所有的節(jié)點(diǎn)必須在同一個(gè)二層網(wǎng)絡(luò)內(nèi);必須允許節(jié)點(diǎn)之間通過(guò) 7946 端口(TCP & UDP,可以配置其他端口)通信,memberlist服務(wù)監(jiān)聽(tīng)在該端口;二層模式不需要將 IP 綁定到工作節(jié)點(diǎn)的網(wǎng)絡(luò)接口上。它的工作原理是直接響應(yīng)本地網(wǎng)絡(luò)上的 ARP 請(qǐng)求,將本機(jī)的 MAC 地址提供給客戶(hù)端
 - 從 Kubernetes v1.14.2 開(kāi)始,若 kube-proxy 使用 IPVS 模式,需要開(kāi)啟 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
通過(guò)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)址無(wú)法拉取,我們可以先拉取然后上傳到自己的鏡像倉(cāng)庫(kù),然后修改地址
$ kubectl create namespace metallb-system
$ helm install metallb -n metallb-system ./metallb
驗(yàn)證安裝,如下圖所示

在metallb-system的namespace下,會(huì)安裝兩個(gè)組件:
- controller deployment:負(fù)責(zé)監(jiān)聽(tīng)service資源的變化;依據(jù)對(duì)應(yīng)的IP地址池進(jìn)行IP地址分配的控制器。
 - speaker daemonset:負(fù)責(zé)監(jiān)聽(tīng)service資源的變化;通過(guò)protocols維護(hù)服務(wù)間聯(lián)通,并依據(jù)具體的協(xié)議發(fā)起對(duì)應(yīng)的廣播和應(yīng)答、以及節(jié)點(diǎn)leader的選舉。
 
speaker pod 響應(yīng) IPv4 服務(wù)和 IPv6 的 NDP 請(qǐng)求。
通過(guò)manifest安裝
要安裝 MetalLB,使用yaml應(yīng)用清單:
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yaml
配置
由于我們的集群工作在測(cè)試環(huán)境中,我們采用的是L2工作模式下。
第 2 層模式最容易上手,并且可以在任何環(huán)境中工作——不需要花哨的路由器。
定義要分給負(fù)載均衡服務(wù)的IP地址池。
新版本metallb使用了CR(Custom Resources),這里我們通過(guò)IPAddressPool的CR,進(jìn)行地址池的定義。
如果實(shí)例中不設(shè)置IPAddressPool選擇器L2Advertisement;那么L2Advertisement默認(rèn)為該實(shí)例所有的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
測(cè)試
創(chuàng)建類(lèi)型為L(zhǎng)oadBalancer的SVC進(jìn)行測(cè)試,創(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é)果如下圖所示:

通過(guò)瀏覽器進(jìn)行訪問(wèn):

參考網(wǎng)址:
- https://access.redhat.com/documentation/zhcn/openshift_container_platform/4.9/html/networking/_load-balancing-with-metallb。
 - https://metallb.universe.tf/。
 















 
 
 








 
 
 
 