このページでは、Google Kubernetes Engine で Compute Engine 内部 TCP / UDP ロードバランサを作成する方法について説明します。
概要
内部 TCP / UDP 負荷分散を使用すると、同じ VPC ネットワークを使用し、同じ Google Cloud リージョンに配置されているクラスタ外のアプリケーションに、クラスタのサービスがアクセスできるようになります。たとえば、us-west1
リージョンにクラスタを配置している場合、そのクラスタのサービスの 1 つが、同じ VPC ネットワークを使用し、このリージョンで実行されている Compute Engine VM インスタンスにアクセスできるようになります。
内部 TCP / UDP ロードバランサを作成するには、cloud.google.com/load-balancer-type: "Internal"
アノテーションを含む Service リソースと type: LoadBalancer
仕様を作成します。以下では、その例と作成方法について説明します。
内部 TCP / UDP ロードバランサを使用しない場合は、外部ロードバランサとファイアウォール ルールを設定して、クラスタの外部からアプリケーションにアクセスできるようにする必要があります。
内部 TCP / UDP ロードバランサでは、Service の内部 IP アドレスが作成されます。Service はこの IP アドレスで、同じ VPC ネットワークの同じコンピューティング リージョン内に配置されているクライアントからのトラフィックを受信します。グローバル アクセスを有効にすると、同じ VPC ネットワークの任意のリージョン内に配置されているクライアントが Service にアクセスできます。また、VPC ネットワーク ピアリングを使用して LoadBalancer ネットワークに接続している VPC ネットワーク内のクライアントも Service にアクセスできます。
料金
Compute Engine の料金モデルに従って課金されます。詳細については、ロードバランサと転送ルールの料金をご覧ください。また、Google Cloud 料金計算ツールに関する Compute Engine のページもご覧ください。
始める前に
作業を始める前に、次のことを確認してください。
- Google Kubernetes Engine API が有効になっていることを確認します。 Google Kubernetes Engine API の有効化
- Cloud SDK がインストール済みであることを確認します。
次のいずれかの方法で gcloud
のデフォルトの設定を指定します。
gcloud init
。デフォルトの設定全般を確認する場合に使用します。gcloud config
。プロジェクト ID、ゾーン、リージョンを個別に設定する場合に使用します。
gcloud init の使用
エラー One of [--zone, --region] must be supplied: Please specify
location
を受信した場合は、このセクションの内容を実施します。
-
gcloud init
を実行して、次の操作を行います。gcloud init
リモート サーバーで SSH を使用している場合は、
--console-only
フラグを指定して、コマンドがブラウザを起動しないようにします。gcloud init --console-only
- 手順に従って
gcloud
を承認し、Google Cloud アカウントを使用します。 - 新しい構成を作成するか、既存の構成を選択します。
- Google Cloud プロジェクトを選択します。
- デフォルトの Compute Engine ゾーンを選択します。
gcloud config の使用
- デフォルトのプロジェクト ID を設定します。
gcloud config set project project-id
- ゾーンクラスタを使用する場合は、デフォルトのコンピューティング ゾーンを設定します。
gcloud config set compute/zone compute-zone
- リージョン クラスタを使用する場合は、デフォルトのコンピューティング リージョンを設定します。
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: "gcr.io/google-samples/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:
cloud.google.com/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
です。 - アノテーション:
cloud.google.com/load-balancer-type: "Internal"
。内部 TCP / UDP ロードバランサが構成されることを指定します。 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 を削除するには、次の手順を行います。
Cloud Console で Google Kubernetes Engine の [ワークロード] メニューに移動します。
メニューから、目的のワークロードを選択します。
[削除] をクリックします。
確認ダイアログのメニューで、[削除] をクリックします。
Service を削除する
Service を削除するには、次の手順を行います。
Cloud Console で Google Kubernetes Engine の [サービス] メニューに移動します。
メニューから目的の Service を選択します。
[削除] をクリックします。
確認ダイアログのメニューで、[削除] をクリックします。
既存の Ingress に関する考慮事項
内部 TCP / UDP ロードバランサと分散モード UTILIZATION
を使用する Ingress の両方を使用することはできません。Ingress と内部 TCP / UDP 負荷分散の両方を使用するには、Ingress で分散モード RATE
を使用する必要があります。
クラスタに存在する Ingress リソースが Kubernetes バージョン 1.7.1 以前で作成されている場合、内部 TCP / UDP ロードバランサと互換性はありません。Kubernetes Ingress Resources オブジェクトによって作成された、以前の BackendService
リソースは、分散モードを指定しないで作成されています。この API では、HTTP ロードバランサについてはデフォルトでバランシング モード UTILIZATION
が使用されていました。しかし、内部 TCP / UDP ロードバランサでは、UTILIZATION
を使って他のロードバランサを使用するインスタンス グループを指すことができません。
Ingress 分散モードの確認
Ingress 分散モードを確認するには、シェルまたはターミナル ウィンドウから次のコマンドを実行します。
GROUPNAME=`kubectl get configmaps ingress-uid -o jsonpath='k8s-ig--{.data.uid}' --namespace=kube-system`
gcloud compute backend-services list --format="table(name,backends[].balancingMode,backends[].group)" | grep $GROUPNAME
これらのコマンドによって、シェル変数 GROUPNAME
がエクスポートされます。これによってクラスタのインスタンス グループ名が取得されます。次に、プロジェクトの Compute Engine backend service
リソースがポーリングされ、$GROUPNAME
の内容に従って結果が絞り込まれます。
出力は次のようになります。
k8s-be-31210--... [u'RATE'] us-central1-b/instanceGroups/k8s-ig--...
k8s-be-32125--... [u'RATE'] us-central1-b/instanceGroups/k8s-ig--...
出力で RATE
エントリが返された場合またはエントリが返されなかった場合、内部ロードバランサは互換性があります。追加作業は必要ありません。
出力で UTILIZATION
とマークされたエントリが返された場合、Ingress は互換性がありません。
Ingress リソースを更新して内部 TCP / UDP ロードバランサとの互換性を維持するには、Kubernetes バージョン 1.7.2 以降で新しいクラスタを作成し、サービスをそのクラスタに移行します。
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 以降の一般提供 |
グローバル アクセス | GCP リージョン間でクライアントが TCP / UDP ロードバランサの VIP にアクセスできるようにします | 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 LoadBalancer 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 以降の GA で一般提供されています。
共有 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 を共有するには、次の操作を行います。
--purpose SHARED_LOADBALANCER_VIP
を使用して、静的内部 IP を作成します。共有を可能にするために、IP アドレスの作成が必要です。この静的 IP を
loadBalancerIP
フィールドに指定して、最大 10 個の内部 LoadBalancer Service をデプロイします。内部 TCP / UDP ロードバランサは、GKE サービス コントローラによって調整されます。このロードバランサは、同じフロントエンド IP を使用してデプロイします。
次の例は、同じ内部ロードバランサの IP で複数の TCP ポートと UDP ポートをサポートする方法を示しています。
GKE クラスタと同じリージョンに静的 IP を作成します。サブネットはロードバランサが使用するサブネットと同じにする必要があります。デフォルトは、GKE クラスタノードの IP によって使用されるサブネットです。
gcloud beta compute addresses create internal-10-128-2-98 \ --region=us-central1 \ --subnet=default \ --addresses=10.128.2.98 \ --purpose=SHARED_LOADBALANCER_VIP
次の TCP Service の構成を
tcp-service.yaml
というファイルに保存し、クラスタにデプロイします。共有 IP10.128.2.98
を使用します。apiVersion: v1 kind: Service metadata: name: tcp-service namespace: default annotations: cloud.google.com/load-balancer-type: "Internal" spec: type: LoadBalancer loadBalancerIP: 10.128.2.98 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
この Service 定義をクラスタに適用します。
kubectl apply -f tcp-service.yaml
次の UDP Service 構成を
udp-service.yaml
というファイルに保存し、デプロイします。また、共有 IP10.128.2.98
も使用します。apiVersion: v1 kind: Service metadata: name: udp-service namespace: default annotations: cloud.google.com/load-balancer-type: "Internal" spec: type: LoadBalancer loadBalancerIP: 10.128.2.98 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
このファイルをクラスタに適用します。
kubectl apply -f udp-service.yaml
LB 転送ルールのリストを取得して静的 IP をフィルタリングし、VIP が LB 転送ルール間で共有されていることを確認します。これにより、UDP と TCP の両方の転送ルールが共有 IP アドレス
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
内部 TCP / UDP ロードバランサの制限事項
- Kubernetes バージョン 1.7.3 以前を実行しているクラスタの場合、自動モードのサブネットでのみ内部 TCP / UDP ロードバランサを使用できます。Kubernetes バージョン 1.7.4 以降の場合は、自動モードのサブネットだけでなく、カスタムモードのサブネットでも内部ロードバランサを使用できます。
- Kubernetes 1.7.X 以降を実行しているクラスタの場合、clusterIP が変更されないため、内部 TCP / UDP ロードバランサは予約済みの IP アドレスを使用できません。
spec.loadBalancerIP
フィールドに未使用の IP アドレスを定義し、特定の内部 IP を割り当てることができます。ポート、プロトコル、セッション アフィニティを変更すると、IP アドレスが変更されることがあります。
内部 UDP ロードバランサの制限事項
- 内部 UDP ロードバランサは、
sessionAffinity: ClientIP
の使用をサポートしていません。
上限
type: Loadbalancer
の Kubernetes Service と cloud.google.com/load-balancer-type: Internal
アノテーションを使用すると、Kubernetes Service を対象にする ILB が作成されます。このような Service の数は、VPC ネットワークで作成できる内部転送ルールの数によって制限されます。詳細については、ネットワークごとの制限をご覧ください。
GKE クラスタでは、内部転送ルールはクラスタ内のすべてのノードを参照します。クラスタの各ノードは ILB のバックエンド VM になります。VM がインスタンス グループに関連付けられる方法に関係なく、ILB のバックエンド VM の最大数は 250 です。したがって、ILB 内 GKE クラスタの最大ノード数は 250 になります。クラスタで自動スケーリングが有効になっている場合、自動スケーリングでクラスタのノード数が 250 を超えないようにする必要があります。
これらの制限事項の詳細については、VPC リソースの割り当てをご覧ください。
次のステップ
- GKE ネットワークの概要を読む。
- Compute Engine ロードバランサの詳細を確認する。
- エイリアス IP について学ぶ。
- IP マスカレード エージェントについて学ぶ。
- 承認済みネットワークの構成について学ぶ。