MetalLB を使用してバンドルされたロード バランシングを構成する

このページでは、Google Distributed Cloud の MetalLB を使用してバンドル型ロード バランシングを構成する方法について説明します。MetalLB ロードバランサは、ワーカーノードの専用プールまたはコントロール プレーンと同じノード上で動作します。

Google Distributed Cloud で使用可能なロード バランシング トポロジの例については、ロードバランサの概要をご覧ください。

要件

  • すべてのロードバランサ ノードは、同じレイヤ 2 サブネット内にある必要があります。
  • すべての VIP は、ロードバランサのノードのサブネット内に存在し、サブネットのゲートウェイを介してルーティング可能である必要があります。
  • ロードバランサのサブネットのゲートウェイは、Gratuitous 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

この値は、上り(内向き)トラフィック用ロードバランサの背後にある Service に使用する IP アドレスを指定します。管理クラスタ構成ファイルでは、このフィールドを使用できません。このアドレスは、構成の [アドレスプール] セクションに記述する必要があります。

loadBalancer.addressPools

構成のこのセクションには、1 つ以上のアドレスプールが含まれています。各アドレスプールで、IP アドレス範囲のリストを指定します。LoadBalancer 型の Service を作成すると、Service の外部 IP アドレスはそれらの範囲から選択されます。

アドレスプールは次の形式で指定します。

- name: POOL_NAME
  avoidBuggyIPs: BOOLEAN
  manualAssign: BOOLEAN
  addresses:
  - IP_RANGE
  - IP_RANGE2
  • name: ご自身の組織の目的に適したアドレスプールの名前(pool-name)。このフィールドは変更できません。
  • avoidBuggyIPs: (省略可)true または falsetrue の場合は、末尾が .0.255 の IP アドレスがプールから除外されます。一部のネットワーク ハードウェアは、これらの特別なアドレスへのトラフィックをドロップします。このフィールドは省略できます。デフォルト値は false です。このフィールドは変更可能です。
  • manualAssign: (省略可)true または falsetrue の場合、このプール内のアドレスは Kubernetes Service に自動的に割り当てられません。true の場合、このプール内の IP アドレスは、Service によって明示的に指定された場合にのみ使用されます。このフィールドは省略できます。デフォルト値は false です。このフィールドは変更可能です。
  • addresses 重複しない 1 つ以上の IP アドレス範囲のリスト。ip-range は、CIDR 表記(198.51.100.0/24 など)または範囲表記(198.51.100.0-198.51.100.10 など。ダッシュの前後にスペースなし)で指定します。このフィールドは変更できません。

addresses リストの IP アドレス範囲は重複していてはならず、ロードバランサを実行しているノードと同じサブネット内に存在する必要があります。

loadBalancer.nodePoolSpec

構成のこのセクションでは、ロードバランサを実行するノードのリストを指定します。ロードバランサ ノードは、デフォルトで通常のワークロードを実行できます。これらのノードには特別な taint はありません。ロードバランサ ノードプール内のノードはワークロードを実行できますが、ワーカー ノードプール内のノードとは分離されています。特定のクラスタノードを複数のノードプールに含めることはできません。ノードプール間でノード IP アドレスが重複すると、クラスタの作成などのクラスタ オペレーションがブロックされます。

ロードバランサ ノードプール内のノードでワークロードが実行されないようにするには、次の taint をノードに追加します。

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

Google Distributed Cloud は、ロード バランシングに必要な Pod にこの taint の toleration を追加します。

次の例は、2 つのノードを含むロード バランシング ノードプールを示しています。最初のノードには、標準 IP アドレス nodePoolSpec.nodes.address(「1.2.3.4」)と Kubernetes IP アドレス nodePoolSpec.nodes.k8sIP10.0.0.32)が設定されています。ノードにオプションの k8sIP アドレスを指定すると、Kubernetes API、kubelet、ワークロードのリクエストやレスポンスなど、ノードのデータ トラフィックの処理専用になります。この場合、管理クラスタ オペレーションでのノードへの SSH 接続には、標準 IP アドレス nodePoolSpec.nodes.address が使用されます。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 Service を対象としています。Google Distributed Cloud は、レイヤ 2 モードで実行される MetalLB を使用してデータプレーンのロード バランシングを行います。データプレーンのロード バランシングは、Google Distributed Cloud を介してのみ構成できます。MetalLB ConfigMap を直接変更しないでください。サービス間での IP アドレス共有など、すべての MetalLB 機能を使用できます。機能の詳細については、MetalLB のドキュメントをご覧ください。

MetalLBL は、デーモンセットを使用して各ノードでスピーカー Pod を実行し、高可用性のために memberlist を使用します。クラスタごとにではなく、Kubernetes Service ごとに専用の MetalLB 専用のロードバランサ ノードがあります。この方法により、複数のサービスがある場合、トラフィックはロードバランサ ノード間で分散されます。

データ プレーン ロードバランサは、コントロール プレーン ノードで、またはワーカーノードのサブセットで実行できます。コントロール プレーン ノードでデータプレーン ロードバランサのバンドルを行うと、コントロール プレーン ノードの使用率が増えます。ただし、コントロール プレーン ノードでバンドルを行うと、コントロール プレーンが過負荷になるリスクが高まり、SSH 認証鍵など、コントロール プレーン上の機密情報のリスク プロファイルが増大します。

クライアントの送信元 IP アドレスの保持

バンドルされたレイヤ 2 ロード バランシング ソリューションで作成された LoadBalancer Service は、外部トラフィック ポリシーのデフォルトの Cluster 設定を使用します。この設定 spec.externalTrafficPolicy: Cluster は、クラスタ全体のエンドポイントに外部トラフィックを転送しますが、クライアント送信元 IP アドレスは不明瞭になります。

以降のセクションでは、クライアントの送信元 IP アドレスを保持するようにクラスタを構成する方法について説明します。

NodePort Service

Kubernetes は、NodePort Service に送信元ネットワーク アドレス変換(SNAT)を行います。クライアントの送信元 IP アドレスを保持するには、service.spec.externalTrafficPolicyLocal に設定します。Kubernetes は SNAT を実行しなくなりますが、選択したノード IP で実行中の Pod があることを確認する必要があります。

LoadBalancer Service

LoadBalancer Service で externalTrafficPolicy: Local を使用するときは、ロードバランサ ノードで確実に実行されるようにアプリケーション Pod を設定します。この変更を行うには、次の nodeSelector をアプリケーション Pod に追加します。

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

Ingress

アプリケーションが HTTP サービスである場合は、Ingress コンポーネントを構成することで、クライアント IP の可視性を実現できます。

  1. istio-ingress Service を編集用に開きます。

    kubectl edit service -n gke-system istio-ingress
  2. externalTrafficPolicy: Localspec に追加し、エディタを保存して終了します。

    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