在 Kubernetes 集群中使用 MetalLB 作为 Load Balancer(上)
作者 | Addo Zhang
來源 | 云原生指北
TL;DR
網絡方面的知識又多又雜,很多又是系統內核的部分。原本自己不是做網絡方面的,系統內核知識也薄弱。但恰恰是這些陌生的內容滿滿的誘惑,加上現在的工作跟網絡關聯更多了,逮住機會就學習下。
這篇以 Kubernetes LoadBalancer 為起點,使用 MetalLB 去實現集群的負載均衡器,在探究其工作原理的同時了解一些網絡的知識。
由于 MetalLB 的內容有點多,一步步來,今天這篇僅介紹其中簡單又容易理解的部分。
LoadBalancer 類型 Service
由于 Kubernets 中 Pod 的 IP 地址不固定,重啟后 IP 會發生變化,無法作為通信的地址。Kubernets 提供了 Service 來解決這個問題,對外暴露。
Kubernetes 為一組 Pod 提供相同的 DNS 名和虛擬 IP,同時還提供了負載均衡的能力。這里 Pod 的分組通過給 Pod 打標簽(Label )來完成,定義 Service 時會聲明標簽選擇器(selector)將 Service 與 這組 Pod 關聯起來。
根據使用場景的不同,Service 又分為 4 種類型:ClusterIP、NodePort、LoadBalancer 和 ExternalName,默認是 ClusterIP。這里不一一詳細介紹,有興趣的查看 Service 官方文檔[1]。
除了今天的主角 LoadBalancer 外,其他 3 種都是比較常用的類型。LoadBalancer 官方的解釋是:
使用云提供商的負載均衡器向外部暴露服務。外部負載均衡器可以將流量路由到自動創建的?NodePort?服務和?ClusterIP?服務上。
lb-service看到“云提供商提供”幾個字時往往望而卻步,有時又需要 LoadBalancer 對外暴露服務做些驗證工作(雖然除了 7 層的 Ingress 以外,還可以使用 NodePort 類型的 Service),而 Kubernetes 官方并沒有提供實現。比如下面要介紹的 MetalLB[2]?就是個不錯的選擇。
MetalLB 介紹
MetalLB 是裸機 Kubernetes 集群的負載均衡器實現,使用標準路由協議。
注意:?MetalLB 目前還是 beta 階段。
前文提到 Kubernetes 官方并沒有提供 LoadBalancer 的實現。各家云廠商有提供實現,但假如不是運行在這些云環境上,創建的 LoadBalancer Service 會一直處于 Pending 狀態(見下文 Demo 部分)。
MetalLB 提供了兩個功能:
地址分配:當創建 LoadBalancer Service 時,MetalLB 會為其分配 IP 地址。這個 IP 地址是從預先配置的 IP 地址庫獲取的。同樣,當 Service 刪除后,已分配的 IP 地址會重新回到地址庫。
對外廣播:分配了 IP 地址之后,需要讓集群外的網絡知道這個地址的存在。MetalLB 使用了標準路由協議實現:ARP、NDP 或者 BGP。
廣播的方式有兩種,第一種是 Layer 2 模式,使用 ARP(ipv4)/NDP(ipv6) 協議;第二種是 BPG。
今天主要介紹簡單的 Layer 2 模式,顧名思義是 OSI 二層的實現。
具體實現原理,看完 Demo 再做分析,等不及的同學請直接跳到最后。
運行時
MetalLB 運行時有兩種工作負載:
Controler:Deployment,用于監聽 Service 的變更,分配/回收 IP 地址。
Speaker:DaemonSet,對外廣播 Service 的 IP 地址。
Demo
安裝之前介紹下網絡環境,Kubernetes 使用 K8s 安裝在 Proxmox 的虛擬機[3]上。
安裝 K3s
安裝 K3s,這里需要通過?--disable servicelb?禁用 k3s 默認的 servicelb。
參考?K3s 文檔[4],默認情況下 K3s 使用?Traefik[5]?ingress 控制器 和?Klipper[6]?Service 負載均衡器來對外暴露服務。
curl?-sfL?https://get.k3s.io?|?sh?-s?-?--disable?traefik?--disable?servicelb?--write-kubeconfig-mode?644?--write-kubeconfig?~/.kube/config創建工作負載
使用 nginx 鏡像,創建兩個工作負載:
kubectl?create?deploy?nginx?--image?nginx:latest?--port?80?-n?default kubectl?create?deploy?nginx2?--image?nginx:latest?--port?80?-n?default同時為兩個 Deployment 創建 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 發現狀態都是?Pending?的,這是因為安裝 K3s 的時候我們禁用了 LoadBalancer 的實現:
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這時就需要 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此時再檢查 LoadBalancer Service 的狀態仍然是?Pending?的,嗯?因為,MetalLB 要為 Service 分配 IP 地址,但 IP 地址不是憑空來的,而是需要預先提供一個地址庫。
這里我們使用?Layer 2?模式,通過?Configmap?為其提供一個 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此時再查看 Service 的狀態,可以看到 MetalLB 為兩個 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 表可以找到這兩個 IP 及 mac 地址,可以看出兩個 IP 都綁定在同一個網卡上,此外還有虛擬機的 IP 地址。也就是說 3 個 IP 綁定在該虛擬機的?en0?上:
而去虛擬機(節點)查看網卡(這里只能看到系統綁定的 IP):
Layer 2 工作原理
Layer 2 中的 Speaker 工作負載是 DeamonSet 類型,在每臺節點上都調度一個 Pod。首先,幾個 Pod 會先進行選舉,選舉出?Leader。Leader?獲取所有?LoadBalancer?類型的 Service,將已分配的 IP 地址綁定到當前主機到網卡上。也就是說,所有?LoadBalancer?類型的 Service 的 IP 同一時間都是綁定在同一臺節點的網卡上。
當外部主機有請求要發往集群內的某個 Service,需要先確定目標主機網卡的 mac 地址(至于為什么,參考維基百科[10])。這是通過發送 ARP 請求,Leader?節點的會以其 mac 地址作為響應。外部主機會在本地 ARP 表中緩存下來,下次會直接從 ARP 表中獲取。
請求到達節點后,節點再通過?kube-proxy?將請求負載均衡目標 Pod。所以說,假如Service 是多 Pod 這里有可能會再跳去另一臺主機。
sequence優缺點
優點很明顯,實現起來簡單(相對于另一種 BGP 模式下路由器要支持 BPG)。就像筆者的環境一樣,只要保證 IP 地址庫與集群是同一個網段即可。
當然缺點更加明顯了,Leader?節點的帶寬會成為瓶頸;與此同時,可用性欠佳,故障轉移需要 10 秒鐘的時間(每個 speaker 進程有個 10s 的循環[11])。
參考鏈接:
Service 官方文檔:?
https://kubernetes.io/zh/docs/concepts/services-networking/service/#publishing-services-service-types?
MetalLB:?https://metallb.universe.tf
Proxmox 的虛擬機:?
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
每個 speaker 進程有個 10s 的循環:
https://github.com/metallb/metallb/blob/main/internal/layer2/announcer.go#L51
地址解析協議:?
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/
往期推薦
為什么大家都在抵制用定時任務實現「關閉超時訂單」功能?
如果被問到分布式鎖,應該怎樣回答?
別再用 Redis List 實現消息隊列了,Stream 專為隊列而生
Java 底層知識:什么是?“橋接方法”??
點分享
點收藏
點點贊
點在看
總結
以上是生活随笔為你收集整理的在 Kubernetes 集群中使用 MetalLB 作为 Load Balancer(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 低碳数据中心,因何而来?一文读懂如何利用
- 下一篇: 普诺飞思公布发明者社区,启发基于事件视觉