MetalLB 作為 Kubernetes 叢集的負載平衡解決方案,提供 Layer 4 的負載平衡功能,讓應用服務得以暴露於外部網路。其核心元件 Speaker 和 Controller 負責服務宣告、IP 位址分配和服務狀態更新,並透過 ETCD 儲存服務狀態。MetalLB 支援多 IP Pool 設定,允許管理員依據服務需求分配不同的子網路,例如區分網頁服務和資料函式庫服務的 IP 範圍。文章以新增 IP Pool subnet-201 為例,示範如何透過修改 ConfigMap 和新增 Service 註解來分配特定 IP 範圍。此外,MetalLB 也支援多協定負載平衡,透過 allow-shared-ip 註解,允許多個服務分享同一個 IP 位址。文章以 CoreDNS 為例,說明如何建立 TCP 和 UDP 服務並確保其分享同一個外部 IP,解決 Kubernetes Service 物件預設不支援多協定的限制。最後,文章也提及 external-dns 的整合,補充 MetalLB 缺少的 DNS 解析功能,讓外部網路能透過網域名稱存取叢集服務。
MetalLB 元件與 LoadBalancer 服務詳解
在前面的章節中,我們介紹瞭如何佈署 MetalLB 並組態其基本設定。在本章節中,我們將探討 MetalLB 的內部元件,以及如何使用 LoadBalancer 服務。
MetalLB 元件
MetalLB 的佈署包含兩個主要元件:speaker 和 controller。這些元件共同工作以維護服務列表和分配的 IP 位址。
Speaker 元件
Speaker 元件負責在節點上宣告 LoadBalancer 服務。它被佈署為 DaemonSet,因為佈署可以在任何工作節點上進行,因此每個工作節點都需要宣告正在執行的工作負載。
當使用 LoadBalancer 型別建立服務時,speaker 將宣告該服務。從節點的 speaker 日誌中,我們可以看到如下宣告:
{"caller":"main.go:176","event":"startUpdate","msg":"start of service update","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.437231123Z"}
{"caller":"main.go:189","event":"endUpdate","msg":"end of service update","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.437516541Z"}
{"caller":"main.go:176","event":"startUpdate","msg":"start of service update","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.464140524Z"}
{"caller":"main.go:246","event":"serviceAnnounced","ip":"10.2.1.72","msg":"service has IP, announcing","pool":"default","protocol":"layer2","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.464311087Z"}
Controller 元件
Controller 元件接收來自每個工作節點上的 speaker 的宣告。使用相同的服務宣告,controller 日誌顯示了宣告和分配給服務的 IP 位址:
{"caller":"main.go:49","event":"startUpdate","msg":"start of service update","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.437701161Z"}
{"caller":"service.go:98","event":"ipAllocated","ip":"10.2.1.72","msg":"IP address assigned by controller","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.438079774Z"}
{"caller":"main.go:96","event":"serviceUpdated","msg":"updated service object","service":"my-grafana-operator/grafana-operator-metrics","ts":"2020-04-21T21:10:07.467998702Z"}
建立 LoadBalancer 服務
現在我們已經安裝了 MetalLB 並瞭解了其元件的工作原理,讓我們在 KinD 叢集上建立第一個 LoadBalancer 服務。
步驟 1:建立 NGINX 佈署
首先,我們需要建立一個 NGINX 佈署。可以使用以下命令快速建立:
kubectl run nginx-web --image bitnami/nginx
步驟 2:建立 LoadBalancer 服務
接下來,我們需要建立一個新的服務,該服務將使用 LoadBalancer 型別。可以透過建立一個新的 manifest 檔案或僅使用 kubectl 暴露佈署。
建立一個名為 nginx-lb.yaml 的檔案,並新增以下內容:
apiVersion: v1
kind: Service
metadata:
name: nginx-lb
spec:
ports:
- port: 8080
targetPort: 8080
selector:
run: nginx-web
type: LoadBalancer
步驟 3:應用 manifest 檔案
使用 kubectl 將檔案應用到叢集:
kubectl apply -f nginx-lb.yaml
步驟 4:驗證服務建立
列出服務以驗證是否正確建立了新的 LoadBalancer 服務:
kubectl get services
將看到一個新的 LoadBalancer 服務被建立,並且 MetalLB 從組態的 IP 地址池中分配了一個 IP 位址。
檢視 controller 日誌,可以驗證 MetalLB controller 分配了 IP 位址:
{"caller":"service.go:114","event":"ipAllocated","ip":"172.16.200.100","msg":"IP address assigned by controller","service":"default/nginx-lb","ts":"2020-04-25T23:54:03.668948668Z"}
步驟 5:測試服務
現在可以使用 curl 命令測試服務,使用分配給服務的 IP 位址和埠 8080:
curl 172.17.200.100:8080
圖表翻譯:MetalLB 元件互動圖示
圖表翻譯: 此圖示展示了 MetalLB 的 Speaker 和 Controller 元件之間的互動作用。Speaker 負責宣告 LoadBalancer 服務,而 Controller 負責分配 IP 位址並更新服務狀態。ETCD 用於儲存服務狀態。
Layer 4 負載平衡器與 MetalLB 多 IP Pool 設定
在 Kubernetes 叢集中,MetalLB 提供了一個強大的 Layer 4 負載平衡解決方案。透過 MetalLB,可以將應用服務暴露給外部網路,而不僅僅依賴 Layer 7 的負載平衡器。
為 MetalLB 新增多個 IP Pool
在某些場景下,您可能需要為不同的服務提供不同的子網路。例如,當您最初為服務建立了一個 IP 範圍,但後來發現這個範圍不夠用時,您就需要擴充套件或新增 IP 範圍。
編輯 ConfigMap 並新增 IP Pool
首先,編輯 metallb-config.yaml 檔案,新增新的 IP 範圍資訊:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 172.17.200.100-172.17.200.125
- name: subnet-201
protocol: layer2
addresses:
- 172.17.201.100-172.17.201.125
套用更新後的 ConfigMap:
kubectl apply -f metallb-config.yaml
這樣,MetalLB 就擁有了兩個 IP Pool:default 和 subnet-201。
從新的 IP Pool 建立服務
要從 subnet-201 Pool 建立一個新的服務,需要在服務請求中新增註解。以下是一個範例:
apiVersion: v1
kind: Service
metadata:
name: nginx-lb2
annotations:
metallb.universe.tf/address-pool: subnet-201
spec:
ports:
- port: 8080
targetPort: 8080
selector:
run: nginx-web
type: LoadBalancer
建立服務:
kubectl apply -f nginx-lb2.yaml
驗證服務是否被分配了來自 subnet-201 Pool 的 IP 位址:
kubectl get services
使用多個 IP Pool 的好處
擁有不同的 IP Pool 可以讓您根據服務型別分配特定的 IP 位址區塊。例如,您可以將一個 IP Pool 用於網頁服務,另一個用於資料函式庫服務等。
在 MetalLB 中使用多協定
預設情況下,Kubernetes 的 Service 物件不支援多協定(例如同時使用 TCP 和 UDP)。然而,MetalLB 提供了一個解決方案:建立兩個不同的 Service 物件,一個用於 TCP,另一個用於 UDP。
建立多協定服務的步驟
- 建立兩個 Service 物件,分別用於 TCP 和 UDP。
- 為每個 Service 物件指定不同的協定。
例如,為 CoreDNS 建立一個同時支援 TCP 和 UDP 的服務:
# TCP Service
apiVersion: v1
kind: Service
metadata:
name: coredns-tcp
spec:
ports:
- port: 53
targetPort: 53
protocol: TCP
selector:
app: coredns
type: LoadBalancer
# UDP Service
apiVersion: v1
kind: Service
metadata:
name: coredns-udp
spec:
ports:
- port: 53
targetPort: 53
protocol: UDP
selector:
app: coredns
type: LoadBalancer
圖表說明
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title MetalLB 多 IP Pool 與多協定負載平衡設定
package "網路架構" {
package "應用層" {
component [HTTP/HTTPS] as http
component [WebSocket] as ws
component [gRPC] as grpc
}
package "傳輸層" {
component [TCP] as tcp
component [UDP] as udp
component [TLS/SSL] as tls
}
package "網路層" {
component [IP] as ip
component [ICMP] as icmp
component [路由協議] as routing
}
package "鏈路層" {
component [Ethernet] as eth
component [WiFi] as wifi
component [ARP] as arp
}
}
http --> tcp
ws --> tcp
grpc --> tcp
tcp --> tls : 加密
tls --> ip
udp --> ip
ip --> routing
routing --> eth
routing --> wifi
eth --> arp
@enduml
圖表翻譯: 此圖示展示了客戶端如何透過 LoadBalancer 同時存取 CoreDNS 的 TCP 和 UDP 服務,最終將請求轉發到 CoreDNS Pod。
使用MetalLB實作多協定負載平衡
在Kubernetes叢集中,佈署服務時常常需要使用多種協定,例如TCP和UDP。然而,預設的LoadBalancer服務型別在多協定支援上存在限制。本章節將探討如何使用MetalLB來解決這一問題,並以CoreDNS為例,展示如何組態多協定的LoadBalancer服務。
MetalLB的多協定支援
MetalLB透過引入allow-shared-ip註解,支援為多個服務分配相同的IP地址,從而實作多協定的負載平衡。這一功能對於需要同時使用TCP和UDP協定的服務(如DNS服務)至關重要。
組態CoreDNS的多協定LoadBalancer服務
要為CoreDNS組態多協定的LoadBalancer服務,需要建立兩個獨立的服務:一個用於TCP協定,另一個用於UDP協定。並且,這兩個服務必須使用相同的allow-shared-ip註解值,以確保它們分享同一個IP地址。
步驟1:檢視kube-system名稱空間中的服務
首先,檢視kube-system名稱空間中的現有服務:
kubectl get svc -n kube-system
這將列出該名稱空間下的所有服務,包括預設的kube-dns服務。
步驟2:建立TCP和UDP服務的Manifest檔案
建立兩個Manifest檔案:coredns-tcp.yaml和coredns-udp.yaml,分別定義TCP和UDP協定的服務。
coredns-tcp.yaml
apiVersion: v1
kind: Service
metadata:
name: coredns-tcp
namespace: kube-system
annotations:
metallb.universe.tf/allow-shared-ip: "coredns-ext"
spec:
selector:
k8s-app: kube-dns
ports:
- name: dns-tcp
port: 53
protocol: TCP
targetPort: 53
type: LoadBalancer
coredns-udp.yaml
apiVersion: v1
kind: Service
metadata:
name: coredns-udp
namespace: kube-system
annotations:
metallb.universe.tf/allow-shared-ip: "coredns-ext"
spec:
selector:
k8s-app: kube-dns
ports:
- name: dns-udp
port: 53
protocol: UDP
targetPort: 53
type: LoadBalancer
#### 內容解密:
- 這兩個Manifest檔案定義了兩個LoadBalancer型別的服務,分別用於TCP和UDP協定。
metadata.annotations中的metallb.universe.tf/allow-shared-ip註解確保了兩個服務分享同一個IP地址。spec.selector欄位指定了服務選擇器,以選擇正確的Pod。spec.ports欄位定義了服務的埠和協定。
步驟3:套用Manifest檔案
使用kubectl apply命令套用這兩個Manifest檔案:
kubectl apply -f coredns-tcp.yaml
kubectl apply -f coredns-udp.yaml
步驟4:驗證服務組態
套用Manifest檔案後,檢視kube-system名稱空間中的服務,以驗證兩個新服務是否已正確建立並分配了相同的IP地址:
kubectl get svc -n kube-system
這將顯示兩個新的服務:coredns-tcp和coredns-udp,並且它們應該具有相同的外部IP地址。
使用external-dns實作外部DNS解析
雖然MetalLB提供了負載平衡功能,但它並不提供DNS解析。要實作外部可存取的服務名稱,需要使用Kubernetes的external-dns專案。該專案支援多種DNS伺服器,包括Google Cloud DNS、Amazon Route 53、Azure DNS等。
external-dns的主要功能
- 自動為LoadBalancer服務建立DNS記錄。
- 支援多種DNS提供者。
透過結合MetalLB和external-dns,可以為Kubernetes叢集中的服務提供完整的負載平衡和DNS解析解決方案,從而提升叢集的可存取性和管理效率。