内部 HTTP(S) 負荷分散用の Ingress の構成

このページでは、Google Kubernetes Engine(GKE)で内部 HTTP(S) 負荷分散用の Ingress を設定して使用する方法を説明します。内部 HTTP(S) 負荷分散用の Ingress は、GKE Ingress コントローラを介して組み込みの内部負荷分散サポートを提供します。

内部 HTTP(S) 負荷分散用の Ingress でサポートされる機能について詳しくは、Ingress の機能をご覧ください。内部 HTTP(S) 負荷分散用の Ingress の仕組みについては、内部 HTTP(S) 負荷分散用の Ingress をご覧ください。

始める前に

Kubernetes Ingress API を使用してロードバランサ リソースをデプロイする前に、所定のリージョンにロードバランサ プロキシをデプロイできるよう、ネットワーク環境を準備する必要があります。プロキシ専用サブネットをデプロイする手順については、ネットワークとサブネットの構成をご覧ください。

この手順は、内部 HTTP(S) 負荷分散用に Ingress をデプロイする前に完了する必要があります。

内部 HTTP(S) 負荷分散用の Ingress でプロキシ専用サブネットを使用する必要がある理由について詳しくは、必要なネットワーク環境をご覧ください。

要件

内部 HTTP(S) 負荷分散用の Ingress には、次の要件があります。

  • クラスタで 1.16.5-gke.10 より後の GKE バージョンを使用している。
  • クラスタを VPC ネイティブ(エイリアス IP)モードで実行している。詳細については、VPC ネイティブ クラスタをご覧ください。
  • クラスタで HTTP 負荷分散アドオンが有効になっている。デフォルトでは、クラスタで HTTP 負荷分散が有効になっています。このアドオンを無効にしないでください。
  • Service のバックエンドとしてネットワーク エンドポイント グループ(NEG)を使用している。

内部 HTTP(S) 負荷分散用に Ingress をデプロイする

以下の演習で、内部 HTTP(S) 負荷分散用に Ingress をデプロイする方法を説明します。

  1. クラスタを作成する
  2. アプリケーションをデプロイする
  3. Service をデプロイする
  4. Ingress をデプロイする
  5. デプロイを検証する
  6. Ingress リソースを削除する

クラスタを作成する

このセクションでは、内部 HTTP(S) 負荷分散用の Ingress で使用できるクラスタを作成します。このクラスタを作成するには、gcloud コマンドライン ツールまたは Google Cloud Console を使用できます。

gcloud

次のフィールドを使用してクラスタを作成します。

gcloud container clusters create CLUSTER_NAME \
    --cluster-version=VERSION_NUMBER \
    --enable-ip-alias \
    --zone=ZONE \
    --network=NETWORK

以下を置き換えます。

  • CLUSTER_NAME: クラスタの名前を追加します。
  • VERSION_NUMBER: 1.16.5-gke.10 より後のバージョンを追加します。--release-channel フラグを使用して、1.16.5-gke.10 より後のバージョンをデフォルトとして使用するリリース チャネルを選択することもできます。
  • --enable-ip-alias により、エイリアス IP が有効になります。内部 HTTP(S) 負荷分散に Ingress を使用するクラスタは、VPC ネイティブ(エイリアス IP)モードで実行する必要があります。詳細については、VPC ネイティブ クラスタの作成をご覧ください。
  • ZONE: クラスタを作成するゾーンを追加します。ネットワークとサブネットを構成する際に内部 HTTP(S) ロードバランサ用に作成したプロキシ サブネットと同じリージョン内にあるゾーンを選択する必要があります。
  • NETWORK: クラスタを作成するネットワークの名前を追加します。このネットワークは、プロキシ サブネットと同じ VPC ネットワークにする必要があります。

Console

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

    Google Kubernetes Engine に移動

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

  3. [クラスタの基本] セクションで、次の操作を行います。

    1. [名前] に、クラスタの名前を入力します。
    2. [ロケーション タイプ] で、クラスタのゾーンを選択します。ネットワークとサブネットを構成する際に内部 HTTP(S) ロードバランサ用に作成したプロキシ サブネットと同じリージョン内にあるゾーンを選択する必要があります。
    3. [コントロール プレーンのバージョン] で、1.16.5-gke.10 より後の静的バージョンを選択するか、1.16.5-gke.10 より後のバージョンをデフォルトとして使用するリリース チャンネルを選択します。
  4. ナビゲーション パネルの [クラスタ] の下の [ネットワーキング] をクリックします。

    1. [ネットワーク] プルダウン リストから、クラスタを作成するネットワークを選択します。このネットワークは、プロキシ サブネットと同じ VPC ネットワークにする必要があります。
    2. [ネットワークの詳細オプション] で、[VPC ネイティブのトラフィック ルーティングを有効にする(エイリアス IP を使用)] と [HTTP 負荷分散を有効にする] が選択されていることを確認します。
  5. [作成] をクリックします。

ウェブ アプリケーションをデプロイする

このセクションでは、Deployment を作成します。

Deployment を作成するには:

  1. 次の Deployment リソースをコピーして、web-deployment.yaml というファイル名で保存します。

    # web-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: hostname
      name: hostname-server
    spec:
      selector:
        matchLabels:
          app: hostname
      minReadySeconds: 60
      replicas: 3
      template:
        metadata:
          labels:
            app: hostname
        spec:
          containers:
          - image: k8s.gcr.io/serve_hostname:v1.4
            name: hostname-server
            ports:
            - containerPort: 9376
              protocol: TCP
          terminationGracePeriodSeconds: 90
    

    この Deployment ファイルでは、HTTPS サーバーのポート 9376 でリッスンするコンテナ イメージを使用します。この Deployment はアプリケーションの Pod も管理します。各 Pod は、HTTPS サーバーに接続して 1 つのアプリケーション コンテナを実行します。このサーバーは、レスポンスとしてアプリケーション サーバーのホスト名を返します。Pod の名前が Pod のデフォルトのホスト名になります。また、このコンテナでは正常な終了処理も行われます。

  2. Deployment ファイルを作成したら、このリソースをクラスタに適用します。

    kubectl apply -f web-deployment.yaml
    

ネットワーク エンドポイント グループ(NEG)として Service をデプロイする

このセクションでは、Service リソースを作成します。この Service はラベルを基準にバックエンド コンテナを選択します。これにより、Ingress コントローラは、選択されたこれらのコンテナをバックエンド エンドポイントとしてプログラムできます。内部 HTTP(S) 負荷分散用の Ingress では、バックエンドとして NEG を使用する必要があります。この機能ではインスタンス グループをバックエンドとして使用できません。NEG バックエンドが必要になることから、Ingress を介して公開される Service をデプロイするときには、次の NEG アノテーションを使用する必要があります。

annotations:
  cloud.google.com/neg: '{"ingress": true}'

以下のすべての条件が満たされると、Service に自動的に cloud.google.com/neg: '{"ingress": true}' アノテーションが付けられます。

  • GKE クラスタ 1.17.6-gke.7 以降で Service を作成した。
  • VPC ネイティブ クラスタを使用している。
  • 共有 VPC を使用していない。
  • GKE ネットワーク ポリシーを使用していない。

NEG を使用すると、Ingress コントローラがコンテナ ネイティブの負荷分散を実行できます。トラフィックは、ノード IP または kube-proxy ネットワーキングを移動するのではなく、Ingress プロキシから直接 Pod IP に負荷分散されます。また、Kubernetes の readiness / liveness チェックだけでなく、負荷分散の観点からも Pod の健全性を判断するために、Pod の readiness ゲートが実装されます。Pod の readiness ゲートにより、Pod の起動、Pod やノードの損失などのライフサイクル イベントでトラフィックが破棄されないよう防ぐことができます。

NEG アノテーションを追加しないと、Ingress オブジェクトに対して警告が返され、内部 HTTP(S) ロードバランサを構成できなくなります。また、NEG アノテーションが含まれていない場合は、Ingress で Kubernetes イベントが生成されます。次のメッセージは、イベント メッセージの例です。

Message
-------
error while evaluating the ingress spec: could not find port "8080" in service "default/no-neg-svc"

Ingress が Service を参照するまでは NEG は作成されません。Ingress とその参照先の Service の両方が存在するようになるまで、NEG は Compute Engine に表示されません。NEG はゾーンリソースです。マルチゾーン クラスタでは、各ゾーンで Service ごとに 1 つの NEG が作成されます。

Service を作成するには:

  1. 次の Service リソースをコピーして、web-service.yaml というファイル名で保存します。

    # web-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: hostname
      namespace: default
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
    spec:
      ports:
      - name: host1
        port: 80
        protocol: TCP
        targetPort: 9376
      selector:
        app: hostname
      type: NodePort
    
  2. Service ファイルを作成したら、このリソースをクラスタに適用します。

    kubectl apply -f  web-service.yaml
    

Ingress をデプロイする

このセクションでは、Ingress コントローラを介して Compute Engine 負荷分散の Deployment をトリガーする Ingress リソースを作成します。内部 HTTP(S) 負荷分散用の Ingress には、次のアノテーションが必要です。

annotations:
    kubernetes.io/ingress.class: "gce-internal"

Ingress を作成するには:

  1. 次の Ingress リソースをコピーして、internal-ingress.yaml というファイル名で保存します。

    # internal-ingress.yaml
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: ilb-demo-ingress
      namespace: default
      annotations:
        kubernetes.io/ingress.class: "gce-internal"
    spec:
      backend:
        serviceName: hostname
        servicePort: 80
    
  2. Ingress ファイルを作成したら、このリソースをクラスタに適用します。

    kubectl apply -f internal-ingress.yaml
    

Ingress が正常にデプロイされたことを検証する

このセクションでは、デプロイが成功したかどうかを検証します。

Ingress リソースが完全にプロビジョニングされるまでに数分かかることがあります。この間に、Ingress コントローラは転送ルール、バックエンド サービス、URL マップ、NEG などのアイテムを作成します。

前のセクションで作成した Ingress リソースのステータスを取得するには、次のコマンドを実行します。

kubectl get ingress ilb-demo-ingress

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

NAME               HOSTS    ADDRESS            PORTS     AGE
ilb-demo-ingress   *        10.128.0.58        80        59s

ADDRESS フィールドに値が入力されている場合、Ingress は動作可能な状態になっています。このフィールドの RFC 1918 アドレスは、VPC 内の内部 IP であることを意味します。

内部 HTTP(S) ロードバランサはリージョン ロードバランサであるため、仮想 IP(VIP)には同じリージョンの VPC 内のクライアントからのみアクセスできます。ロードバランサの VIP を取得したら、curl などのツールを使用して、VPC 内から VIP に対して HTTP GET 呼び出しを発行できます。

HTTP GET 呼び出しを発行するには、次の手順を行います。

  1. VPC 内から Ingress VIP にアクセスするには、クラスタと同じリージョンとネットワークに VM をデプロイします。

    たとえば、上記の手順に沿って Deployment、Service、Ingress を作成し、デフォルト ネットワークと us-central1-a ゾーンにクラスタを作成した場合は、次のコマンドを使用します。

    gcloud compute instances create l7-ilb-client-us-central1-a \
        --image-family=debian-9 \
        --image-project=debian-cloud \
        --network=default \
        --subnet=default \
        --zone=us-central1-a \
        --tags=allow-ssh
    

    インスタンスの作成方法について詳しくは、VM インスタンスの作成と起動をご覧ください。

  2. VM 内から内部 VIP にアクセスするには、curl を使用します。

    1. 前の手順で作成した VM に SSH 接続します。

      gcloud compute ssh l7-ilb-client-us-central1-a \
         --zone=us-central1-a
      
    2. curl を使用して内部アプリケーション VIP にアクセスします。

      curl 10.128.0.58
      hostname-server-6696cf5fc8-z4788
      

      成功を示す HTTP レスポンスとバックエンド コンテナのホスト名が返された場合、完全な負荷分散パスが正常に機能しています。

Ingress リソースを削除する

Ingress と Service のリソースを削除すると、関連する Compute Engine のロードバランサ リソースも削除されます。リソースのリークを防ぐため、不要になった Ingress リソースを破棄します。また、クラスタを削除する前に、Ingress リソースと Service リソースを削除する必要があります。そうしないと、Compute Engine 負荷分散リソースが孤立します。

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

  1. Ingress を削除します。たとえば、このページで作成した Ingress を削除するには、次のコマンドを実行します。

    kubectl delete ingress ilb-demo-ingress
    

    Ingress を削除すると、この Ingress リソースに関連付けられた転送ルール、バックエンド サービス、URL マップが削除されます。

  2. Service を削除します。たとえば、このページで作成した Service を削除するには、次のコマンドを実行します。

    kubectl delete service hostname
    

    Service を削除すると、Service に関連付けられている NEG が削除されます。

静的 IP アドレスの指定

内部 Ingress リソースでは、静的 IP アドレスとエフェメラル IP アドレスの両方がサポートされます。IP アドレスが指定されていなければ、GKE ノードのサブネットから使用可能な IP アドレスが自動的に割り振られます。ただし、Ingress リソースはプロキシ専用サブネットから IP アドレスを取得してプロビジョニングすることはしません。このサブネットは、内部プロキシを使用するためだけに利用されるからです。これらのエフェメラル IP アドレスは、内部 Ingress リソースのライフサイクルに対してのみ Ingress に割り振られます。ただし、Ingress を削除して同じマニフェスト ファイルから新しい Ingress を作成しても、同じ外部 IP アドレスが得られる保証はありません。

内部 Ingress リソースのライフサイクルとは独立した永続的な IP アドレスが必要な場合は、リージョン静的内部 IP アドレスを予約する必要があります。そのうえで、Ingress リソースで kubernetes.io/ingress.regional-static-ip-name アノテーションを使用して静的 IP アドレスを指定できます。

次の例は、このアノテーションを追加する方法を示しています。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.regional-static-ip-name: STATIC_IP_NAME
    kubernetes.io/ingress.class: "gce-internal"

STATIC_IP_NAME は、次の条件を満たす静的 IP 名で置き換えます。

  • Ingress をデプロイする前に静的 IP を作成します。ロードバランサは、静的 IP が作成されるまではデプロイされません。また、存在しない IP アドレス リソースを参照しても、静的 IP は作成されません。
  • Google Cloud IP アドレス リソースは、その IP アドレスではなく名前で参照するようにします。
  • この IP アドレスは、GKE クラスタと同じリージョン内のサブネットからのものである必要があります。リージョン(プロキシ専用サブネットを除く)内で使用可能なプライベート サブネットを使用できます。Ingress リソースごとに異なるサブネットから取得したアドレスを設定することもできます。

クライアントとロードバランサ間の HTTPS

内部負荷分散用の Ingress は、クライアントへの TLS 証明書の配信をサポートします。TLS 証明書は、Kubernetes Secret または Google Cloud の事前共有リージョン SSL 証明書を通じて提供できます。Ingress リソースごとに複数の証明書を指定することもできます。

以下の手順で、Google Cloud で証明書を作成し、Ingress を介して内部クライアントに配布する方法を説明します。

  1. リージョン証明書を作成します。

    gcloud compute ssl-certificates create CERT_NAME \
        --certificate CERT_FILE_PATH \
        --private-key KEY_FILE_PATH \
        --region REGION
    

    以下を置き換えます。

    • CERT_NAME: 証明書の名前を追加します。
    • CERT_FILE_PATH: ローカル証明書ファイルへのパスを追加してセルフマネージド証明書を作成します。証明書は PEM 形式にする必要があります。
    • KEY_FILE_PATH: ローカルの秘密鍵ファイルのパスを追加します。秘密鍵は PEM 形式にして、RSA または ECDSA 暗号化を使用する必要があります。
    • REGION: 証明書を適用するリージョンを追加します。
  2. Ingress を作成します。次の ingress-pre-shared-cert.yaml という名前の YAML ファイルは、作成する必要のある Ingress リソースの一例です。

    # ingress-pre-shared-cert.yaml
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: ilb-demo-ing
      namespace: default
      annotations:
        ingress.gcp.kubernetes.io/pre-shared-cert: "CERT_NAME"
        kubernetes.io/ingress.class: "gce-internal"
        kubernetes.io/ingress.allow-http: "false"
    spec:
      rules:
      - host: DOMAIN
        http:
          paths:
          - backend:
              serviceName: SERVICE_NAME
              servicePort: 80
    

    以下を置き換えます。

    • DOMAIN: ドメインを追加します。
    • CERT_NAME: 前のセクションで作成した証明書の名前を追加します。
    • SERVICE_NAME: Service の名前を追加します。
  3. Ingress を作成したら、このリソースをクラスタに適用します。

    kubectl apply -f ingress-pre-shared-cert.yaml
    

内部 Ingress アノテーションの概要

次の表は、内部 HTTP(S) 負荷分散用の Ingress に Ingress リソースと Service リソースを作成するときに追加できるアノテーションを示しています。

Ingress アノテーション

アノテーション 説明
kubernetes.io/ingress.class 内部 Ingress に対しては "gce-internal" と指定されます。クラスが指定されていない場合、Ingress リソースはデフォルトで外部 Ingress として解釈されます。
kubernetes.io/ingress.allow-http クライアントと HTTP(S) ロードバランサ間の HTTP トラフィックを許可するかどうかを指定します。有効な値は truefalse です。デフォルト値は true ですが、内部負荷分散に HTTPS を使用している場合は、このアノテーションを false に設定する必要があります。詳しくは、HTTP の無効化をご覧ください。
ingress.gcp.kubernetes.io/pre-shared-cert 証明書と鍵を Google Cloud プロジェクトにアップロードできます。このアノテーションを使用して証明書と鍵を参照します。詳細については、HTTP(S) 負荷分散での複数の SSL 証明書の使用をご覧ください。
アノテーション 説明
cloud.google.com/backend-config このアノテーションを使用して、servicePort に関連付けられるバックエンド サービスを構成します。詳細については、Ingress の機能をご覧ください。
cloud.google.com/neg このアノテーションを使用して、ロードバランサがネットワーク エンドポイント グループを使用するように指定します。詳しくは、コンテナ ネイティブの負荷分散を使用するをご覧ください。

トラブルシューティング

通常、Ingress の状態を把握および監視するには、Ingress に関連付けられているリソースの検査が必要になります。よく発生する問題としては、負荷分散リソースが適切に作成されない、トラフィックがバックエンドに到達しない、バックエンドが正常な状態でないといった問題が挙げられます。

一般的なトラブルシューティングの手順は次のとおりです。

  • クライアント トラフィックがロードバランサと同じリージョンおよび VPC 内から送信されていることを確認します。
  • Pod とバックエンドが正常な状態であることを確認します。
  • VIP へのトラフィック パスを確認します。Compute Engine ヘルスチェックの場合は、そのパスがファイアウォール ルールでブロックされていないことを確認します。
  • Ingress リソース イベントのエラーを確認します。
  • Ingress リソースの説明を参照して、Compute Engine リソースとのマッピングを確認します。
  • Compute Engine 負荷分散リソースが存在し、正しく構成されていて、エラーが報告されていないことを確認します。

Ingress イベントのフィルタリング

次のクエリを実行すると、クラスタ内のすべての Ingress イベントを対象にエラーをフィルタリングできます。

kubectl get events --all-namespaces --field-selector involvedObject.kind=Ingress

オブジェクトまたはオブジェクト名を基準にフィルタリングすることもできます。

kubectl get events --field-selector involvedObject.kind=Ingress,involvedObject.name=hostname-internal-ingress

次のエラーは、Ingress によって参照されている Service が存在しないことを示しています。

LAST SEEN   TYPE      REASON      OBJECT                              MESSAGE
0s          Warning   Translate   ingress/hostname-internal-ingress   error while evaluating the ingress spec: could not find service "default/hostname-invalid"

Compute Engine ロードバランサ リソースの検査

次のコマンドを実行すると、Ingress リソースの完全な出力が表示されます。これにより、Ingress コントローラによって作成された Compute Engine リソースへのマッピングを確認できます。

kubectl get ing INGRESS_FILENAME -o yaml

INGRESS_FILENAME を Ingress リソースのファイル名に置き換えます。

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

apiVersion: v1
items:
- apiVersion: networking.k8s.io/v1beta1
  kind: Ingress
  metadata:
    annotations:
      ingress.kubernetes.io/backends: '{"k8s1-241a2b5c-default-hostname-80-29269aa5":"HEALTHY"}'
      ingress.kubernetes.io/forwarding-rule: k8s-fw-default-ilb-demo-ingress--241a2b5c94b353ec
      ingress.kubernetes.io/target-proxy: k8s-tp-default-ilb-demo-ingress--241a2b5c94b353ec
      ingress.kubernetes.io/url-map: k8s-um-default-ilb-demo-ingress--241a2b5c94b353ec
      kubectl.kubernetes.io/last-applied-configuration: |
       {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"gce-internal"},"name":"ilb-demo-ingress","namespace":"default"},"spec":{"backend":{"serviceName":"hostname","servicePort":80}}}
      kubernetes.io/ingress.class: gce-internal
    creationTimestamp: "2019-10-15T02:16:18Z"
    finalizers:
    - networking.gke.io/ingress-finalizer
    generation: 1
    name: ilb-demo-ingress
    namespace: default
    resourceVersion: "1538072"
    selfLink: /apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/ilb-demo-ingress
    uid: 0ef024fe-6aea-4ee0-85f6-c2578f554975
  spec:
    backend:
      serviceName: hostname
      servicePort: 80
  status:
    loadBalancer:
      ingress:
      - ip: 10.128.0.127
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

ingress.kubernetes.io/backends アノテーションには、バックエンドとそのステータスの一覧が表示されています。バックエンドが HEALTHY になっていることを確認します。

Ingress で作成された Compute Engine リソースの場合は、直接クエリを送信してステータスと構成を確認できます。トラブルシューティングでも、これらのクエリを実行すると役立ちます。

Compute Engine 転送ルールの一覧を取得するには:

gcloud compute forwarding-rules list

出力例:

NAME                                                        REGION       IP_ADDRESS      IP_PROTOCOL  TARGET
k8s-fw-default-hostname-internal-ingress--42084f6a534c335b  us-central1  10.128.15.225   TCP          us-central1/targetHttpProxies/k8s-tp-default-hostname-internal-ingress--42084f6a534c335b

バックエンド サービスの状態を一覧表示するには、まずバックエンド サービスを一覧表示し、検査するバックエンド サービスの名前をコピーします。

gcloud compute backend-services list

出力例:

NAME                                         BACKENDS                                                                       PROTOCOL
k8s1-42084f6a-default-hostname-80-98cbc1c1   us-central1-a/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1 HTTP

これで、バックエンド サービス名を使用してヘルスチェックのクエリを実行できます。

gcloud compute backend-services get-health k8s1-42084f6a-default-hostname-80-98cbc1c1 \
    --region us-central1

出力例:

backend: https://www.googleapis.com/compute/v1/projects/user1-243723/zones/us-central1-a/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1
status:
  healthStatus:
  - healthState: HEALTHY

次のステップ