内部 TCP / UDP ロードバランサの使用

このページでは、Google Kubernetes Engine(GKE)で内部 TCP / UDP ロードバランサを作成する方法について説明します。

概要

内部 TCP / UDP ロード バランシングを使用すると、同じ VPC ネットワークを使用し、同じ Google Cloud リージョンに配置されているクラスタ外のアプリケーションに、クラスタのサービスがアクセスできるようになります。たとえば、us-west1 リージョンにクラスタを配置している場合、そのクラスタのサービスの 1 つが、同じ VPC ネットワークを使用し、このリージョンで実行されている Compute Engine 仮想マシン(VM)インスタンスにアクセスできるようになります。

内部 TCP / UDP 負荷分散を使用しない場合は、外部ロードバランサとファイアウォール ルールを設定して、クラスタの外部からアプリケーションにアクセスできるようにする必要があります。

アノテーション

内部 TCP / UDP ロードバランサを作成するには、type: LoadBalancer 仕様とアノテーションを含む Service リソースを作成します。アノテーションは、GKE クラスタのバージョンによって異なります。

GKE バージョン 1.17 以降の場合は、アノテーション networking.gke.io/load-balancer-type: "Internal" を使用します。

それよりも前のバージョンでは、アノテーション cloud.google.com/load-balancer-type: "Internal" を使用します。

アーキテクチャ

内部 TCP / UDP ロードバランサでは、Service の内部 IP アドレスが作成されます。Service はこの IP アドレスで、同じ VPC ネットワークの同じコンピューティング リージョン内に配置されているクライアントからのトラフィックを受信します。グローバル アクセスを有効にすると、同じ VPC ネットワークの任意のリージョン内に配置されているクライアントが Service にアクセスできます。また、VPC ネットワーク ピアリングを使用して LoadBalancer ネットワークに接続している VPC ネットワーク内のクライアントも Service にアクセスできます。

GKE Ingress コントローラは、ロード バランシング リソースをデプロイして管理します。GKE Ingress コントローラの詳細については、GKE Ingress コントローラの動作の概要をご覧ください。

料金

Compute Engine の料金モデルに従って課金されます。詳細については、ロードバランサと転送ルールの料金をご覧ください。また、Google Cloud 料金計算ツールに関する Compute Engine のページもご覧ください。

始める前に

作業を始める前に、次のことを確認してください。

次のいずれかの方法で gcloud のデフォルトの設定を指定します。

  • gcloud init。デフォルトの設定全般を確認する場合に使用します。
  • gcloud config。プロジェクト ID、ゾーン、リージョンを個別に設定する場合に使用します。

gcloud init の使用

エラー One of [--zone, --region] must be supplied: Please specify location を受信した場合は、このセクションの内容を実施します。

  1. gcloud init を実行して、次の操作を行います。

    gcloud init

    リモート サーバーで SSH を使用している場合は、--console-only フラグを指定して、コマンドがブラウザを起動しないようにします。

    gcloud init --console-only
  2. 手順に従って gcloud を承認し、Google Cloud アカウントを使用します。
  3. 新しい構成を作成するか、既存の構成を選択します。
  4. Google Cloud プロジェクトを選択します。
  5. ゾーンクラスタの場合はデフォルトの Compute Engine ゾーン、リージョン クラスタまたは Autopilot クラスタの場合はデフォルトの Compute Engine リージョンを選択します。

gcloud config の使用

  • デフォルトのプロジェクト ID を設定します。
    gcloud config set project PROJECT_ID
  • ゾーンクラスタを使用する場合は、デフォルトのコンピューティング ゾーンを設定します。
    gcloud config set compute/zone COMPUTE_ZONE
  • Autopilot クラスタまたはリージョン クラスタを使用する場合は、デフォルトのコンピューティング リージョンを設定します。
    gcloud config set compute/region COMPUTE_REGION
  • gcloud を最新バージョンに更新します。
    gcloud components update

Deployment の作成

以下のマニフェストは、Hello World アプリの 3 つのレプリカを実行する Deployment を記述しています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 3
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"

このサンプルアプリのソースコードと Dockerfile は GitHub で入手できます。PORT 環境変数が指定されていないため、コンテナはデフォルト ポート 8080 でリッスンします。

Deployment を作成するには、マニフェストから my-deployment.yaml ファイルを作成し、シェルまたはターミナル ウィンドウで次のコマンドを実行します。

kubectl apply -f my-deployment.yaml

内部 TCP ロードバランサを作成する

以降のセクションでは、Service を使用して内部 TCP ロードバランサを作成する方法について説明します。

Service 構成ファイルの作成

内部 TCP ロードバランサを作成する Service の例を次に示します。

apiVersion: v1
kind: Service
metadata:
  name: ilb-service
  annotations:
    networking.gke.io/load-balancer-type: "Internal"
  labels:
    app: hello
spec:
  type: LoadBalancer
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

Service の最小要件

マニフェストには次のものを含める必要があります。

  • Service の name。この場合 ilb-service です。
  • 内部 TCP / UDP ロードバランサを指定するアノテーション。アノテーションは、GKE クラスタのバージョンによって異なります。GKE バージョン 1.17 以降の場合は、アノテーション networking.gke.io/load-balancer-type: "Internal" を使用します。それよりも前のバージョンでは、アノテーション cloud.google.com/load-balancer-type: "Internal" を使用します。
  • type: LoadBalancer
  • spec: selector フィールド。Service が対象にするポッドを指定します。例: app: hello
  • port には、Service が公開されるポートを指定します。targetPort には、コンテナがリッスンするポートを指定します。

Service のデプロイ

内部 TCP ロードバランサを作成するには、マニフェストから my-service.yaml ファイルを作成し、シェルまたはターミナル ウィンドウで次のコマンドを実行します。

kubectl apply -f my-service.yaml

Service の検査

デプロイ後、Service を検査し、正常に構成されていることを確認します。

Service に関する詳細情報を取得します。

kubectl get service ilb-service --output yaml

出力の status.loadBalancer.ingress の下に、内部ロードバランサの IP アドレスが表示されます。これは、clusterIP の値と異なります。この例の場合、ロードバランサの IP アドレスは 10.128.15.193 です。

apiVersion: v1
kind: Service
metadata:
  ...
  labels:
    app: hello
  name: ilb-service
  ...
spec:
  clusterIP: 10.0.9.121
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30835
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: hello
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 10.128.15.193

app: hello というラベルを持つポッドは、この Service のメンバーです。これらは、内部ロードバランサに送信されたリクエストを最後に受信するポッドになります。

クライアントは、Service マニフェストの port フィールドに指定された loadBalancer IP アドレスと TCP ポートを使用して Service を呼び出します。リクエストは、targetPort フィールドに指定された TCP ポートのいずれかのメンバーポッドに転送されます。前の例では、クライアントは 10.128.15.193 の TCP ポート 80 で Service を呼び出します。リクエストは、いずれかのメンバーポッドの TCP ポート 8080 に転送されます。メンバーポッドには、ポート 8080 をリッスンするコンテナが必要です。

nodePort 値 30835 は無関係です。内部ロードバランサには関係ありません。

ロードバランサの転送ルールの表示

内部ロードバランサは転送ルールとして実装されています。転送ルールにはバックエンド Service が設定され、この Service にはインスタンス グループが設定されています。

内部ロードバランサのアドレス(前の例では 10.128.15.193)は転送ルールのアドレスと同じです。内部ロードバランサを実装する転送ルールを確認するには、プロジェクト内のすべての転送ルールのリストを取得します。

gcloud compute forwarding-rules list --filter="loadBalancingScheme=INTERNAL"

出力で、内部ロードバランサと同じアドレスの転送ルールを探します(この例では 10.128.15.193)。

NAME                          ... IP_ADDRESS  ... TARGET
...
aae3e263abe0911e9b32a42010a80008  10.128.15.193   us-central1/backendServices/aae3e263abe0911e9b32a42010a80008

出力には、関連するバックエンド サービスも表示されます(この例では ae3e263abe0911e9b32a42010a80008)。

バックエンド サービスの説明:

gcloud compute backend-services describe aae3e263abe0911e9b32a42010a80008 --region us-central1

出力には、関連するインスタンス グループが表示されます(この例では k8s-ig--2328fa39f4dc1b75)。

backends:
- balancingMode: CONNECTION
  group: .../us-central1-a/instanceGroups/k8s-ig--2328fa39f4dc1b75
...
kind: compute#backendService
loadBalancingScheme: INTERNAL
name: aae3e263abe0911e9b32a42010a80008
...

Service の抽象化の仕組み

パケットが転送ルールで処理されると、パケットはいずれかのクラスタノードに転送されます。パケットがクラスタノードに到着すると、アドレスとポートは次のようになります。

宛先 IP アドレス 転送ルール。この例では 10.128.15.193 です。
宛先 TCP ポート Service の port フィールド。この例では 80 です。

転送ルール(つまり内部ロードバランサ)は、宛先 IP アドレスまたは宛先ポートを変更しません。代わりに、クラスタノードの iptables ルールにより、パケットが適切なポッドにルーティングされます。iptables ルールは、宛先 IP アドレスをポッドの IP アドレスに変更し、宛先ポートを Service の targetPort 値(この例では 8080)に変更します。

内部 TCP ロードバランサの確認

VM インスタンスに SSH で接続し、次のコマンドを実行します。

curl LOAD_BALANCER_IP

LOAD_BALANCER_IP は、LoadBalancer Ingress の IP アドレスに置き換えます。

レスポンスには hello-app の出力が含まれます。

Hello, world!
Version: 2.0.0
Hostname: hello-app-77b45987f7-pw54n

同じ VPC ネットワークの外部または同じリージョンの外部からコマンドを実行すると、タイムアウト エラーが発生します。グローバル アクセスを構成すると、同じ VPC ネットワーク内の任意のリージョン内に配置されているクライアントがロードバランサにアクセスできます。

クリーンアップ

Deployment と Service を削除するには、kubectl delete または Cloud Console を使用します。

kubectl

Deployment を削除する

Deployment を削除するには、次のコマンドを実行します。

kubectl delete deployment hello-app

Service を削除する

Service を削除するには、次のコマンドを実行します。

kubectl delete service ilb-service

Console

Deployment を削除する

Deployment を削除するには、次の手順を行います。

  1. Cloud Console の [ワークロード] ページに移動します。

    [ワークロード] に移動

  2. 削除する Deployment を選択して、[ 削除] をクリックします。

  3. 確認を求められたら、[Delete Horizontal Pod Autoscaler associated with selected Deployment] チェックボックスをオンにして、[削除] をクリックします。

Service を削除する

Service を削除するには、次の手順を行います。

  1. Cloud Console の [Service と Ingress] ページに移動します。

    [Service と Ingress] に移動

  2. 削除するサービスを選択して、[ 削除] をクリックします。

  3. 確認のメッセージが表示されたら、[削除] をクリックします。

内部 TCP / UDP ロードバランサのサブセット化を使用する

GKE の内部ロードバランサ サブセット化は、バックエンドを小さな重複グループにパーティショニングすることで、内部 TCP / UDP ロードバランサのスケーラビリティを改善します。サブセット化を使用すると、250 を超えるノードを持つクラスタで内部 TCP / UDP ロードバランサを構成できます。

サブセット設定は、クラスタの作成時と既存のクラスタを編集する際に有効にできます。

アーキテクチャ

サブセット化を行うと、内部 TCP / UDP ロードバランサのデプロイ方法が変更されます。サブセット化を行わない場合、GKE コントローラは、クラスタのすべてのノードを 1 つ以上のゾーンの非マネージド インスタンス グループに配置します。このグループは、GKE クラスタ内のすべての内部ロードバランサによって共有されます。たとえば、40 ノードの GKE クラスタのすべての内部 TCP / UDP ロードバランサは、バックエンドと同じ 40 ノードを共有します。

内部 TCP / UDP ロードバランサのサブセット設定を使用すると、GKE コントローラはノードを GCE_VM_IP zonal network endpoint groups (NEGs) に配置します。インスタンス グループとは異なり、ノードは複数のゾーン NEG のメンバーにすることができ、各ゾーン NEG は内部 TCP / UDP ロードバランサによって参照されます。GKE コントローラは、GKE ノードのサブセットをメンバーとして使用し、各サービスに NEG を作成します。たとえば、40 ノードの GKE クラスタは、バックエンド ゾーン NEG に 25 のノードを含む 1 つの内部 TCP / UDP ロードバランサと、別のバックエンドに 25 のノードを含む別の内部 TCP / UDP で構成されている場合があります。

次の図は、内部 TCP / UDP ロードバランサのサブセットが有効になっているクラスタ内の 2 つの異なるサービスを示しています。各サービスには、3 つのノードにスケジュールされている 2 つの Pod があります。Google Cloud は各サービスに GCE_VM_IP NEG を作成します。GKE コントローラは、クラスタ内のノードのサブセットとして NEG のメンバーを選択し、選択した各ノードの IP アドレスをエンドポイントとして使用します。

サブセット化してサービスのエンドポイントとして使用されるノードの仮想 IP アドレス。
図: サービスを含むクラスタ内のサブセットの例。

バックエンド ノード サブセットの選択

クラスタでサブセット化を有効にすると、GKE コントローラはノードをサブセットにする方法を自動的に決定します。externalTrafficPolicy には Local または Cluster の値を使用できますが、バックエンド ノードのサブセットの選択は値によって異なります。

  • externalTrafficPolicy: Cluster: クライアント リクエストがノード IP に送信され、バックエンド Pod に負荷分散されます。バックエンド Pod は同じノードまたは別のノードに存在する可能性があります。GKE コントローラが、25 ノードのサブセットをランダムに選択します。この分散により、単一障害点を防ぐことができます。25 を超えるノードでバックエンド Pod がホストされている場合でも、Pod はトラフィックを受信しますが、トラフィックはサブセットに含まれるノード(最大 25 個)を経由してクラスタに送信されます。クラスタのノード数が 25 未満の場合は、すべてのノードがサブセットに含まれます。

  • externalTrafficPolicy: Local: クライアント リクエストがノード IP に送信され、同じノードで実行されているバックエンド Pod にのみ負荷分散されます。その結果、バックエンド ノードのサブセットには、サービス オブジェクト Pod の 1 つをホストするノードのみが含まれます。サブセット サイズは、このサービスから Pod をホストするノードの数になります(最大 250 ノード)。追加のノードはロードバランサからトラフィックを受信しないため、ノードが 250 を超えるサービスはスケジュールしないでください。

要件と制限事項

GKE のサブセット化には次の要件と制限があります。

  • GKE バージョン 1.18.19-gke.1400 以降では、新規および既存のクラスタのサブセット化を有効にできます。
  • クラスタで HttpLoadBalancing アドオンが有効になっている必要があります。このアドオンはデフォルトで有効になっています。このアドオンを無効にしているクラスタでは、サブセット化を使用できません。HttpLoadBalancing アドオンを有効にしてカスタム Ingress コントローラを実行する方法については、HttpLoadBalancing アドオンを有効にしてカスタム Ingress コントローラを使用するをご覧ください。
  • Cloud SDK バージョン 345.0.0 以降。
  • Autopilot クラスタでは、サブセット化を使用できません。
  • ネットワーク エンドポイント グループの割り当てが適用されます。Google Cloud は、内部 TCP / UDP ロードバランサにつき、ゾーンごとに 1 つの NEG を作成します。
  • 転送ルール、バックエンド サービス、その他のネットワーク リソースの割り当てが適用されます。
  • クラスタで一度有効にしたサブセット化を無効にすることはできません。
  • バックエンド サービスを共有するためのアノテーションにサブセット設定(alpha.cloud.google.com/load-balancer-backend-share)を使用することはできません。

新しいクラスタで内部ロードバランサのサブセット化を有効にする

内部ロードバランサのサブセット化を有効にしてクラスタを作成するには、gcloud コマンドライン ツールまたは Cloud Console を使用します。

Console

  1. Cloud Console で Google Kubernetes Engine ページに移動します。

    Google Kubernetes Engine に移動

  2. [ 作成] をクリックします。

  3. 必要に応じてクラスタを構成します。

  4. ナビゲーション パネルの [クラスタ] の下の [ネットワーキング] をクリックします。

  5. [L4 内部ロードバランサのサブセット化を有効にする] チェックボックスをオンにします。

  6. [作成] をクリックします。

gcloud

gcloud container clusters create CLUSTER_NAME \
    --cluster-version=VERSION \
    --enable-l4-ilb-subsetting \
    --region=COMPUTE_REGION

次のように置き換えます。

  • CLUSTER_NAME: 新しいクラスタの名前。
  • VERSION: GKE バージョン。1.18.19-gke.1400 以降にする必要があります。--release-channel オプションを使用して、リリース チャンネルを選択することもできます。リリース チャンネルには、デフォルトのバージョン 1.18.19-gke.1400 以降が必要です。
  • COMPUTE_REGION: クラスタの Compute Engine のリージョン

既存のクラスタで内部ロードバランサのサブセット化を有効にする

既存のクラスタの内部ロードバランサ サブセット化を有効にするには、gcloud ツールまたは Google Cloud Console を使用します。クラスタで一度有効にした内部ロードバランサのサブセット化は無効にできません。

Console

  1. Cloud Console で、Google Kubernetes Engine のページに移動します。

    Google Kubernetes Engine に移動

  2. クラスタのリストで、変更するクラスタの名前をクリックします。

  3. [ネットワーキング] で、[L4 内部ロードバランサのサブセット化] フィールドの横にある [L4 内部ロードバランサのサブセット化を有効にする] をクリックします。

  4. [L4 内部ロードバランサのサブセット化を有効にする] チェックボックスをオンにします。

  5. [変更を保存] をクリックします。

gcloud

gcloud container clusters update CLUSTER_NAME \
    --enable-l4-ilb-subsetting

次のように置き換えます。

  • CLUSTER_NAME: クラスタの名前。

内部ロードバランサのサブセット設定を確認する

内部ロードバランサのサブセット設定がクラスタで正しく動作していることを確認するには、次の手順を行います。

  1. ワークロードをデプロイします。

    以下のマニフェストは、サンプルのウェブ アプリケーション コンテナ イメージを実行する Deployment を記述しています。マニフェストを ilb-deployment.yaml として保存します。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ilb-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: ilb-deployment
      template:
        metadata:
          labels:
            app: ilb-deployment
        spec:
          containers:
          - name: hello-app
            image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
    
  2. マニフェストをクラスタに適用します。

    kubectl apply -f ilb-deployment.yaml
    
  3. Service を作成します。

    次のマニフェストでは、TCP ポート 8080 で内部ロードバランサを作成する Service が記述されています。マニフェストを ilb-svc.yaml として保存します。

    apiVersion: v1
    kind: Service
    metadata:
      name: ilb-svc
      annotations:
        networking.gke.io/load-balancer-type: "Internal"
    spec:
      type: LoadBalancer
      externalTrafficPolicy: Cluster
      selector:
        app: ilb-deployment
      ports:
      - name: tcp-port
        protocol: TCP
        port: 8080
        targetPort: 8080
    
  4. マニフェストをクラスタに適用します。

    kubectl apply -f ilb-svc.yaml
    
  5. サービスの検査:

    kubectl get svc ilb-svc -o=jsonpath="{.metadata.annotations.cloud\.google\.com/neg-status}"
    

    出力は次のようになります。

    {"network_endpoint_groups":{"0":"k8s2-knlc4c77-default-ilb-svc-ua5ugas0"},"zones":["us-central1-c"]}
    

    レスポンスは、GKE が k8s2-knlc4c77-default-ilb-svc-ua5ugas0 という名前のネットワーク エンドポイント グループを作成したことを示します。このアノテーションは、GKE サブセット設定を使用する LoadBalancer タイプの Service に存在し、サブセット設定を使用しない Service には存在しません。

トラブルシューティング

サービスのサブセットのノードのリストを確認するには、次のコマンドを使用します。

gcloud compute network-endpoint-groups list-network-endpoints NEG_NAME \
    --zone=COMPUTE_ZONE

次のように置き換えます。

  • NEG_NAME: GKE コントローラによって作成されたネットワーク エンドポイント グループの名前。
  • COMPUTE_ZONE: 動作対象のネットワーク エンドポイント グループのコンピューティング ゾーン

内部 TCP / UDP ロードバランサの正常なノードのリストを確認するには、次のコマンドを使用します。

gcloud compute backend-services get-health SERVICE_NAME \
    --region=COMPUTE_REGION

次のように置き換えます。

  • SERVICE_NAME: バックエンド サービスの名前。この値は、GKE コントローラによって作成されたネットワーク エンドポイント グループの名前と同じです。
  • COMPUTE_REGION: 操作するバックエンド サービスのコンピューティング リージョン

既知の問題

10 分ごとに接続タイムアウトする

サブセットを使用して作成した内部 LoadBalancer Service では、約 10 分ごとにトラフィックが中断されることがあります。このバグは次のバージョンで修正されています。

  • 1.18.19-gke.1700 以降
  • 1.19.10-gke.1000 以降
  • 1.20.6-gke.1000 以降

Private Service Connect を使用した内部 TCP / UDP ロードバランサの作成

サービス プロデューサーとしてサービス アタッチメントを使用すると、Private Service Connect を使用して、他の VPC ネットワークのサービス コンシューマがサービスを利用できるようになります。ServiceAttachment カスタム リソースを使用して、サービス アタッチメントを作成、管理、削除できます。

要件と制限事項

  • Private Service Connect の制限事項が適用されます。
  • サービス アタッチメントは、GKE バージョン 1.21.4-gke.300 以降で作成できます。
  • 複数サービスのアタッチメント構成で同じサブネットを使用することができません。
  • 内部 TCP / UDP ロードバランサを使用する GKE サービスを作成する必要があります。

ServiceAttachment の作成

  1. サブネットを作成します。

    ServiceAttachment ごとに新しいサブネットを作成する必要があります。

    gcloud beta compute networks subnets create SUBNET_NAME \
        --project PROJECT_ID \
        --network NETWORK_NAME \
        --region REGION \
        --range SUBNET_RANGE \
        --purpose PRIVATE_SERVICE_CONNECT
    

    次のように置き換えます。

    • SUBNET_NAME: 新しいサブネットの名前。
    • PROJECT_ID: Google Cloud プロジェクトの ID。
    • NETWORK_NAME: サブネットの VPC ネットワークの名前。
    • REGION: 新しいサブネットのリージョン。作成するサービスと同じリージョンを使用する必要があります。
    • SUBNET_RANGE: サブネットに使用する IP アドレス範囲。
  2. ワークロードをデプロイします。

    以下のマニフェストは、サンプルのウェブ アプリケーション コンテナ イメージを実行する Deployment を記述しています。マニフェストを my-deployment.yaml として保存します。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: psc-ilb
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: psc-ilb
      template:
        metadata:
          labels:
            app: psc-ilb
        spec:
          containers:
          - name: whereami
            image: gcr.io/google-samples/whereami:v1.2.1
            ports:
              - name: http
                containerPort: 8080
            readinessProbe:
              httpGet:
                path: /healthz
                port: 8080
                scheme: HTTP
              initialDelaySeconds: 5
              timeoutSeconds: 1
    
  3. マニフェストをクラスタに適用します。

    kubectl apply -f my-deployment.yaml
    
  4. サービスを作成します。次のマニフェストでは、TCP ポート 8080 で内部 TCP / UDP ロードバランサを作成するサービスを記述しています。マニフェストを my-service.yaml として保存します。

     apiVersion: v1
     kind: Service
     metadata:
       name: SERVICE_NAME
       annotations:
         networking.gke.io/load-balancer-type: "Internal"
     spec:
       type: LoadBalancer
       selector:
         app: psc-ilb
       ports:
       - port: 80
         targetPort: 8080
         protocol: TCP
    

    次のように置き換えます。

    • SERVICE_NAME: 新しいサービスの名前。
  5. マニフェストをクラスタに適用します。

    kubectl apply -f my-service.yaml
    
  6. ServiceAttachment を作成します。

    次のマニフェストでは、作成したサービスをサービス コンシューマに提供する ServiceAttachment を記述しています。マニフェストを my-psc.yaml として保存します。

    apiVersion: networking.gke.io/v1beta1
    kind: ServiceAttachment
    metadata:
     name: SERVICE_ATTACHMENT_NAME
     namespace: default
    spec:
     connectionPreference: ACCEPT_AUTOMATIC
     natSubnets:
     - SUBNET_NAME
     proxyProtocol: false
     resourceRef:
       kind: Service
       name: SERVICE_NAME
    

    次のように置き換えます。

    • SERVICE_ATTACHMENT_NAME: 新しいサービス アタッチメントの名前。

    ServiceAttachment には次のフィールドがあります。

    • connectionPreference: コンシューマがサービスに接続する方法を決定する接続設定。ACCEPT_AUTOMATIC を使用してプロジェクトの自動承認を使用するか、ACCEPT_MANUAL を使用してプロジェクトを明示的に承認できます。詳細については、Private Service Connect を使用してサービスを公開するをご覧ください。
    • natSubnets: サービス アタッチメントに使用するサブネットワーク リソース名のリスト。
    • proxyProtocol: true に設定すると、リクエスト内でコンシューマ ソース IP と Private Service Connect の接続 ID を使用できるようになります。このフィールドは省略可能で、指定しない場合はデフォルトの false になります。
    • consumerAllowList: ServiceAttachment への接続が許可されているコンシューマ プロジェクトのリスト。このフィールドは、connectionPreferenceACCEPT_MANUAL の場合にのみ使用できます。このフィールドの詳細については、Private Service Connect を使用してサービスを公開するをご覧ください。
      • project: コンシューマ プロジェクトのプロジェクト ID または番号。
      • connectionLimit: コンシューマ プロジェクトの接続の上限。このフィールドは省略可能です。
      • forceSendFields: API リクエストに含めるフィールド名。このフィールドは省略可能です。
      • nullFields: API リクエストに null 値で含めるフィールド名。このフィールドは省略可能です。
    • consumerRejectList: コンシューマ プロジェクトの ID または番号のリスト。ServiceAttachment への接続は許可されません。このフィールドは、connectionPreferenceACCEPT_MANUAL の場合にのみ使用できます。このフィールドの詳細については、Private Service Connect を使用してサービスを公開するをご覧ください。
    • resourceRef: Kubernetes リソースへの参照。
      • kind: Kubernetes リソースのタイプ。Service を使用する必要があります。
      • name: 内部 TCP / UDP ロードバランサと同じ名前空間にある Kubernetes リソースの名前。
  7. マニフェストをクラスタに適用します。

    kubectl apply -f my-psc.yaml
    
  8. Private Service Connect コントローラがサービス アタッチメントを作成したことを確認します。

    gcloud beta compute service-attachments list
    

    出力には、自動生成された名前のサービス アタッチメントが表示されます。

    NAME        REGION       PRODUCER_FORWARDING_RULE          CONNECTION_PREFERENCE
    k8s1-sa-... us-central1  a3fea439c870148bdba5e59c9ea9451a  ACCEPT_AUTOMATIC
    

ServiceAttachment の表示

ServiceAttachment の詳細を表示するには、次のコマンドを使用します。

kubectl describe serviceattachment SERVICE_ATTACHMENT_NAME /
    --project PROJECT_ID

出力は次のようになります。

 kubectl describe serviceattachment foo-sa
Name:        <sa-name>
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  networking.gke.io/v1beta1
Kind:         ServiceAttachment
Metadata:
  ...
Status:
  Forwarding Rule URL:      https://www.googleapis.com/compute/beta/projects/<project>/regions/<region>/forwardingRules/<fr-name>
  Last Modified Timestamp:  2021-07-08T01:32:39Z
  Service Attachment URL:   https://www.googleapis.com/compute/beta/projects/<projects>/regions/<region>/serviceAttachments/<gce-service-attachment-name>
Events:                     <none>

ServiceAttachment の使用

別のプロジェクトのサービスを使用するには、次の手順を行います。

  1. ServiceAttachment の URL を取得します。

    kubectl get serviceattachment SERVICE_ATTACHMENT_NAME -o=jsonpath="{.status.serviceAttachmentURL}"
    

    出力は次のようになります。

      serviceAttachmentURL: https://www.googleapis.com/compute/alpha/projects/<project>/region/<region>/serviceAttachments/k8s1-...my-sa
    
  2. ServiceAttachment の URL を使用して、Private Service Connect エンドポイントを作成します。

  3. コンシューマ プロジェクトの VM から curl コマンドを使用して、プロデューサー プロジェクトでデプロイした Service に接続できることを確認します。

    curl PSC_IP_ADDRESS
    

    PSC_IP_ADDRESS は、コンシューマ プロジェクトの転送ルールの IP アドレスに置き換えます。

    出力は次のようになります。

    {
      "cluster_name":"cluster",
      "host_header":"10.128.15.200",
      "node_name":"gke-psc-default-pool-be9b6e0e-dvxg.c.gke_project.internal",
      "pod_name":"foo-7bf648dcfd-l5jf8",
      "pod_name_emoji":"👚",
      "project_id":"gke_project",
      "timestamp":"2021-06-29T21:32:03",
      "zone":"us-central1-c"
    }
    

ServiceAttachment の更新

ServiceAttachment を更新するには、次の手順を行います。

  1. my-psc.yamlServiceAttachment マニフェストを編集します。

    apiVersion: networking.gke.io/v1beta1
    kind: ServiceAttachment
    metadata:
      name: my-sa
      namespace: default
    spec:
      connectionPreference: ACCEPT_AUTOMATIC
      natSubnets:
      - my-nat-subnet
      proxyProtocol: false
      resourceRef:
        kind: Service
        name: ilb-service
    
  2. マニフェストをクラスタに適用します。

    kubectl apply -f my-psc.yaml
    

クリーンアップ

サービス アタッチメントに接続されている内部 TCP / UDP ロードバランサは削除できません。サービス アタッチメントと GKE Service は個別に削除する必要があります。

  1. サービス アタッチメントを削除します。

    kubectl delete serviceattachment SERVICE_ATTACHMENT_NAME --wait=false
    

    このコマンドは、サービス アタッチメントに削除マークを付けますが、リソースは引き続き存在します。--wait フラグを省略して、削除の完了を待つこともできます。

  2. Service を削除します。

    kubectl delete svc SERVICE_NAME
    
  3. サブネットを削除します。

    gcloud compute networks subnets delete SUBNET_NAME
    

トラブルシューティング

次のコマンドを使用すると、エラー メッセージを表示できます。

kubectl get events -n NAMESPACE

NAMESPACE は、内部 TCP / UDP ロードバランサの名前空間に置き換えます。

サービス アタッチメントで使用されている内部 TCP / UDP ロードバランサを削除しようとすると、次のようなエラー メッセージが表示されます。内部 TCP / UDP ロードバランサを削除する前に、ServiceAttachment を削除する必要があります。

Error syncing load balancer: failed to ensure load balancer: googleapi:
Error 400: The forwarding_rule resource '<fwd-rule-URL>' is already being used
by '<svc-attachment-URL>', resourceInUseByAnotherResource.

Service のパラメータ

構成可能なロードバランサのパラメータの詳細については、TCP / UDP 負荷分散の構成をご覧ください。さらに、内部 LoadBalancer Service は、次の追加パラメータをサポートしています。

機能 概要 サービス フィールド GKE バージョンのサポート
ロードバランサのサブネット ロードバランサが IP を自動的にプロビジョニングするサブネットを指定します。 metadata:annotations: networking.gke.io/internal-load-balancer-subnet GKE 1.17 以降と 1.16.8-gke.10 以降のベータ版
GKE 1.17.9-gke.600 以降の一般提供
グローバル アクセス Google Cloud リージョンのクライアントが内部 TCP / UDP ロードバランサの仮想 IP アドレスにアクセスできるようにします。 metadata:annotations: networking.gke.io/internal-load-balancer-allow-global-access GKE 1.16 以降のベータ版
GKE 1.17.9-gke.600 以降の一般提供

ロードバランサのサブネット

デフォルトでは、GKE はノードのサブネット範囲を使用して内部 TCP / UDP ロードバランサをデプロイします。サブネットは、networking.gke.io/internal-load-balancer-subnet アノテーションを使用して Service ごとに指定できます。これは、内部ロードバランサの IP をノード IP から個別にファイアウォールする場合や、複数の GKE クラスタ間で同じ Service のサブネットを共有する場合に便利です。このパラメータは、内部 TCP / UDP ロードバランサの Service にのみ関連します。

GKE はサブネット自体のライフサイクルを管理しないため、Servie のリソースによって参照される前にサブネットが存在する必要があります。サブネットは、GKE クラスタと同じ VPC とリージョンに存在する必要もあります。このステップでは、GKE から帯域外に作成されます。

gcloud compute networks subnets create gke-vip-subnet \
    --network=default \
    --range=10.23.0.0/24 \
    --region=us-central1

次の Service 定義では、internal-load-balancer-subnet を使用してサブネットを名前で参照します。デフォルトでは、サブネットから使用可能な IP が自動的に選択されます。loadBalancerIP を指定することもできますが、参照されるサブネットの一部である必要があります。

この内部ロードバランサのサブネットを共有して、さまざまなユースケースを実現する方法は複数あります。

  • 同じクラスタ内の Service のグループに対する複数のサブネット
  • クラスタ内のすべての Service の単一サブネット
  • 複数のクラスタと Service 間で共有される単一のサブネット
apiVersion: v1
kind: Service
metadata:
  name: ilb-service
  annotations:
    networking.gke.io/load-balancer-type: "Internal"
    networking.gke.io/internal-load-balancer-subnet: "gke-vip-subnet"
  labels:
    app: hello
spec:
  type: LoadBalancer
  loadBalancerIP: 10.23.0.15
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

グローバル アクセス

グローバル アクセスは、同じ VPC ネットワーク内の任意のリージョンに配置されているクライアントに対し、内部 TCP / UDP ロードバランサへのアクセスを許可するために使用する、内部 LoadBalancer Service のオプション パラメータです。グローバル アクセスを使用しない場合、トラフィックを送信するクライアントは、ロードバランサと同じ VPC ネットワーク内の同じリージョンに配置されていなければなりません。グローバル アクセスを使用すると、任意のリージョン内のクライアントがロードバランサにアクセスできます。ただし、バックエンド インスタンスはロードバランサと同じリージョン内に配置されている必要があります。

グローバル アクセスは、次のアノテーションを使用してサービスごとに有効にされます。networking.gke.io/internal-load-balancer-allow-global-access: "true"

従来のネットワークでは、グローバル アクセスはサポートされません。リージョン間でグローバル アクセスを使用する場合は、通常のリージョン間トラフィック費用が適用されます。リージョン間の下り(外向き)ネットワーク料金については、ネットワーク料金をご覧ください。GKE クラスタ 1.16 以降では、グローバル アクセスはベータ版として提供されています。1.17.9-gke.600 以降では一般提供されています。

オンプレミスのクライアントは、グローバル アクセスにより、どのリージョンでも Cloud VPN または Cloud Interconnect(VLAN)を使用してロードバランサにアクセスできます。詳細については、Cloud VPN と Cloud Interconnect の使用をご覧ください。

共有 IP

内部 TCP / UDP ロードバランサでは、複数の転送ルール間で仮想 IP アドレスを共有できます。これは、同じ IP で同時使用のポート数を拡張する場合や、同じ IP で UDP トラフィックと TCP トラフィックを受け入れる場合に便利です。IP アドレスあたり最大 50 個の公開ポートが許可されます。共有 IP は、内部 LoadBalancer Service のある GKE クラスタでネイティブにサポートされます。デプロイ時に、Service の loadBalancerIP フィールドを使用して、Service 間で共有する IP を指定します。

制限事項

複数のロードバランサの共有 IP には、次のような制限と機能があります。

  • 各 Service(または転送ルール)に最大で 5 個のポートを設定できます。
  • IP アドレスを共有できるのは最大 10 個の Services(転送ルール)です。このため、共有 IP あたり最大で 50 個のポートを設定できます。
  • プロトコル / ポートタプルは、同じ IP を共有する Service 間で重複させることはできません。
  • 同じ共有 IP では TCP 専用と UDP 専用の Service の組み合わせがサポートされていますが、同じ Service で TCP ポートと UDP ポートの両方を公開することはできません。

共有 IP の有効化

内部 LoadBalancer Service で共通の IP を共有するには、次の操作を行います。

  1. --purpose SHARED_LOADBALANCER_VIP を使用して、静的内部 IP を作成します。共有を可能にするために、IP アドレスの作成が必要です。共有 VPC で静的内部 IP アドレスを作成する場合は、IP アドレスを使用するインスタンスと同じサービス プロジェクトに IP アドレスを作成する必要があります。これは、IP アドレスの値が共有 VPC ネットワークの選択された共有サブネット内の利用可能な IP の範囲から取得されたものだとしても、同様です。詳細については、共有 VPC のプロビジョニングのページで静的内部 IP の予約をご覧ください。

  2. この静的 IP を loadBalancerIP フィールドに指定して、最大 10 個の内部 LoadBalancer Service をデプロイします。内部 TCP / UDP ロードバランサは、GKE サービス コントローラによって調整され、同じフロントエンド IP を使用してデプロイします。

次の例は、同じ内部ロードバランサの IP で複数の TCP ポートと UDP ポートをサポートする方法を示しています。

  1. GKE クラスタと同じリージョンに静的 IP を作成します。サブネットはロードバランサが使用するサブネットと同じにする必要があります。デフォルトは、GKE クラスタノードの IP によって使用されるサブネットです。

    クラスタと VPC ネットワークが同じプロジェクト内にある場合:

    gcloud compute addresses create IP_ADDR_NAME \
        --project=PROJECT_ID \
        --subnet=SUBNET \
        --addresses=IP_ADDRESS \
        --region=COMPUTE_REGION \
        --purpose=SHARED_LOADBALANCER_VIP
    

    クラスタが共有 VPC サービス プロジェクトにあるが、ホスト プロジェクトで共有 VPC ネットワークを使用している場合:

    gcloud compute addresses create IP_ADDR_NAME \
        --project=SERVICE_PROJECT_ID \
        --subnet=projects/HOST_PROJECT_ID/regions/REGION/subnetworks/SUBNET \
        --addresses=IP_ADDRESS \
        --region=COMPUTE_REGION \
        --purpose=SHARED_LOADBALANCER_VIP
    

    次のように置き換えます。

    • IP_ADDR_NAME: IP アドレス オブジェクトの名前。
    • SERVICE_PROJECT_ID: サービス プロジェクトの ID。
    • PROJECT_ID: プロジェクト(単一プロジェクト)の ID。
    • HOST_PROJECT_ID: 共有 VPC ホスト プロジェクトの ID。
    • COMPUTE_REGION: 共有サブネットを含むコンピューティング リージョン
    • IP_ADDRESS: 選択したサブネットのプライマリ IP アドレス範囲の未使用の内部 IP アドレス。IP アドレスの指定を省略すると、Google Cloud は選択したサブネットのプライマリ IP アドレス範囲から未使用の内部 IP アドレスを選択します。自動的に選択されるアドレスを確認するには、gcloud compute addresses describe を実行する必要があります。
    • SUBNET: 共有サブネットの名前。
  2. 次の TCP Service の構成を tcp-service.yaml というファイルに保存し、クラスタにデプロイします。IP_ADDRESS を前のステップで選択した IP アドレスに置き換えます。

    apiVersion: v1
    kind: Service
    metadata:
      name: tcp-service
      namespace: default
      annotations:
        networking.gke.io/load-balancer-type: "Internal"
    spec:
      type: LoadBalancer
      loadBalancerIP: IP_ADDRESS
      selector:
        app: myapp
      ports:
      - name: 8001-to-8001
        protocol: TCP
        port: 8001
        targetPort: 8001
      - name: 8002-to-8002
        protocol: TCP
        port: 8002
        targetPort: 8002
      - name: 8003-to-8003
        protocol: TCP
        port: 8003
        targetPort: 8003
      - name: 8004-to-8004
        protocol: TCP
        port: 8004
        targetPort: 8004
      - name: 8005-to-8005
        protocol: TCP
        port: 8005
        targetPort: 8005
    
  3. この Service 定義をクラスタに適用します。

    kubectl apply -f tcp-service.yaml
    
  4. 次の UDP Service 構成を udp-service.yaml というファイルに保存し、デプロイします。また、前のステップで指定した IP_ADDRESS も使用します。

    apiVersion: v1
    kind: Service
    metadata:
      name: udp-service
      namespace: default
      annotations:
        networking.gke.io/load-balancer-type: "Internal"
    spec:
      type: LoadBalancer
      loadBalancerIP: IP_ADDRESS
      selector:
        app: my-udp-app
      ports:
      - name: 9001-to-9001
        protocol: UDP
        port: 9001
        targetPort: 9001
      - name: 9002-to-9002
        protocol: UDP
        port: 9002
        targetPort: 9002
    
  5. このファイルをクラスタに適用します。

    kubectl apply -f udp-service.yaml
    
  6. ロードバランサ転送ルールのリストを取得して静的 IP をフィルタリングし、VIP がロードバランサ転送ルール間で共有されていることを確認します。これは、UDP と TCP の両方の転送ルールが、共有 IP_ADDRESS(この例では 10.128.2.98)で 7 つの異なるポートをリッスンしていることを示しています。

    gcloud compute forwarding-rules list | grep 10.128.2.98
    ab4d8205d655f4353a5cff5b224a0dde                         us-west1   10.128.2.98     UDP          us-west1/backendServices/ab4d8205d655f4353a5cff5b224a0dde
    acd6eeaa00a35419c9530caeb6540435                         us-west1   10.128.2.98     TCP          us-west1/backendServices/acd6eeaa00a35419c9530caeb6540435
    

すべてのポート

内部転送ルールは、転送ルールごとに最大 5 つのポート、または、転送ルールですべてのポートを転送するオプションのパラメータ --ports=ALL をサポートします。

要件

GKE のすべてのポートには、次の要件と制限があります。

  • --enable-l4-ilb-subsetting が有効になっている場合にのみサポートされます。
  • 内部ロードバランサ サービスでのみサポートされています。
  • 最大 100 個の連続するポート範囲で任意の数のポートをサポートします。

GKE コントローラは、サービスに存在するポート数が 5 つを超える場合、転送ルールですべてのポートを自動的に有効にします。たとえば、次のサービス マニフェストでは、2 つの連続する範囲で 6 つのポートが構成されています。

apiVersion: v1
kind: Service
metadata:
  name: all-ports
  annotations:
    networking.gke.io/load-balancer-type: "Internal"
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
  - port: 8081
    targetPort: 8081
    name: 8081-to-8081
    protocol: TCP
  - port: 8082
    targetPort: 8082
    name: 8082-to-8082
    protocol: TCP
  - port: 8083
    targetPort: 8083
    name: 8083-to-8083
    protocol: TCP
  - port: 9001
    targetPort: 9001
    name: 9001-to-9001
    protocol: TCP
  - port: 9002
    targetPort: 9002
    name: 9002-to-9002
    protocol: TCP
  - port: 9003
    targetPort: 9003
    name: 9003-to-9003
    protocol: TCP

サービスに存在するポート数が 5 つを超えるため、GKE コントローラは転送ルールですべてのポートを有効にします。ただし、GKE コントローラは、サービスで指定されたポートのファイアウォール ポートのみを作成します。他のすべてのルールは、VPC ファイアウォールによってブロックされます。

内部 TCP / UDP ロードバランサの制限事項

  • Kubernetes バージョン 1.7.4 以降を実行しているクラスタでは、自動モードのサブネットだけでなく、カスタムモードのサブネットの内部ロードバランサも使用できます。
  • Kubernetes バージョン 1.7.X 以降を実行しているクラスタは、--purpose フラグを SHARED_LOADBALANCER_VIP に設定した予約済み IP アドレスを作成した場合、内部 TCP / UDP ロードバランサに対する予約済み IP アドレスの使用をサポートします。詳しい手順については、共有 IP の有効化をご覧ください。GKE は、Service がその目的で内部 IP アドレスを参照する場合にのみ、内部 TCP / UDP ロードバランサの IP アドレスを保持します。それ以外の場合、Service が更新されるときに(ポートが変更された場合など)、GKE がロードバランサの IP アドレス(spec.loadBalancerIP)を変更することがあります。
  • ロードバランサの IP アドレスが変更されても(前のポイントを参照)、spec.clusterIP は一定に保たれます。

内部 UDP ロードバランサの制限事項

  • 内部 UDP ロードバランサは、sessionAffinity: ClientIP の使用をサポートしていません。

上限

type: LoadBalancer の Kubernetes Service と networking.gke.io/load-balancer-type: Internal アノテーションを使用すると、Kubernetes Service を対象にする内部ロードバランサが作成されます。このような Service の数は、VPC ネットワークで作成できる内部転送ルールの数によって制限されます。詳細については、ネットワークごとの制限をご覧ください。

内部 TCP / UDP ロードバランサを含む GKE クラスタの最大ノード数は、externalTrafficPolicy の値によって異なります。

  • externalTrafficPolicy: Cluster: 内部 TCP / UDP ロードバランサのバックエンドは、ランダムに選択された最大 250 個のノードを使用します。クラスタのノード数が 250 より多い場合、ロードバランサのすべてのトラフィックは 250 のノードからクラスタに入り、ランダムに選択された Pod に転送されます。250 を超えるノードでは、このモードの使用はおすすめしません。

  • externalTrafficPolicy: Local: 内部 TCP / UDP ロードバランサのバックエンドは、ランダムに選択された最大 250 個のノードを使用します。選択した 250 個のどのノードでも内部 TCP / UDP ロードバランサ サービスのバックエンド Pod が実行されない場合、LoadBalancer IP への接続は失敗します。250 を超えるノードでは、このモードの使用はサポートされていません。

この制限を削除するには、内部ロードバランサのサブセット設定を有効にします。

VPC の上限の詳細については、割り当てと上限をご覧ください。

次のステップ