iT邦幫忙

2025 iThome 鐵人賽

DAY 20
1
DevOps

牧場主的 K8s 放牧日記系列 第 20

Day 20: MetalLB 負載均衡實戰 - 牧場的智慧流量分配系統

  • 分享至 

  • xImage
  •  

牧場主今日工作

今天要來建立牧場的智慧流量分配系統!就像牧場主需要設計多條道路讓訪客能順利進入不同的牛舍,而不會在單一入口造成大塞車,MetalLB 就是 Kubernetes 世界的交通管制中心。在地端環境中,我們沒有雲端供應商提供的 LoadBalancer 服務,MetalLB 正是解決這個問題的最佳方案,讓我們的 Service 也能擁有真正的外部 IP!

技術背景與概念

LoadBalancer Service 的地端困境

在雲端環境中,當你建立 type: LoadBalancer 的 Service 時,雲端供應商會自動幫你配置負載均衡器和外部 IP。但在地端環境中,Service 本身會正常建立並運作,只是 EXTERNAL-IP 欄位會一直顯示 <pending> 狀態,因為沒有任何組件負責提供外部 IP 地址。此時 Service 仍可透過 ClusterIP 或 NodePort 的方式正常存取。

傳統地端解決方案的限制

  • NodePort
    • 需要記住隨機分配的高端口號(30000-32767),不適合正式服務
    • 直接進入節點,繞過 Ingress Controller,無法記錄存取日誌
    • 存在資安疑慮,難以進行流量監控和安全控管
  • externalIPs
    • 手動指定外部 IP 地址,需要確保該 IP 能路由到節點
    • 存在單點故障問題,IP 綁定到特定節點
    • 缺乏自動化管理,IP 衝突風險高
    • 節點故障時需要手動重新配置
    • 重要警告:在 IPVS 模式下,絕對不可使用節點本身的 IP 作為 externalIPs,會導致集群網路崩潰
  • Ingress + NodePort:需要額外的 Ingress Controller 配置,增加架構複雜度

NodePort vs externalIPs 實務比較

# NodePort 適用場景:
- 開發測試環境快速存取
- 臨時性的服務暴露
- 不在意端口號的內部工具

# externalIPs 適用場景:
- 需要固定 IP 和標準端口 (80/443)
- 有現成的外部 IP 資源
- 願意手動管理 IP 分配

# 兩者共同問題:
- 缺乏企業級的負載均衡和故障轉移
- 難以整合監控和日誌系統
- 無法提供雲端級的服務體驗

# 社群技術專家觀點:
- externalIPs 被認為是「規格不足的安全蟲洞」
- 允許非管理員使用者直接對節點網路程式設計
- LoadBalancer + Controller 是更安全的權限控制模型

MetalLB:地端 LoadBalancer 的救星

https://ithelp.ithome.com.tw/upload/images/20250903/20141794Nta5UFnZtf.png

MetalLB 是專門為裸機(Bare Metal)Kubernetes 集群設計的負載均衡器實現,它使用標準的網路協議來實現真正的 LoadBalancer 功能。

MetalLB 核心價值

  • 讓地端 Kubernetes 也能使用 type: LoadBalancer
  • 自動分配和管理外部 IP 地址
  • 使用標準路由協議,無需專有硬體
  • 與雲端 LoadBalancer 相同的使用體驗
  • 安全設計:採用 Controller 模式,避免 externalIPs 的潛在安全風險
  • 權限控制:由系統管理員統一管理 IP 池,而非使用者直接操作節點網路

MetalLB 核心架構

雙核心組件設計

MetalLB 採用簡潔的雙組件架構:

1. Controller(控制器)

  • 部署方式:Deployment,通常單一實例
  • 核心職責
    • 監聽 LoadBalancer Service 的創建/更新/刪除事件
    • 從 IP 地址池中分配可用的外部 IP
    • 管理 IP 地址的生命週期
    • 處理 Service 與 IP 的綁定關係

2. Speaker(廣播器)

  • 部署方式:DaemonSet,每個節點都運行
  • 核心職責
    • 對外廣播 Service 的外部 IP 地址
    • 根據配置選擇廣播方式:
      • Layer 2 模式:透過 ARP 回應告訴外部「這個 IP 在我這台機器上」
      • BGP 模式:透過 BGP 協議告訴路由器「要到這個 IP 請走我這條路」
    • 處理外部流量路由到正確的節點

架構圖示
https://ithelp.ithome.com.tw/upload/images/20250903/20141794RDv6McVdxS.png

工作模式詳解

MetalLB 提供兩種工作模式,適用於不同的網路環境:

Layer 2 模式(ARP/NDP 廣播)

工作原理
Layer 2 模式通過 ARP(Address Resolution Protocol,地址解析協議) 響應來告知外部網路「這個 IP 地址在我這台機器上」。

技術名詞解釋

  • ARP (Address Resolution Protocol 地址解析協議)
    • 用來找出「IP 地址對應到哪張網卡」的協議
    • 當設備要傳送資料時,知道目標 IP 但不知道實際網卡位置
    • 會在區域網路廣播:「誰有這個 IP?請告訴我你的 MAC 地址」
    • 有該 IP 的設備會回應:「我有!我的 MAC 是 xx:xx:xx:xx:xx:xx」
  • NDP (Neighbor Discovery Protocol):IPv6 版本的 ARP,功能類似但協議不同
  • MAC 地址:每張網卡的唯一硬體識別碼,像是網卡的身分證號碼

流程示例
https://ithelp.ithome.com.tw/upload/images/20250903/20141794lQwjvq6CYu.png

優缺點分析

  • 優點

    • 不需要特殊的網路設備,任何交換器都支援
    • 配置簡單,適合小型環境
    • 不需要了解複雜的路由協議
  • 缺點

    • 單節點瓶頸:同一時間只有一個節點處理該 IP 的流量
    • 故障轉移慢:節點故障時需要等待 ARP 快取過期
    • 不是真正的負載均衡:更像是主備模式的故障轉移

BGP 模式(邊界閘道協議)

工作原理
BGP 模式使用 BGP (Border Gateway Protocol,邊界閘道協議) 向路由器廣播路由信息,告知外部網路「要到達這個 IP,請走這條路」。

技術名詞解釋

  • BGP:互聯網上最重要的路由協議,用於在不同的自治系統間交換路由信息
  • AS (Autonomous System):自治系統編號,用於標識不同的網路區域
  • BGP Peer:建立 BGP 連接的兩端設備
  • 路由廣播:向其他設備告知「我知道如何到達某個網路」

流程示例
https://ithelp.ithome.com.tw/upload/images/20250903/20141794cyv1Z5nh4N.png

優缺點分析

  • 優點

    • 真正的負載均衡:多個節點同時處理流量
    • 快速故障轉移:路由器能立即發現節點故障
    • 擴展性好:適合大型生產環境
  • 缺點

    • 設備要求高:需要支援 BGP 的路由器
      • 企業級路由器:Cisco ISR 4000 系列、Juniper SRX 系列、HP Aruba 系列
      • 開源軟體路由器:pfSense (FreeBSD)、OpenWrt、VyOS
      • 雲端環境:AWS VGW、Azure ExpressRoute、GCP Cloud Router
      • ❌ 不支援:家用路由器(TP-Link、ASUS、Netgear 等消費級產品)
    • 配置複雜:需要了解 BGP 協議和路由配置
    • 連接重排:節點變動可能導致現有連接中斷

模式選擇建議

# 選擇 Layer 2 模式的情況:
- 小型環境(< 10 節點)
- 使用一般的交換器設備
- 家用路由器環境(如 TP-Link、ASUS、Netgear 等)
- 對高可用性要求不嚴格
- 網路管理員不熟悉 BGP 協議

# 選擇 BGP 模式的情況:
- 大型生產環境
- 有企業級路由器支援 BGP
- 需要真正的負載均衡
- 對故障轉移時間要求嚴格

# 本文實驗環境:
- 使用 TP-Link 家用路由器,因此選擇 Layer 2 模式
- 適合個人學習和小型實驗環境

在 RKE2 環境中部署 MetalLB

環境準備檢查

在安裝 MetalLB 前,需要確認幾個重要的前置條件:

1. Kubernetes 版本檢查

# 檢查 K8s 版本(需要 v1.13.0 或以上)
kubectl version --short

# 輸出範例:
# Server Version: v1.28.8+rke2r1

2. RKE2 kube-proxy 設定檢查

RKE2 預設使用 iptables 模式,如果要使用 IPVS 模式才需要特殊配置:

# RKE2 中檢查 kube-proxy 模式
kubectl get nodes -o wide

# 直接查看 kube-proxy 進程參數(最可靠的方法)
ps aux | grep kube-proxy

# 檢查目前使用的代理模式
ps aux | grep kube-proxy | grep -o "proxy-mode=[a-z]*"

# 如果輸出是 proxy-mode=iptables,表示使用 iptables 模式
# 如果輸出是 proxy-mode=ipvs,表示使用 IPVS 模式

範例輸出解讀

# iptables 模式(RKE2 預設)
kube-proxy --proxy-mode=iptables --cluster-cidr=10.42.0.0/16 ...

# IPVS 模式(需要手動配置)  
kube-proxy --proxy-mode=ipvs --ipvs-strict-arp=true --cluster-cidr=10.42.0.0/16 ...

IPVS 模式配置(選用)

重要提醒:本文使用 iptables 模式即可,MetalLB 運作完全正常。

如果未來需要切換到 IPVS 模式,可以透過 Rancher UI 編輯集群 YAML:

spec:
  rkeConfig:
    machineGlobalConfig:
      kube-proxy-arg:
        - proxy-mode=ipvs
        - ipvs-strict-arp=true

切換後需要重新建立集群讓配置生效。

iptables vs IPVS 模式比較

技術差異解析

iptables 模式(RKE2 預設)

  • 工作原理:使用 netfilter 框架的 iptables 規則進行流量轉發
  • 規則匹配:線性掃描 iptables 規則鏈,逐一比對
  • 效能特性:規則數量增加時,查找時間線性增長 O(n)
  • 記憶體使用:相對較低
  • 穩定性:非常成熟穩定,廣泛使用

IPVS 模式(需手動啟用)

  • 工作原理:在 Linux 核心空間使用雜湊表進行負載均衡
  • 規則匹配:雜湊表查找,近似 O(1) 時間複雜度
  • 效能特性:大規模環境下效能優勢明顯
  • 記憶體使用:需要額外的核心記憶體存儲雜湊表
  • 負載均衡算法:支援多種算法(rr, lc, dh, sh, sed, nq)

效能對比

比較項目 iptables IPVS
小規模環境 ✅ 足夠快速 ⚡ 稍快但差異不大
大規模環境 ❌ 規模增長時效能下降 ✅ 效能相對穩定
CPU 使用率 較高(線性查找) 較低(雜湊查找)
記憶體使用 較低 較高
設定複雜度 簡單(預設) 複雜(需配置)

實際使用建議

# 選擇 iptables 模式的情況:
- 小型到中型集群
- 追求穩定性和簡單性
- 資源有限的環境
- 預設配置已滿足需求(推薦)

# 選擇 IPVS 模式的情況:
- 大規模生產環境
- 對效能有特殊要求
- 需要進階負載均衡算法
- 願意承擔額外的配置複雜性

# 本文實驗環境:
- 使用 RKE2 預設的 iptables 模式
- Cilium CNI 也有取代 kube-proxy 的能力
- 小規模環境下 iptables 已經足夠

MetalLB 相容性

重要資訊:無論使用哪種模式,MetalLB 都能正常運作!

  • iptables 模式:完全支援,無需額外配置
  • IPVS 模式:完全支援,但需啟用 strict ARP

技術名詞解釋

  • IPVS (IP Virtual Server):Linux 核心的負載均衡技術,提供高效能的 Layer 4 負載均衡
  • strict ARP:嚴格的 ARP 模式,避免 ARP 響應衝突,確保 MetalLB Layer 2 模式正常運作
  • netfilter:Linux 核心的封包過濾框架,iptables 是其使用者空間工具

3. CNI 兼容性確認

# 檢查目前使用的 CNI
kubectl get pods -n kube-system | grep -E "(cilium|flannel|calico|weave)"

# 確認 CNI 與 MetalLB 相容(大多數主流 CNI 都支援)

安裝 MetalLB

使用 Helm 進行安裝(推薦方式):

# 添加 MetalLB Helm repository
helm repo add metallb https://metallb.github.io/metallb

# 更新 Helm repository
helm repo update

# 安裝 MetalLB
helm install metallb metallb/metallb -n metallb-system --create-namespace

# 確認安裝狀態
kubectl get pods -n metallb-system

Helm 安裝優勢

  • 版本管理:易於升級和回滾
  • 配置靈活:可透過 values.yaml 自訂配置
  • 依賴管理:自動處理 CRD 升級
  • 狀態追蹤:透過 helm list 檢查部署狀態

檢查安裝狀態

# 檢查 Helm 部署狀態
helm list -n metallb-system

# 檢查 MetalLB CRDs 是否已建立
kubectl get crd | grep metallb

配置 IP 池和地址分配

規劃 IP 地址範圍

在配置前,需要先規劃可用的 IP 地址範圍:

IP 規劃考量

# 家用路由器環境範例:
# - 路由器通常是網段的第一個 IP (如 192.168.x.1)
# - K8s 節點分配固定 IP 範圍
# - 檢查路由器 DHCP 設定,避開自動分配範圍
# - MetalLB 使用 DHCP 範圍外的靜態 IP

# IP 規劃原則:
# 1. 不與現有設備衝突
# 2. 與集群節點在同一網段  
# 3. 避開 DHCP 保留範圍(重要!)
# 4. 建議使用網段末端的 IP 範圍

建立 IP 地址池(IPAddressPool)

# 建立 IP 地址池配置檔案
cat > metallb-ippool.yaml << 'EOF'
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: production-pool
  namespace: metallb-system
spec:
  addresses:
  # 使用範圍格式(避開 DHCP 保留範圍)
  - 192.168.0.250-192.168.0.254
  # 或者單一 IP 指定
  # - 192.168.0.250
  # - 192.168.0.251
  autoAssign: true
EOF

# 套用設定
kubectl apply -f metallb-ippool.yaml

# 確認 IP 池建立成功
kubectl get ipaddresspool -n metallb-system

技術名詞解釋

  • CIDR (Classless Inter-Domain Routing):IP 地址表示法,如 192.168.1.100/28 表示從 192.168.1.96 到 192.168.1.111
  • autoAssign:是否自動分配 IP 給 LoadBalancer Service

Layer 2 模式配置

對於大多數地端環境,Layer 2 模式是最簡單的選擇:

# 建立 Layer 2 廣播配置
cat > metallb-l2advertisement.yaml << 'EOF'
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: production-l2adv
  namespace: metallb-system
spec:
  # 關聯到指定的 IP 池
  ipAddressPools:
  - production-pool
  # 可以指定特定節點(可選)
  # nodeSelectors:
  # - matchLabels:
  #     kubernetes.io/hostname: node1
EOF

# 套用設定
kubectl apply -f metallb-l2advertisement.yaml

# 確認 L2Advertisement 建立成功
kubectl get l2advertisement -n metallb-system

LoadBalancer Service 實戰測試

部署測試應用

建立一個簡單的 nginx 測試環境:

# 建立測試應用
cat > nginx-loadbalancer-test.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-lb-test
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-lb-test
  template:
    metadata:
      labels:
        app: nginx-lb-test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            cpu: 100m
            memory: 128Mi

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-loadbalancer
  namespace: default
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: nginx-lb-test
EOF

# 部署測試應用
kubectl apply -f nginx-loadbalancer-test.yaml

驗證 LoadBalancer 功能

# 檢查 Service 狀態
kubectl get svc nginx-loadbalancer

# 注意觀察 EXTERNAL-IP 是否已分配(不再是 <pending>)

# 檢查 IP 分配詳情
kubectl describe svc nginx-loadbalancer

# 測試外部連線(IP 會是 250-254 範圍中的一個)
curl http://192.168.0.250

故障排除經驗:外部無法訪問 LoadBalancer IP

問題現象

在初次測試時遇到:

  • 集群內部:LoadBalancer IP 可正常訪問
  • 外部設備:無法訪問 LoadBalancer IP
  • NodePort:外部可正常訪問

可能原因

  1. ARP 表更新延遲:外部設備需要時間學習新的 MAC 地址映射
  2. 網路快取:路由器或交換機的 ARP 快取未及時更新
  3. CNI 初始化:MetalLB 和 Cilium 之間需要時間同步

故障排除方法

基本檢查

# 檢查 Service 是否正確分配 IP
kubectl get svc nginx-loadbalancer

# 檢查 MetalLB 狀態
kubectl get pods -n metallb-system
kubectl logs -n metallb-system -l app.kubernetes.io/component=speaker

# 檢查外部設備的 ARP 表
arp -a | grep 192.168.0.250

今日總結與明日預告

今天我們成功部署了 MetalLB 負載均衡器,讓地端 Kubernetes 集群也能享受 LoadBalancer Service 的便利!從基本概念到實際部署,從 Layer 2 到 BGP 模式,我們建立了完整的外部流量分配機制。記住選擇合適的工作模式:簡單環境用 Layer 2,企業環境考慮 BGP。

明天我們要繼續完善基礎設施,學習 Ingress Controller 的流量路由設定,建立更靈活的 HTTP/HTTPS 流量管理機制!

💡 牧場主小提示:MetalLB 就像牧場的智慧門禁系統,Layer 2 模式像是單一大門管制,BGP 模式像是多個入口分流!記住三個關鍵:IP 規劃要仔細、模式選擇看環境、監控測試不能少。有了 MetalLB,你的服務就能像雲端一樣擁有真正的外部 IP 了!


上一篇
Day 19: Cilium Network Policy 網路隔離實戰 - 牧場的智慧圍欄系統
下一篇
Day 21: Ingress Controller 流量路由實戰 - 牧場的智慧導航系統
系列文
牧場主的 K8s 放牧日記21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言