Ingress による HTTP(S) 負荷分散の設定

このチュートリアルでは、Ingress リソースを構成することにより、外部 HTTP(S) ロードバランサの背後でウェブ アプリケーションを実行する方法について説明します。

背景

Google Kubernetes Engine(GKE)には、一般公開するアプリケーション用に次の 2 種類の Cloud Load Balancing のサポートが組み込まれています。

  • リソース マニフェストに type:LoadBalancer を指定すると、GKE は LoadBalancer タイプの Service を作成します。GKE は、適切な Google Cloud API 呼び出しを行い、外部ネットワーク ロードバランサまたは内部 TCP / UDP ロードバランサを作成します。cloud.google.com/load-balancer-type: "Internal" アノテーションを追加すると、GKE は内部 TCP / UDP ロードバランサを作成します。追加しない場合、GKE は外部ネットワーク ロードバランサを作成します。

    このいずれかのロードバランサを HTTP(S) トラフィックの処理に使用できますが、これらは OSI レイヤ 3 または 4 で動作します。このため、HTTP 接続や、個々の HTTP リクエストとレスポンスを認識しません。もう 1 つの重要な特長は、リクエストがプロキシ経由で宛先に送信されない点です。

  • リソース マニフェストに kind:Ingress を指定すると、GKE は Ingress リソースを作成します。アノテーション、サポート ワークロード、Service を指定すると、独自の Ingress コントローラを作成できます。それ以外の場合、GKE は適切な Google Cloud API 呼び出しを行い、外部 HTTP(S) ロードバランサを作成します。ロードバランサの URL マップのホストルールとパスマッチャーは 1 つ以上のバックエンド サービスを参照します。Ingress で参照されているように、各バックエンド サービスは NodePort タイプの GKE Service に対応しています。各バックエンド サービスのバックエンドは、インスタンス グループまたはネットワーク エンドポイント グループ(NEG)のいずれかです。Ingress の構成の一部として コンテナ ネイティブの負荷分散を構成すると、NEG が作成されます。GKE は、対応する GKE Service が参照するワークロードの readinessProbe 設定に基づいて、バックエン ドサービスごとに Google Cloud ヘルスチェックを作成します。

    GKE でホストされている HTTP(S) サービスを公開する場合は、負荷分散として HTTP(S) 負荷分散の利用をおすすめします。

目標

  • GKE クラスタを作成する。
  • サンプル ウェブ アプリケーションをクラスタにデプロイする。
  • 外部 HTTP(S) ロードバランサの背後にあるサンプルアプリをインターネットに公開する。

始める前に

次の手順で Kubernetes Engine API を有効にします。
  1. Google Cloud Console で Kubernetes Engine ページにアクセスします。
  2. プロジェクトを作成または選択します。
  3. API と関連サービスが有効になるのを待ちます。 これには数分かかることがあります。
  4. Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

このチュートリアルで使用されている以下のコマンドライン ツールをインストールします。

  • gcloud は、Kubernetes Engine クラスタの作成と削除に使用されます。gcloud は、Google Cloud SDK に含まれています。
  • kubectl は、Kubernetes Engine で使用されるクラスタ オーケストレーション システムである Kubernetes の管理に使用されます。gcloud を使用して kubectl をインストールできます。
    gcloud components install kubectl

GitHub からサンプルコードのクローンを作成します。

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd kubernetes-engine-samples/load-balancing

gcloud コマンドライン ツールのデフォルトの設定

次のようにしてデフォルト値を設定しておくと、gcloud コマンドライン ツールでプロジェクト ID および Compute Engine ゾーン オプションを入力する時間が節約されます。
gcloud config set project project-id
gcloud config set compute/zone compute-zone

コンテナ クラスタの作成

次のコマンドを実行して、loadbalancedcluster という名前のコンテナ クラスタを作成します。

gcloud container clusters create loadbalancedcluster

ウェブ アプリケーションのデプロイ

次のマニフェストでは、ポート 8080 で HTTP サーバー上でサンプル ウェブ アプリケーション コンテナ イメージを実行する Deployment を記述しています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: default
spec:
  selector:
    matchLabels:
      run: web
  template:
    metadata:
      labels:
        run: web
    spec:
      containers:
      - image: gcr.io/google-samples/hello-app:1.0
        imagePullPolicy: IfNotPresent
        name: web
        ports:
        - containerPort: 8080
          protocol: TCP

リソースをクラスタに適用します。

kubectl apply -f web-deployment.yaml

クラスタ内での Deployment の公開

次のマニフェストでは、web Deployment をコンテナ クラスタ内でアクセス可能にする Service が記述されています。

apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: default
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    run: web
  type: NodePort
  1. リソースをクラスタに適用します。

    kubectl apply -f web-service.yaml
    

    このコマンドで NodePort タイプの Service を作成すると、クラスタ内のすべてのノードで、ランダムに選択された上位ポート番号(32640 など)を使用して Service を利用できるようになります。

  2. Service が作成され、ノードポートが割り当てられたことを確認します。

    kubectl get service web
    
    出力:
    NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    web       NodePort   10.35.245.219   <none>        8080:32640/TCP   5m
    

    このサンプル出力では、web Service のノードポートは 32640 です。また、この Service には外部 IP アドレスが割り振られていないことに注意してください。デフォルトで GKE ノードに外部からアクセスすることはできないため、この Service を作成しても、インターネットからアプリケーションにアクセスできるようにはなりません。

HTTP(S) ウェブサーバー アプリケーションを公開するには、Ingress リソースを作成する必要があります。

Ingress リソースの作成

Ingress は、外部 HTTP(S) トラフィックを内部サービスにルーティングするためのルールと構成の集合をカプセル化する Kubernetes リソースです。

GKE では、Ingress は Cloud Load Balancing を使用して実装されます。クラスタで Ingress を作成すると、GKE により HTTP(S) ロードバランサが作成され、トラフィックをアプリケーションにルーティングするように構成されます。

Kubernetes Ingress はベータ版リソースであり、Ingress オブジェクトの記述方法は変更される可能性がありますが、GKE で Ingress を実装するためにプロビジョニングされる Cloud Load Balancer は、本番環境に対応しています。

次のマニフェストでは、トラフィックを web Service に転送する Ingress リソースが記述されています。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: basic-ingress
spec:
  backend:
    serviceName: web
    servicePort: 8080

リソースをクラスタに適用します。

kubectl apply -f basic-ingress.yaml

このマニフェストをデプロイすると、Kubernetes によってクラスタに Ingress リソースが作成されます。GKE Ingress コントローラでは、Ingress の情報に従って HTTP(S) ロードバランサを作成して構成し、すべての外部 HTTP トラフィック(ポート 80)を、公開した web NodePort Service にルーティングします。

アプリケーションへのアクセス

次のコマンドを実行して、アプリケーションに対応するロードバランサの外部 IP アドレスを調べます。

kubectl get ingress basic-ingress
出力:
NAME            HOSTS     ADDRESS         PORTS     AGE
basic-ingress   *         203.0.113.12    80        2m

ブラウザでアプリケーションの外部 IP アドレスを開くと、次のような書式なしテキストの HTTP レスポンスが表示されます。

Hello, world!
Version: 1.0.0
Hostname: web-6498765b79-fq5q5

Cloud Console の [負荷分散] にアクセスすると、GKE Ingress コントローラによって作成されたネットワーキング リソースを調べることができます。

(省略可)静的 IP アドレスの構成

ドメイン名でウェブサーバーを公開する場合、アプリケーションの外部 IP アドレスを変化しない静的 IP アドレスにする必要があります。

デフォルトで、Ingress によって公開される HTTP アプリケーションに GKE が割り振るのはエフェメラル外部 IP アドレスです。エフェメラル アドレスは変化する可能性があります。長期間使用する予定のウェブ アプリケーションでは、静的外部 IP アドレスを使用する必要があります。

Ingress リソースに静的 IP を構成した場合、Ingress を削除しても、それに関連付けられている静的 IP アドレスは削除されないことに注意してください。構成した静的 IP アドレスを再び使用する予定がない場合は、クリーンアップが必要になります。

静的 IP アドレスを構成するには、次の手順を行います。

  1. web-static-ip という静的外部 IP アドレスを予約します。

    gcloud

    gcloud compute addresses create web-static-ip --global
    

    Config Connector

    注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順を実施してください。

    apiVersion: compute.cnrm.cloud.google.com/v1beta1
    kind: ComputeAddress
    metadata:
      name: web-static-ip
    spec:
      location: global
    このマニフェストをデプロイするには、マニフェストを compute-address.yaml というファイル名でマシンにダウンロードしてから、次のコマンドを実行します。
    kubectl apply -f compute-address.yaml

  2. basic-ingress-static.yaml マニフェストは、web-static-ip という名前の静的 IP リソースを使用するためのアノテーションを Ingress に追加します。

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: basic-ingress
      annotations:
        kubernetes.io/ingress.global-static-ip-name: "web-static-ip"
    spec:
      backend:
        serviceName: web
        servicePort: 8080
    

    マニフェストを確認します。

    cat basic-ingress-static.yaml
    
  3. リソースをクラスタに適用します。

    kubectl apply -f basic-ingress-static.yaml
    
  4. 外部 IP アドレスを確認します。

    kubectl get ingress basic-ingress
    

    web-static-ip リソースの予約済み IP アドレスを使用するようにアプリケーションの IP アドレスが変更されるまで待ちます。

    既存の Ingress リソースの更新、ロードバランサの再構成、および負荷分散ルールが世界中に伝播されるまで、数分かかることがあります。このオペレーションが完了すると、以前にアプリケーションに割り振られていたエフェメラル IP アドレスが解放されます。

(省略可)1 つのロードバランサで複数のアプリケーションに対応する

Ingress でルーティング ルールを構成することにより、単一のロードバランサとパブリック IP アドレスで複数のサービスを実行できます。同じ Ingress で複数のサービスをホストすると、インターネットに公開する Service ごとに追加のロードバランサ(課金対象のリソース)を作成しなくて済みます。

次のマニフェストでは、同じウェブ アプリケーションのバージョン 2.0 を使用した Deployment が記述されています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web2
  namespace: default
spec:
  selector:
    matchLabels:
      run: web2
  template:
    metadata:
      labels:
        run: web2
    spec:
      containers:
      - image: gcr.io/google-samples/hello-app:2.0
        imagePullPolicy: IfNotPresent
        name: web2
        ports:
        - containerPort: 8080
          protocol: TCP

リソースをクラスタに適用します。

kubectl apply -f web-deployment-v2.yaml

次のマニフェストでは、web2 と呼ばれる NodePort Service 上のクラスタに web2 を内部公開する Service が記述されています。

apiVersion: v1
kind: Service
metadata:
  name: web2
  namespace: default
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    run: web2
  type: NodePort

リソースをクラスタに適用します。

kubectl apply -f web-service-v2.yaml

以下に示すマニフェストは、次のような Ingress リソースを記述しています。

  • /v2/ でパスが始まるリクエストを web2 Service にルーティングする。
  • 他のすべてのリクエストを web Service にルーティングする。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: fanout-ingress
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: web
          servicePort: 8080
      - path: /v2/*
        backend:
          serviceName: web2
          servicePort: 8080

リソースをクラスタに適用します。

kubectl create -f fanout-ingress.yaml

Ingress をデプロイした後、kubectl get ingress fanout-ingress を実行してクラスタのパブリック IP アドレスを調べます。

次に、IP アドレスを参照して、両方のアプリケーションが同じロードバランサ上で到達可能であることを確認します。

  • http://<IP_ADDRESS>/ に移動し、レスポンスに Version: 1.0.0 が含まれていることを確認します(リクエストは web Service にルーティングされる)。
  • http://<IP_ADDRESS>/v2/ に移動し、レスポンスに Version: 2.0.0 が含まれていることを確認します(リクエストは web2 Service にルーティングされる)。

Ingress の path フィールドでサポートされているワイルドカード文字は「*」のみです。「*」はスラッシュ(「/」)の直後に置かれる必要があり、パターンの最後の文字でなければなりません。たとえば、/*/foo/*/foo/bar/* は有効なパターンですが、*/foo/bar*/foo/*/bar は有効ではありません。

より具体的なパターンのほうが、そうでないものよりも優先されます。/foo/*/foo/bar/* の両方を使用すると、/foo/bar/bat/foo/bar/* と比較されます。

パスの制限とパターン マッチングの詳細については、URL マップのドキュメントをご覧ください。

(省略可)サービスの可用性とレイテンシをモニタリングする

Google Cloud の稼働時間チェックでは、ユーザーの視点からアプリケーションのブラックボックス モニタリングを実行し、複数の外部 IP からロードバランサの IP アドレスへのレイテンシと可用性を決定します。これに対して、Google Cloud のヘルスチェックは Pod IP に対して内部チェックを実行し、インスタンス レベルでの可用性を決定します。この 2 つは補完的な関係にあり、アプリケーションの健全性を総合的に把握できます。

稼働時間チェックを作成するには、Google Cloud Console または Cloud Monitoring API を使用するか、Cloud Monitoring クライアント ライブラリを使用します。詳しくは、稼働時間チェックの管理をご覧ください。Google Cloud Console を使用して稼働時間チェックを作成する手順は次のとおりです。

  1. Google Cloud Console で [Monitoring] を選択するか、次のボタンをクリックします。

    [Monitoring] に移動

  2. [Monitoring] ナビゲーション パネルで、[稼働時間チェック] を選択し、[稼働時間チェックの作成] をクリックします。

  3. 稼働時間チェックのターゲットとして、次のフィールドを設定します。

    • プロトコルのタイプとして [TCP] を選択します。
    • [リソースの種類] として [URL] を選択します。
    • [Hostname] にロードバランサの IP アドレスを入力します。
    • [Port] フィールドにロードバランサのポート番号を入力します。

    稼働時間チェックのすべてのフィールドの詳細については、稼働時間チェックの作成をご覧ください。

稼働時間チェックをモニタリングするには、アラート ポリシーを作成するか、稼働時間チェック ダッシュボードを表示します。稼働時間チェックに失敗した場合は、アラート ポリシーによってメールまたは別のチャネルで通知されます。アラート ポリシーの概要については、アラートの概要をご覧ください。

備考

デフォルトでは、Ingress は GET リクエストを / パスで実行してアプリケーションの状態を判断することで定期的なヘルスチェックを実行し、HTTP 200 レスポンスを待ちます。別のパスをチェックしたい場合、または別のレスポンス コードを待つ場合は、カスタム ヘルスチェック パスを使用できます。

Ingress は、次のような高度なユースケースをサポートしています。

  • 名前ベースの仮想ホスティング: Ingress を使用して、複数のドメイン名およびサブドメインに対してロードバランサを再利用し、複数の Service を 1 つの IP アドレスとロードバランサで公開できます。これらのタスク用に Ingress を構成する方法については、簡単なファンアウト名前ベースの仮想ホスティングの例をご覧ください。

  • HTTPS 終了: Cloud Load Balancer を使用して HTTPS トラフィックを終了させるように Ingress を構成できます。

Ingress を削除すると、関連付けられているリソース(予約された静的 IP アドレスを除く)は GKE Ingress コントローラによって自動的にクリーンアップされます。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

  1. 手動で作成した転送ルールと、Ingress を参照するターゲット プロキシを削除します。

    GKE Ingress コントローラのマネージド URL マップを参照しているターゲット プロキシが不要である場合、1.15.4-gke.22 以降の GKE バージョンでは Ingress を削除できません。Ingress リソースを調べて、次のようなエラー メッセージを含むイベントを確認します。

     Error during GC: error running load balancer garbage collection routine: googleapi: Error 400: The url_map resource 'projects/project-id/global/urlMaps/k8s2-um-tlw9rhgp-default-my-ingress-9ifnni82' is already being used by 'projects/project-id/global/targetHttpsProxies/k8s2-um-tlw9rhgp-default-my82-target-proxy', resourceInUseByAnotherResource
     

    上記のエラー メッセージの例では、k8s2-um-tlw9rhgp-default-my82-target-proxy は手動で作成されたターゲット https プロキシであり、Ingress コントローラによって作成、管理された URL マップ k8s2-um-tlw9rhgp-default-my-ingress-9ifnni82 を引き続き参照しています。

    手動で作成したフロントエンド リソース(転送ルールとターゲット プロキシの両方)を削除してから Ingress を削除する必要があります。

  2. Ingress を削除する: アプリケーションに関連付けられているエフェメラル外部 IP アドレスと負荷分散リソースの割り振りを解除します。

    kubectl delete ingress basic-ingress

    オプションの手順でパスによってリクエストをルーティングする Ingress を作成した場合は、Ingress を削除します。

    kubectl delete ingress fanout-ingress

  3. 静的 IP アドレスを削除する: この手順は、オプションの手順を行って静的 IP アドレスを作成した場合にのみ行ってください。

    • 「オプション 1」に従って既存のエフェメラル IP アドレスを静的 IP に変換した場合は、Cloud Console にアクセスして静的 IP アドレスを削除します。

    • 「オプション 2」に従って新しい静的 IP アドレスを作成した場合は、次のコマンドを実行して静的 IP アドレスを削除します。

      gcloud compute addresses delete web-static-ip --global
  4. クラスタを削除する: コンテナ クラスタのコンピューティング ノードとその他のリソース(クラスタ内の Deployment など)を削除します。

    gcloud container clusters delete loadbalancedcluster

次のステップ