使用 MetalLB 設定套裝組合負載平衡

本頁說明如何為 Google Distributed Cloud 設定與 MetalLB 搭配使用的套裝負載平衡。MetalLB 負載平衡器會在專屬的工作站節點集區中運作,也可以與控制層位於相同的節點。

如需 Google Distributed Cloud 提供的負載平衡拓撲範例,請參閱負載平衡器總覽

需求條件

  • 所有負載平衡器節點都必須位於同一個第 2 層子網路。
  • 所有 VIP 都必須位於負載平衡器節點子網路中,且可透過子網路的閘道路由。
  • 負載平衡器子網路的閘道必須監聽無故 ARP 訊息,並將 ARP 封包轉送至負載平衡器節點。

設定欄位

編輯叢集設定檔的 cluster.spec.loadBalancer 區段,設定隨附的負載平衡功能。如要瞭解叢集設定檔和有效設定的範例,請參閱下列其中一個頁面:

loadBalancer.mode

如要啟用組合式負載平衡,這個值必須為 bundled

loadBalancer.ports.controlPlaneLBPort

這個值會指定 Kubernetes 控制層 (Kubernetes API 伺服器) 接收流量適用的目的地通訊埠。

loadBalancer.vips.controlPlaneVIP

這個值會指定 Kubernetes 控制層 (Kubernetes API 伺服器) 接收流量適用的目的地 IP 位址。這個 IP 位址必須與叢集中的節點位於同一個第 2 層子網路。請勿在設定檔的 address pools 區段中列出這個地址。

loadBalancer.vips.ingressVIP

這個值會指定負載平衡器後方服務的 IP 位址,用於輸入流量。管理員叢集設定檔不得包含這個欄位。這個位址必須列在設定的「位址集區」部分。

loadBalancer.addressPools

設定的這部分包含一或多個位址集區。每個位址集區都會指定 IP 位址範圍清單。建立LoadBalancer 類型的 Service 時,系統會從這些範圍中選擇 Service 的外部 IP 位址。

地址集格式如下:

- name: POOL_NAME
  avoidBuggyIPs: BOOLEAN
  manualAssign: BOOLEAN
  addresses:
  - IP_RANGE
  - IP_RANGE2
  • name:地址集區的名稱 (pool-name),僅供機構內部使用。這個欄位無法變更。
  • avoidBuggyIPs:(選用) truefalse。如果為 true,集區會省略以 .0.255 結尾的 IP 位址。部分網路硬體會捨棄傳送至這些特殊位址的流量。你可以省略這個欄位,預設值為 false。這個欄位可變更。
  • manualAssign:(選用) truefalse。如果 true,系統不會自動將這個集區中的位址指派給 Kubernetes 服務。如果 true,只有在服務明確指定時,才會使用這個集區中的 IP 位址。您可以省略這個欄位,預設值為 false。這個欄位可變更。
  • addresses 一或多個不重疊 IP 位址範圍的清單。ip-range 可以 CIDR 標記法 (如 198.51.100.0/24) 或範圍標記法 (如 198.51.100.0-198.51.100.10,破折號周圍不得有空格) 指定。這個欄位無法變更。

addresses 清單中的 IP 位址範圍不得重疊,且必須與執行負載平衡器的節點位於同一個子網路。

loadBalancer.nodePoolSpec

這項設定會指定要執行負載平衡器的節點清單。根據預設,負載平衡器節點可以執行一般工作負載,這些節點上沒有特殊汙點。雖然負載平衡器節點集區中的節點可以執行工作負載,但與工作站節點集區中的節點不同。您無法將特定叢集節點納入多個節點集區。節點集區之間若有節點 IP 位址重疊,會導致叢集無法建立,以及其他叢集作業無法執行。

如要防止工作負載在負載平衡器節點集區的節點上執行,請在節點中新增下列汙點:

node-role.kubernetes.io/load-balancer:NoSchedule

Google Distributed Cloud 會為負載平衡所需的 Pod 新增此汙點的容許度。

以下範例顯示具有兩個節點的負載平衡節點集區。第一個節點具有標準 IP 位址 nodePoolSpec.nodes.address (「1.2.3.4」) 和 Kubernetes IP 位址 nodePoolSpec.nodes.k8sIP (10.0.0.32)。為節點指定選用的 k8sIP 位址時,該位址會專門處理節點的資料流量,例如 Kubernetes API、kubelet 和工作負載的要求和回應。在這種情況下,標準 IP 位址 nodePoolSpec.nodes.address 會用於節點的 SSH 連線,以進行管理叢集作業。如未指定 k8sIP 位址,標準節點 IP 位址會處理節點的所有流量。

nodePoolSpec:
  nodes:
  - address: 1.2.3.4
    k8sIP: 10.0.0.32
  - address: 10.0.0.33

根據預設,負載平衡器節點集區中的所有節點,都必須與設定檔 loadBalancer.addressPools 區段中設定的負載平衡器 VIP 位於同一個第 2 層子網路。不過,如果您為節點指定 Kubernetes IP 位址 k8sIP,則只有該位址需要與其他負載平衡器 VIP 位於相同的第 2 層子網路。

如果未設定 nodePoolSpec,系統會透過控制層節點執行隨附的負載平衡器。建議您盡可能在不同的節點集區上執行負載平衡器。

控制層負載平衡

控制層負載平衡器會提供控制層虛擬 IP 位址 (VIP)。Google Distributed Cloud 會在負載平衡器節點上,以 Kubernetes 靜態 Pod 形式執行 Keepalived 和 HAProxy,藉此發布控制層 VIP。Keepalived 會在負載平衡器節點上使用 Virtual Router Redundancy Protocol (VRRP),確保高可用性。

資料平面負載平衡

資料平面負載平衡器適用於所有類型為 LoadBalancer 的 Kubernetes 服務。Google Distributed Cloud 會使用以第 2 層模式執行的 MetalLB,進行資料平面負載平衡。資料層負載平衡只能透過 Google Distributed Cloud 設定,請勿直接修改 MetalLB ConfigMap。您可以使用所有 MetalLB 功能,包括在服務之間共用 IP 位址。如需功能資訊,請參閱 MetalLB 說明文件。

MetalLB 會使用 daemonset 在每個節點上執行 speaker Pod,並使用成員清單確保高可用性。每個 Kubernetes 服務都有專屬的 MetalLB 負載平衡器節點,而不是整個叢集共用一個。如果有多項服務,流量就會以這種方式分配到負載平衡器節點。

資料層負載平衡器可以在控制層節點或部分工作站節點上執行。將資料層負載平衡器與控制層節點綁在一起,可提高控制層節點的利用率。此外,在控制層節點上進行組合也會增加控制層過載的風險,並提高控制層上機密資訊 (例如 SSH 金鑰) 的風險狀況。

負載平衡器分離

在 1.32 版之前,使用 MetalLB 設定第 2 層負載平衡時,控制層負載平衡器和資料層負載平衡器會在相同節點上執行。視設定而定,負載平衡器會在控制層節點上執行,或是在負載平衡器節點集區中執行。

下圖顯示預設的隨附負載平衡器設定,其中控制層和資料層負載平衡器都在控制層節點上執行,或都在負載平衡器節點集區中執行:

預設負載平衡器設定

在 1.32 版叢集中,您可以設定控制層負載平衡器在控制層節點上執行,並設定資料層負載平衡器在負載平衡器節點集區中執行。建立 1.32 版叢集時,您可以指定負載平衡器是否要分開,也可以更新 1.32 版叢集,將資料層負載平衡器從控制層節點遷移至負載平衡器節點集區。

分離式負載平衡器的叢集設定應類似下列範例:

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: hybrid-ha-lb
  namespace: cluster-hybrid-ha-lb
spec:
  type: hybrid
  profile: default
  anthosBareMetalVersion: 1.32
  gkeConnect:
    projectID: project-fleet
  controlPlane:
    loadBalancer:
      mode: bundled
    nodePoolSpec:
      nodes:
      - address: 10.200.0.2
      - address: 10.200.0.3
      - address: 10.200.0.4
  clusterNetwork:
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - 10.96.0.0/20
  ...
  loadBalancer:
    mode: bundled
    ...
    nodePoolSpec:
      nodes:
      - address: 10.200.0.5
      - address: 10.200.0.6
      - address: 10.200.0.7
  clusterOperations:
  ...

建立叢集時使用獨立負載平衡器

如果您要建立 1.32 以上版本的新叢集,可以設定負載平衡器,在控制層節點上執行控制層負載平衡器,並在負載平衡器節點集區上執行資料層負載平衡器。

下圖顯示控制層和資料層負載平衡器分別位於不同節點:

控制層和資料層負載平衡器分開

如要在建立叢集時區隔負載平衡器,請按照下列步驟操作:

  1. 在叢集設定檔中,指定具有 loadBalancer.nodePoolSpec 的負載平衡器節點集區,如本文的「loadBalancer.nodePoolSpec」一節所述。

  2. controlPlane.loadBalancer.mode 新增至叢集設定檔,並將 mode 值設為 bundled

  3. 完成叢集設定,然後執行 bmctl create cluster 建立叢集。

將資料層負載平衡器從控制層遷移

如果您有現有的 1.32 以上版本叢集,且未設定 controlPlane.loadBalancer.modeloadBalancer.nodePoolSpec,控制層負載平衡器和資料層負載平衡器都會在控制層節點集區中執行。您可以更新叢集,將資料平面負載平衡器遷移至負載平衡器節點集區。

下圖顯示資料層負載平衡器從控制層節點遷移後,控制層和資料層負載平衡器如何分離:

資料層負載平衡器已遷移至負載平衡器節點集區

如要在更新叢集時,將資料平面負載平衡器遷移至負載平衡器節點集區,請按照下列步驟操作:

  1. 在叢集設定檔中,指定具有 loadBalancer.nodePoolSpec 的負載平衡器節點集區,如本文的「loadBalancer.nodePoolSpec」一節所述。

  2. controlPlane.loadBalancer.mode 新增至叢集設定檔,並將 mode 值設為 bundled

  3. 執行下列指令來更新叢集:

    bmctl update cluster -c CLUSTER_NAME --kubeconfig=ADMIN_KUBECONFIG
    

    更改下列內容:

    • CLUSTER_NAME:您要更新的叢集名稱。

    • ADMIN_KUBECONFIG:管理員叢集 kubeconfig 檔案的路徑。

保留用戶端來源 IP 位址

使用隨附的第 2 層負載平衡解決方案建立的 LoadBalancer Service,會使用外部流量政策的預設 Cluster 設定。這項設定 (spec.externalTrafficPolicy: Cluster) 會將外部流量轉送至叢集範圍端點,但也會遮蓋用戶端來源 IP 位址。

Google Distributed Cloud 支援兩種保留用戶端來源 IP 位址的方法:

  • 將負載平衡的轉送模式設為伺服器直接回傳 (DSR)。如要進一步瞭解 DSR 轉送模式,包括如何啟用這項模式,請參閱「設定負載平衡轉送模式」。

  • LoadBalancer 服務的外部流量政策設為本機,並相應設定相關服務和 Ingress。以下各節說明如何設定叢集,以使用這種方法。

LoadBalancer 服務

LoadBalancer 服務中使用 externalTrafficPolicy: Local 時,請將應用程式 Pod 設為在負載平衡器節點上執行。將下列 nodeSelector 新增至應用程式 Pod,即可進行這項變更:

apiVersion: v1
kind: Pod
...
spec:
  nodeSelector:
      baremetal.cluster.gke.io/lbnode: "true"
...

NodePort 服務

Kubernetes 會對 NodePort 執行來源網路位址轉譯 (SNAT)。如要保留用戶端來源 IP 位址,請將 service.spec.externalTrafficPolicy 設為 Local。Kubernetes 不會再執行 SNAT,但您必須確保所選節點 IP 上有 Pod 正在執行。

Ingress

如果您的應用程式是 HTTP 服務,可以設定 Ingress 元件,讓用戶端 IP 位址可見:

  1. 開啟 istio-ingress 服務進行編輯:

    kubectl edit service -n gke-system istio-ingress
    
  2. spec 中新增 externalTrafficPolicy: Local,然後儲存並結束編輯器。

    apiVersion: v1
    kind: Service
    ...
    spec:
    ...
      externalTrafficPolicy: Local
    
  3. 開啟 istio-ingress Deployment 進行編輯:

    kubectl edit deployment -n gke-system istio-ingress
    
  4. 將下列 nodeSelector 新增至 Deployment,然後儲存並結束編輯器。

    apiVersion: apps/v1
    kind: Deployment
    ...
    spec:
      ...
      template:
        ...
        spec:
          ...
          nodeSelector:
              baremetal.cluster.gke.io/lbnode: "true"
    ...
    

現在,Ingress 後方的所有服務都會看到含有用戶端 IP 的 X-Forwarded-For 標頭,如下例所示:

X-Forwarded-For: 21.0.104.4