在 Kubernetes 集群中使用 MetalLB 作为 Load Balancer(上)
作者 | Addo Zhang
來源 | 云原生指北
TL;DR
網(wǎng)絡(luò)方面的知識(shí)又多又雜,很多又是系統(tǒng)內(nèi)核的部分。原本自己不是做網(wǎng)絡(luò)方面的,系統(tǒng)內(nèi)核知識(shí)也薄弱。但恰恰是這些陌生的內(nèi)容滿滿的誘惑,加上現(xiàn)在的工作跟網(wǎng)絡(luò)關(guān)聯(lián)更多了,逮住機(jī)會(huì)就學(xué)習(xí)下。
這篇以 Kubernetes LoadBalancer 為起點(diǎn),使用 MetalLB 去實(shí)現(xiàn)集群的負(fù)載均衡器,在探究其工作原理的同時(shí)了解一些網(wǎng)絡(luò)的知識(shí)。
由于 MetalLB 的內(nèi)容有點(diǎn)多,一步步來,今天這篇僅介紹其中簡單又容易理解的部分。
LoadBalancer 類型 Service
由于 Kubernets 中 Pod 的 IP 地址不固定,重啟后 IP 會(huì)發(fā)生變化,無法作為通信的地址。Kubernets 提供了 Service 來解決這個(gè)問題,對外暴露。
Kubernetes 為一組 Pod 提供相同的 DNS 名和虛擬 IP,同時(shí)還提供了負(fù)載均衡的能力。這里 Pod 的分組通過給 Pod 打標(biāo)簽(Label )來完成,定義 Service 時(shí)會(huì)聲明標(biāo)簽選擇器(selector)將 Service 與 這組 Pod 關(guān)聯(lián)起來。
根據(jù)使用場景的不同,Service 又分為 4 種類型:ClusterIP、NodePort、LoadBalancer 和 ExternalName,默認(rèn)是 ClusterIP。這里不一一詳細(xì)介紹,有興趣的查看 Service 官方文檔[1]。
除了今天的主角 LoadBalancer 外,其他 3 種都是比較常用的類型。LoadBalancer 官方的解釋是:
使用云提供商的負(fù)載均衡器向外部暴露服務(wù)。外部負(fù)載均衡器可以將流量路由到自動(dòng)創(chuàng)建的?NodePort?服務(wù)和?ClusterIP?服務(wù)上。
lb-service看到“云提供商提供”幾個(gè)字時(shí)往往望而卻步,有時(shí)又需要 LoadBalancer 對外暴露服務(wù)做些驗(yàn)證工作(雖然除了 7 層的 Ingress 以外,還可以使用 NodePort 類型的 Service),而 Kubernetes 官方并沒有提供實(shí)現(xiàn)。比如下面要介紹的 MetalLB[2]?就是個(gè)不錯(cuò)的選擇。
MetalLB 介紹
MetalLB 是裸機(jī) Kubernetes 集群的負(fù)載均衡器實(shí)現(xiàn),使用標(biāo)準(zhǔn)路由協(xié)議。
注意:?MetalLB 目前還是 beta 階段。
前文提到 Kubernetes 官方并沒有提供 LoadBalancer 的實(shí)現(xiàn)。各家云廠商有提供實(shí)現(xiàn),但假如不是運(yùn)行在這些云環(huán)境上,創(chuàng)建的 LoadBalancer Service 會(huì)一直處于 Pending 狀態(tài)(見下文 Demo 部分)。
MetalLB 提供了兩個(gè)功能:
地址分配:當(dāng)創(chuàng)建 LoadBalancer Service 時(shí),MetalLB 會(huì)為其分配 IP 地址。這個(gè) IP 地址是從預(yù)先配置的 IP 地址庫獲取的。同樣,當(dāng) Service 刪除后,已分配的 IP 地址會(huì)重新回到地址庫。
對外廣播:分配了 IP 地址之后,需要讓集群外的網(wǎng)絡(luò)知道這個(gè)地址的存在。MetalLB 使用了標(biāo)準(zhǔn)路由協(xié)議實(shí)現(xiàn):ARP、NDP 或者 BGP。
廣播的方式有兩種,第一種是 Layer 2 模式,使用 ARP(ipv4)/NDP(ipv6) 協(xié)議;第二種是 BPG。
今天主要介紹簡單的 Layer 2 模式,顧名思義是 OSI 二層的實(shí)現(xiàn)。
具體實(shí)現(xiàn)原理,看完 Demo 再做分析,等不及的同學(xué)請直接跳到最后。
運(yùn)行時(shí)
MetalLB 運(yùn)行時(shí)有兩種工作負(fù)載:
Controler:Deployment,用于監(jiān)聽 Service 的變更,分配/回收 IP 地址。
Speaker:DaemonSet,對外廣播 Service 的 IP 地址。
Demo
安裝之前介紹下網(wǎng)絡(luò)環(huán)境,Kubernetes 使用 K8s 安裝在 Proxmox 的虛擬機(jī)[3]上。
安裝 K3s
安裝 K3s,這里需要通過?--disable servicelb?禁用 k3s 默認(rèn)的 servicelb。
參考?K3s 文檔[4],默認(rèn)情況下 K3s 使用?Traefik[5]?ingress 控制器 和?Klipper[6]?Service 負(fù)載均衡器來對外暴露服務(wù)。
curl?-sfL?https://get.k3s.io?|?sh?-s?-?--disable?traefik?--disable?servicelb?--write-kubeconfig-mode?644?--write-kubeconfig?~/.kube/config創(chuàng)建工作負(fù)載
使用 nginx 鏡像,創(chuàng)建兩個(gè)工作負(fù)載:
kubectl?create?deploy?nginx?--image?nginx:latest?--port?80?-n?default kubectl?create?deploy?nginx2?--image?nginx:latest?--port?80?-n?default同時(shí)為兩個(gè) Deployment 創(chuàng)建 Service,這里類型選擇?LoadBalancer:
kubectl?expose?deployment?nginx?--name?nginx-lb?--port?8080?--target-port?80?--type?LoadBalancer?-n?default kubectl?expose?deployment?nginx2?--name?nginx2-lb?--port?8080?--target-port?80?--type?LoadBalancer?-n?default檢查 Service 發(fā)現(xiàn)狀態(tài)都是?Pending?的,這是因?yàn)榘惭b K3s 的時(shí)候我們禁用了 LoadBalancer 的實(shí)現(xiàn):
kubectl?get?svc?-n?default NAME?????????TYPE???????????CLUSTER-IP??????EXTERNAL-IP???PORT(S)??????????AGE kubernetes???ClusterIP??????10.43.0.1???????<none>????????443/TCP??????????14m nginx-lb?????LoadBalancer???10.43.108.233???<pending>?????8080:31655/TCP???35s nginx2-lb????LoadBalancer???10.43.26.30?????<pending>?????8080:31274/TCP???16s這時(shí)就需要 MetalLB 登場了。
安裝 MetalLB
使用官方提供 manifest 來安裝,目前最新的版本是?0.12.1。此外,還可以其他安裝方式供選擇,比如?Helm[7]、Kustomize[8]?或者?MetalLB Operator[9]。
kubectl?apply?-f?https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml kubectl?apply?-f?https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yamlkubectl?get?po?-n?metallb-system NAME??????????????????????????READY???STATUS????RESTARTS???AGE speaker-98t5t?????????????????1/1?????Running???0??????????22s controller-66445f859d-gt9tn???1/1?????Running???0??????????22s此時(shí)再檢查 LoadBalancer Service 的狀態(tài)仍然是?Pending?的,嗯?因?yàn)?#xff0c;MetalLB 要為 Service 分配 IP 地址,但 IP 地址不是憑空來的,而是需要預(yù)先提供一個(gè)地址庫。
這里我們使用?Layer 2?模式,通過?Configmap?為其提供一個(gè) IP 段:
apiVersion:?v1 kind:?ConfigMap metadata:namespace:?metallb-systemname:?config data:config:?|address-pools:-?name:?defaultprotocol:?layer2addresses:-?192.168.1.30-192.168.1.49此時(shí)再查看 Service 的狀態(tài),可以看到 MetalLB 為兩個(gè) Service 分配了 IP 地址?192.168.1.30、192.168.1.31:
kubectl?get?svc?-n?default NAME?????????TYPE???????????CLUSTER-IP??????EXTERNAL-IP????PORT(S)??????????AGE kubernetes???ClusterIP??????10.43.0.1???????<none>?????????443/TCP??????????28m nginx-lb?????LoadBalancer???10.43.201.249???192.168.1.30???8080:30089/TCP???14m nginx2-lb????LoadBalancer???10.43.152.236???192.168.1.31???8080:31878/TCP???14m可以請求測試下:
curl?-I?192.168.1.30:8080 HTTP/1.1?200?OK Server:?nginx/1.21.6 Date:?Wed,?02?Mar?2022?15:31:15?GMT Content-Type:?text/html Content-Length:?615 Last-Modified:?Tue,?25?Jan?2022?15:03:52?GMT Connection:?keep-alive ETag:?"61f01158-267" Accept-Ranges:?bytescurl?-I?192.168.1.31:8080 HTTP/1.1?200?OK Server:?nginx/1.21.6 Date:?Wed,?02?Mar?2022?15:31:18?GMT Content-Type:?text/html Content-Length:?615 Last-Modified:?Tue,?25?Jan?2022?15:03:52?GMT Connection:?keep-alive ETag:?"61f01158-267" Accept-Ranges:?bytesmacOS 本地使用?arp -a?查看 ARP 表可以找到這兩個(gè) IP 及 mac 地址,可以看出兩個(gè) IP 都綁定在同一個(gè)網(wǎng)卡上,此外還有虛擬機(jī)的 IP 地址。也就是說 3 個(gè) IP 綁定在該虛擬機(jī)的?en0?上:
而去虛擬機(jī)(節(jié)點(diǎn))查看網(wǎng)卡(這里只能看到系統(tǒng)綁定的 IP):
Layer 2 工作原理
Layer 2 中的 Speaker 工作負(fù)載是 DeamonSet 類型,在每臺(tái)節(jié)點(diǎn)上都調(diào)度一個(gè) Pod。首先,幾個(gè) Pod 會(huì)先進(jìn)行選舉,選舉出?Leader。Leader?獲取所有?LoadBalancer?類型的 Service,將已分配的 IP 地址綁定到當(dāng)前主機(jī)到網(wǎng)卡上。也就是說,所有?LoadBalancer?類型的 Service 的 IP 同一時(shí)間都是綁定在同一臺(tái)節(jié)點(diǎn)的網(wǎng)卡上。
當(dāng)外部主機(jī)有請求要發(fā)往集群內(nèi)的某個(gè) Service,需要先確定目標(biāo)主機(jī)網(wǎng)卡的 mac 地址(至于為什么,參考維基百科[10])。這是通過發(fā)送 ARP 請求,Leader?節(jié)點(diǎn)的會(huì)以其 mac 地址作為響應(yīng)。外部主機(jī)會(huì)在本地 ARP 表中緩存下來,下次會(huì)直接從 ARP 表中獲取。
請求到達(dá)節(jié)點(diǎn)后,節(jié)點(diǎn)再通過?kube-proxy?將請求負(fù)載均衡目標(biāo) Pod。所以說,假如Service 是多 Pod 這里有可能會(huì)再跳去另一臺(tái)主機(jī)。
sequence優(yōu)缺點(diǎn)
優(yōu)點(diǎn)很明顯,實(shí)現(xiàn)起來簡單(相對于另一種 BGP 模式下路由器要支持 BPG)。就像筆者的環(huán)境一樣,只要保證 IP 地址庫與集群是同一個(gè)網(wǎng)段即可。
當(dāng)然缺點(diǎn)更加明顯了,Leader?節(jié)點(diǎn)的帶寬會(huì)成為瓶頸;與此同時(shí),可用性欠佳,故障轉(zhuǎn)移需要 10 秒鐘的時(shí)間(每個(gè) speaker 進(jìn)程有個(gè) 10s 的循環(huán)[11])。
參考鏈接:
Service 官方文檔:?
https://kubernetes.io/zh/docs/concepts/services-networking/service/#publishing-services-service-types?
MetalLB:?https://metallb.universe.tf
Proxmox 的虛擬機(jī):?
https://atbug.com/deploy-vm-on-proxmox-with-terraform/
K3s 文檔:?
https://rancher.com/docs/k3s/latest/en/networking/
Traefik:?https://rancher.com/docs/k3s/latest/en/networking/
Klipper:?https://metallb.universe.tf/configuration/k3s/
Helm:?https://metallb.universe.tf/installation/#installation-with-helm
Kustomize:?
https://metallb.universe.tf/installation/#installation-with-kustomize
MetalLB Operator:?https://metallb.universe.tf/installation/#using-the-metallb-operator
維基百科:?
https://zh.wikipedia.org/wiki/%E5%9C%B0%E5%9D%80%E8%A7%A3%E6%9E%90%E5%8D%8F%E8%AE%AE
每個(gè) speaker 進(jìn)程有個(gè) 10s 的循環(huán):
https://github.com/metallb/metallb/blob/main/internal/layer2/announcer.go#L51
地址解析協(xié)議:?
https://zh.wikipedia.org/wiki/%E5%9C%B0%E5%9D%80%E8%A7%A3%E6%9E%90%E5%8D%8F%E8%AE%AE
MetalLB 概念:?
https://metallb.universe.tf/concepts/
往期推薦
為什么大家都在抵制用定時(shí)任務(wù)實(shí)現(xiàn)「關(guān)閉超時(shí)訂單」功能?
如果被問到分布式鎖,應(yīng)該怎樣回答?
別再用 Redis List 實(shí)現(xiàn)消息隊(duì)列了,Stream 專為隊(duì)列而生
Java 底層知識(shí):什么是?“橋接方法”??
點(diǎn)分享
點(diǎn)收藏
點(diǎn)點(diǎn)贊
點(diǎn)在看
總結(jié)
以上是生活随笔為你收集整理的在 Kubernetes 集群中使用 MetalLB 作为 Load Balancer(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 低碳数据中心,因何而来?一文读懂如何利用
- 下一篇: 场景化封装,一站式使用,普惠AI集成 —