エッジからマルチクラスタ メッシュへ: GKE Gateway と Cloud Service Mesh を介してグローバルに分散されたアプリケーションをデプロイする

Last reviewed 2024-06-30 UTC

このドキュメントでは、次のタスクを行う方法について説明します。

このデプロイガイドは、プラットフォーム管理者を対象としています。また、Cloud Service Mesh を実行する上級者も対象としています。この手順は Istio on GKE でも使用できます。

アーキテクチャ

次の図は、サービス メッシュのデフォルトの Ingress トポロジを示しています。これは、単一クラスタで Ingress ゲートウェイ プロキシを公開する外部 TCP/UDP ロードバランサです。

外部ロードバランサは、外部クライアントを Ingress ゲートウェイ プロキシ経由でメッシュにルーティングします。

このデプロイガイドでは、Google Kubernetes Engine(GKE)Gateway リソースを使用します。具体的には、マルチクラスタ Gateway を使用して、2 つのリージョンに分散された複数の Autopilot クラスタの前にマルチリージョン ロード バランシングを構成します。

クライアント、ロードバランサ、メッシュからの TLS 暗号化。

上の図は、データが Cloud Ingress と Mesh Ingress のシナリオを通過する方法を示しています。詳細については、関連するリファレンス アーキテクチャ ドキュメントのアーキテクチャ図の説明をご覧ください。

目標

  • Google Cloud で GKE Autopilot クラスタのペアを同じフリートにデプロイします。
  • Istio ベースの Cloud Service Mesh を同じフリートにデプロイします。
  • GKE Gateway を使用してロードバランサを構成し、パブリック HTTPS トラフィックを終了します。
  • 複数のクラスタとリージョンにデプロイされた Cloud Service Mesh でホストされているアプリケーションに、パブリック HTTPS トラフィックを転送します。
  • whereami サンプル アプリケーションを両方の Autopilot クラスタにデプロイします。

費用の最適化

このドキュメントでは、課金対象である次の Google Cloudコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。

新規の Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    このデプロイでは、Cloud Shell からすべてのターミナル コマンドを実行します。

  4. デフォルトの Google Cloud プロジェクトを設定します。

    export PROJECT=YOUR_PROJECT
    export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)")
    gcloud config set project PROJECT_ID
    

    PROJECT_ID は、このデプロイで使用するプロジェクトの ID に置き換えます。

  5. 作業ディレクトリを作成します。

    mkdir -p ${HOME}/edge-to-mesh-multi-region
    cd ${HOME}/edge-to-mesh-multi-region
    export WORKDIR=`pwd`
    
  6. GKE クラスタを作成する

    このセクションでは、アプリケーションとサポート インフラストラクチャをホストする GKE クラスタを作成します。これらは、このデプロイガイドの後半で作成します。

    1. Cloud Shell で、新しい kubeconfig ファイルを作成します。この手順により、既存の(デフォルト)kubeconfig ファイルと競合しなくなります。

      touch edge2mesh_mr_kubeconfig
      export KUBECONFIG=${WORKDIR}/edge2mesh_mr_kubeconfig
      
    2. GKE クラスタとその内部のリソースの作成時に使用される環境変数を定義します。目的に合わせてデフォルトのリージョン選択を変更します。

      export CLUSTER_1_NAME=edge-to-mesh-01
      export CLUSTER_2_NAME=edge-to-mesh-02
      export CLUSTER_1_REGION=us-central1
      export CLUSTER_2_REGION=us-east4
      export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
      
    3. このガイド全体で使用される Google Cloud APIs を有効にします。

      gcloud services enable \
        container.googleapis.com \
        mesh.googleapis.com \
        gkehub.googleapis.com \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        certificatemanager.googleapis.com
      
    4. CLUSTER_1_REGIONプライベート ノードを含む GKE Autopilot クラスタを作成します。--async フラグを使用して、最初のクラスタがプロビジョニングされてフリートに登録されるまで待機しないようにします。

      gcloud container clusters create-auto --async \
      ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} \
      --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \
      --enable-private-nodes --enable-fleet
      
    5. CLUSTER_2_REGION に 2 つ目の Autopilot クラスタを作成して登録します。

      gcloud container clusters create-auto \
      ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} \
      --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \
      --enable-private-nodes --enable-fleet
      
    6. クラスタが実行されていることを確認します。すべてのクラスタが実行されるまでに最大 20 分かかることがあります。

      gcloud container clusters list
      

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

      NAME             LOCATION     MASTER_VERSION  MASTER_IP       MACHINE_TYPE  NODE_VERSION    NUM_NODES  STATUS
      edge-to-mesh-01  us-central1  1.27.5-gke.200  34.27.171.241   e2-small      1.27.5-gke.200             RUNNING
      edge-to-mesh-02  us-east4     1.27.5-gke.200  35.236.204.156  e2-small      1.27.5-gke.200             RUNNING
      
    7. CLUSTER_1_NAME の認証情報を収集します。CLUSTER_1_NAME は非同期で作成したため、クラスタのプロビジョニング中に追加のコマンドを実行できます。

      gcloud container clusters get-credentials ${CLUSTER_1_NAME} \
          --region ${CLUSTER_1_REGION}
      
    8. Kubernetes コンテキストの名前をわかりやすくするために、クラスタの名前に変更します。

      kubectl config rename-context gke_PROJECT_ID_${CLUSTER_1_REGION}_${CLUSTER_1_NAME} ${CLUSTER_1_NAME}
      kubectl config rename-context gke_PROJECT_ID_${CLUSTER_2_REGION}_${CLUSTER_2_NAME} ${CLUSTER_2_NAME}
      

    サービス メッシュをインストールする

    このセクションでは、Fleet API を使用してマネージド Cloud Service Mesh を構成します。Fleet API を使用して Cloud Service Mesh を有効にすると、サービス メッシュをプロビジョニングするための宣言型アプローチが提供されます。

    1. Cloud Shell で、フリートで Cloud Service Mesh を有効にします。

      gcloud container fleet mesh enable
      
    2. コントロール プレーンとデータプレーンの自動管理を有効にします。

      gcloud container fleet mesh update \
        --management automatic \
        --memberships ${CLUSTER_1_NAME},${CLUSTER_2_NAME}
      
    3. 20 分ほど待ちます。コントロール プレーンのステータスが ACTIVE になっていることを確認します。

      gcloud container fleet mesh describe
      

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

      createTime: '2023-11-30T19:23:21.713028916Z'
      membershipSpecs:
        projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01:
          mesh:
            management: MANAGEMENT_AUTOMATIC
        projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02:
          mesh:
            management: MANAGEMENT_AUTOMATIC
      membershipStates:
        projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01:
          servicemesh:
            controlPlaneManagement:
              details:
              - code: REVISION_READY
                details: 'Ready: asm-managed-rapid'
              implementation: ISTIOD
              state: ACTIVE
            dataPlaneManagement:
              details:
              - code: OK
                details: Service is running.
              state: ACTIVE
          state:
           code: OK
            description: |-
              Revision ready for use: asm-managed-rapid.
              All Canonical Services have been reconciled successfully.
            updateTime: '2024-06-27T09:00:21.333579005Z'
        projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02:
          servicemesh:
            controlPlaneManagement:
              details:
              - code: REVISION_READY
                details: 'Ready: asm-managed-rapid'
              implementation: ISTIOD
              state: ACTIVE
            dataPlaneManagement:
              details:
              - code: OK
                details: Service is running.
              state: ACTIVE
          state:
            code: OK
            description: |-
              Revision ready for use: asm-managed-rapid.
              All Canonical Services have been reconciled successfully.
            updateTime: '2024-06-27T09:00:24.674852751Z'
      name: projects/e2m-private-test-01/locations/global/features/servicemesh
      resourceState:
        state: ACTIVE
      spec: {}
      updateTime: '2024-06-04T17:16:28.730429993Z'
      

    外部アプリケーション ロードバランサをデプロイして、上り(内向き)ゲートウェイを作成する

    このセクションでは、GKE Gateway Controller を介して外部アプリケーション ロードバランサをデプロイし、両方のクラスタの Ingress ゲートウェイを作成します。gateway リソースと gatewayClass リソースは、ロードバランサとバックエンドのヘルスチェックのプロビジョニングを自動化します。ロードバランサで TLS 終端を提供するには、Certificate Manager リソースを作成してロードバランサに接続します。また、Endpoints を使用して、アプリケーションのパブリック DNS 名が自動的にプロビジョニングされます。

    両方のクラスタに Ingress ゲートウェイをインストールする

    セキュリティのベスト プラクティスとして、Ingress ゲートウェイは、メッシュ コントロール プレーンとは異なる名前空間にデプロイすることをおすすめします。

    1. Cloud Shell で、各クラスタに専用の asm-ingress Namespace を作成します。

      kubectl --context=${CLUSTER_1_NAME} create namespace asm-ingress
      kubectl --context=${CLUSTER_2_NAME} create namespace asm-ingress
      
    2. asm-ingress Namespace に Namespace ラベルを追加します。

      kubectl --context=${CLUSTER_1_NAME} label namespace asm-ingress istio-injection=enabled
      kubectl --context=${CLUSTER_2_NAME} label namespace asm-ingress istio-injection=enabled
      

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

      namespace/asm-ingress labeled
      

      asm-ingress Namespace に istio-injection=enabled というラベルを付けると、Pod のデプロイ時に Envoy サイドカー プロキシを自動挿入するよう Cloud Service Mesh が指示されます。

    3. 後で使用する自己署名証明書を生成します。

      openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
       -subj "/CN=frontend.endpoints.PROJECT_ID.cloud.goog/O=Edge2Mesh Inc" \
       -keyout ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
       -out ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
      

      証明書により、ロードバランサとサービス メッシュ Ingress ゲートウェイの間に暗号化のレイヤが追加されます。また、gRPC などの HTTP/2 ベースのプロトコルのサポートも有効になります。自己署名証明書を Ingress ゲートウェイに接続する方法については、後述の外部 IP アドレス、DNS レコード、TLS 証明書リソースを作成するをご覧ください。

      Ingress ゲートウェイ証明書の要件の詳細については、ロードバランサからバックエンドへの暗号化をご覧ください。

    4. 各クラスタに自己署名証明書を保存する Kubernetes Secret を作成します。

      kubectl --context ${CLUSTER_1_NAME} -n asm-ingress create secret tls \
       edge2mesh-credential \
       --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
       --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
      kubectl --context ${CLUSTER_2_NAME} -n asm-ingress create secret tls \
       edge2mesh-credential \
       --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
       --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
      
    5. 外部アプリケーション ロードバランサと統合するには、kustomize バリアントを作成して、Ingress ゲートウェイ リソースを構成します。

      mkdir -p ${WORKDIR}/asm-ig/base
      
      cat <<EOF > ${WORKDIR}/asm-ig/base/kustomization.yaml
      resources:
        - github.com/GoogleCloudPlatform/anthos-service-mesh-samples/docs/ingress-gateway-asm-manifests/base
      EOF
      
      mkdir ${WORKDIR}/asm-ig/variant
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/role.yaml
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      rules:
      - apiGroups: [""]
        resources: ["secrets"]
        verbs: ["get", "watch", "list"]
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/rolebinding.yaml
      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: asm-ingressgateway
      subjects:
        - kind: ServiceAccount
          name: asm-ingressgateway
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/service-proto-type.yaml
      apiVersion: v1
      kind: Service
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      spec:
        ports:
        - name: status-port
          port: 15021
          protocol: TCP
          targetPort: 15021
        - name: http
          port: 80
          targetPort: 8080
          appProtocol: HTTP
        - name: https
          port: 443
          targetPort: 8443
          appProtocol: HTTP2
        type: ClusterIP
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/gateway.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      spec:
       servers:
        - port:
            number: 443
            name: https
            protocol: HTTPS
          hosts:
          - "*" # IMPORTANT: Must use wildcard here when using SSL, as SNI isn't passed from GFE
          tls:
            mode: SIMPLE
            credentialName: edge2mesh-credential
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/kustomization.yaml
      namespace: asm-ingress
      resources:
      - ../base
      - role.yaml
      - rolebinding.yaml
      patches:
      - path: service-proto-type.yaml
        target:
          kind: Service
      - path: gateway.yaml
        target:
          kind: Gateway
      EOF
      
    6. 両方のクラスタに Ingress ゲートウェイ構成を適用します。

      kubectl --context ${CLUSTER_1_NAME} apply -k ${WORKDIR}/asm-ig/variant
      kubectl --context ${CLUSTER_2_NAME} apply -k ${WORKDIR}/asm-ig/variant
      

    マルチクラスタ サービスを使用して Ingress ゲートウェイ Pod をロードバランサに公開する

    このセクションでは、ServiceExport カスタム リソースを使用して上り(内向き)ゲートウェイ Pod をエクスポートします。次の理由から、ServiceExport カスタム リソースを使用して Ingress Gateway Pod をエクスポートする必要があります。

    1. Cloud Shell で、フリートのマルチクラスタ Service(MCS)を有効にします。

      gcloud container fleet multi-cluster-services enable
      
    2. MCS に、プロジェクトまたはフリートに必要な IAM 権限を付与します。

      gcloud projects add-iam-policy-binding PROJECT_ID \
       --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \
       --role "roles/compute.networkViewer"
      
    3. ServiceExport YAML ファイルを作成します。

      cat <<EOF > ${WORKDIR}/svc_export.yaml
      kind: ServiceExport
      apiVersion: net.gke.io/v1
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      EOF
      
    4. ServiceExport YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/svc_export.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/svc_export.yaml
      

      次のエラー メッセージが表示された場合は、MCS カスタム リソース定義(CRD)がインストールされるまでしばらく待ちます。次に、コマンドを再実行して、ServiceExport YAML ファイルを両方のクラスタに適用します。

      error: resource mapping not found for name: "asm-ingressgateway" namespace: "asm-ingress" from "svc_export.yaml": no matches for kind "ServiceExport" in version "net.gke.io/v1"
      ensure CRDs are installed first
      

    外部 IP アドレス、DNS レコード、TLS 証明書リソースを作成する

    このセクションでは、このデプロイで後で作成するロード バランシング リソースをサポートするネットワーキング リソースを作成します。

    1. Cloud Shell で、静的外部 IP アドレスを予約します。

      gcloud compute addresses create mcg-ip --global
      

      静的 IP アドレスは、GKE Gateway リソースで使用されます。これにより、外部ロードバランサが再作成されても、IP アドレスは同じままになります。

    2. 静的 IP アドレスを取得して、環境変数として保存します。

      export MCG_IP=$(gcloud compute addresses describe mcg-ip --global --format "value(address)")
      echo ${MCG_IP}
      

      Gateway IP アドレスとの安定した理解しやすいマッピングを作成するには、パブリック DNS レコードが必要です。

      任意の DNS プロバイダと自動化スキームを使用できます。このデプロイでは、マネージド DNS ゾーンを作成する代わりに Endpoints を使用します。Endpoints は、外部 IP アドレス用に無料の Google 管理 DNS レコードを提供します。

    3. 次のコマンドを実行して、dns-spec.yaml という名前の YAML ファイルを作成します。

      cat <<EOF > ${WORKDIR}/dns-spec.yaml
      swagger: "2.0"
      info:
        description: "Cloud Endpoints DNS"
        title: "Cloud Endpoints DNS"
        version: "1.0.0"
      paths: {}
      host: "frontend.endpoints.PROJECT_ID.cloud.goog"
      x-google-endpoints:
      - name: "frontend.endpoints.PROJECT_ID.cloud.goog"
        target: "${MCG_IP}"
      EOF
      

      dns-spec.yaml ファイルでは、frontend.endpoints.PROJECT_ID.cloud.goog の形式でパブリック DNS レコードが定義されます。PROJECT_ID は一意のプロジェクト ID です。

    4. dns-spec.yaml ファイルをデプロイして DNS エントリを作成します。この処理には数分かかります。

      gcloud endpoints services deploy ${WORKDIR}/dns-spec.yaml
      
    5. 前の手順で作成した DNS エントリ名に対して、Certificate Manager を使用して証明書を作成します。

      gcloud certificate-manager certificates create mcg-cert \
          --domains="frontend.endpoints.PROJECT_ID.cloud.goog"
      

      Google マネージド TLS 証明書は、ロードバランサでインバウンド クライアント リクエストを終了するために使用されます。

    6. 証明書マップを作成します。

      gcloud certificate-manager maps create mcg-cert-map
      

      ロードバランサは、次の手順で作成する証明書マップエントリを介して証明書を参照します。

    7. このセクションで作成した証明書の証明書マップエントリを作成します。

      gcloud certificate-manager maps entries create mcg-cert-map-entry \
          --map="mcg-cert-map" \
          --certificates="mcg-cert" \
          --hostname="frontend.endpoints.PROJECT_ID.cloud.goog"
      

    バックエンド サービス ポリシーとロードバランサ リソースを作成する

    このセクションでは、次のタスクを行います。

    • ルールを含む Cloud Armor セキュリティ ポリシーを作成します。
    • ロードバランサが、先ほど作成した ServiceExport YAML ファイルを使用して上り(内向き)ゲートウェイ Pod の応答性をチェックできるようにするポリシーを作成します。
    • GKE Gateway API を使用してロードバランサ リソースを作成します。
    • GatewayClass カスタム リソースを使用して、特定のロードバランサ タイプを設定します。
    • フリートのマルチクラスタ ロード バランシングを有効にして、クラスタの 1 つをフリートの構成クラスタとして指定します。
    1. Cloud Shell で、Cloud Armor セキュリティ ポリシーを作成します。

      gcloud compute security-policies create edge-fw-policy \
          --description "Block XSS attacks"
      
    2. セキュリティ ポリシーのルールを作成します。

      gcloud compute security-policies rules create 1000 \
          --security-policy edge-fw-policy \
          --expression "evaluatePreconfiguredExpr('xss-stable')" \
          --action "deny-403" \
          --description "XSS attack filtering"
      
    3. セキュリティ ポリシーの YAML ファイルを作成し、対応する ServiceImport YAML ファイルを介して ServiceExport YAML ファイルを参照します。

      cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml
      apiVersion: networking.gke.io/v1
      kind: GCPBackendPolicy
      metadata:
        name: cloud-armor-backendpolicy
        namespace: asm-ingress
      spec:
        default:
          securityPolicy: edge-fw-policy
        targetRef:
          group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
      EOF
      
    4. Cloud Armor ポリシーを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      
    5. 両方のクラスタの Ingress ゲートウェイ Pod の Envoy ヘルス エンドポイント(パス /healthz/ready のポート 15021)に対してロードバランサがヘルスチェックを実行できるようにするカスタム YAML ファイルを作成します。

      cat <<EOF > ${WORKDIR}/ingress-gateway-healthcheck.yaml
      apiVersion: networking.gke.io/v1
      kind: HealthCheckPolicy
      metadata:
        name: ingress-gateway-healthcheck
        namespace: asm-ingress
      spec:
        default:
          config:
            httpHealthCheck:
              port: 15021
              portSpecification: USE_FIXED_PORT
              requestPath: /healthz/ready
            type: HTTP
        targetRef:
          group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
      EOF
      
    6. 前の手順で作成したカスタム YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      
    7. フリートのマルチクラスタ ロード バランシングを有効にして、構成クラスタとして CLUSTER_1_NAME を指定します。

      gcloud container fleet ingress enable \
        --config-membership=${CLUSTER_1_NAME} \
        --location=${CLUSTER_1_REGION}
      
    8. フリート内の Gateway コントローラに IAM 権限を付与します。

      gcloud projects add-iam-policy-binding PROJECT_ID \
          --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \
          --role "roles/container.admin"
      
    9. gke-l7-global-external-managed-mc gatewayClass と、以前に作成した静的 IP アドレスを参照する Gateway カスタム リソースを使用して、ロードバランサ YAML ファイルを作成します。

      cat <<EOF > ${WORKDIR}/frontend-gateway.yaml
      kind: Gateway
      apiVersion: gateway.networking.k8s.io/v1
      metadata:
        name: external-http
        namespace: asm-ingress
        annotations:
          networking.gke.io/certmap: mcg-cert-map
      spec:
        gatewayClassName: gke-l7-global-external-managed-mc
        listeners:
        - name: http # list the port only so we can redirect any incoming http requests to https
          protocol: HTTP
          port: 80
        - name: https
          protocol: HTTPS
          port: 443
          allowedRoutes:
            kinds:
            - kind: HTTPRoute
        addresses:
        - type: NamedAddress
          value: mcg-ip
      EOF
      
    10. frontend-gateway YAML ファイルを両方のクラスタに適用します。別の構成クラスタを権限のあるクラスタとして指定しない限り、CLUSTER_1_NAME のみが権限のあるクラスタです。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
      
    11. Gateway リソースに Ingress ゲートウェイにリクエストを送信するように指示する default-httproute.yaml という名前の HTTPRoute YAML ファイルを作成します。

      cat << EOF > ${WORKDIR}/default-httproute.yaml
      apiVersion: gateway.networking.k8s.io/v1
      kind: HTTPRoute
      metadata:
        name: default-httproute
        namespace: asm-ingress
      spec:
        parentRefs:
        - name: external-http
          namespace: asm-ingress
          sectionName: https
        rules:
        - backendRefs:
          - group: net.gke.io
            kind: ServiceImport
            name: asm-ingressgateway
            port: 443
      EOF
      
    12. 前の手順で作成した HTTPRoute YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute.yaml
      
    13. HTTP から HTTP(S) へのリダイレクトを実行するには、default-httproute-redirect.yaml という名前の追加の HTTPRoute YAML ファイルを作成します。

      cat << EOF > ${WORKDIR}/default-httproute-redirect.yaml
      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1
      metadata:
        name: http-to-https-redirect-httproute
        namespace: asm-ingress
      spec:
        parentRefs:
        - name: external-http
          namespace: asm-ingress
          sectionName: http
        rules:
        - filters:
          - type: RequestRedirect
            requestRedirect:
              scheme: https
              statusCode: 301
      EOF
      
    14. リダイレクト HTTPRoute YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
      
    15. Gateway リソースを調べて、ロードバランサのデプロイの進行状況を確認します。

      kubectl --context=${CLUSTER_1_NAME} describe gateway external-http -n asm-ingress
      

      出力には、このセクションで入力した情報が表示されます。

    whereami サンプル アプリケーションをデプロイする

    このガイドでは、whereami をサンプル アプリケーションとして使用して、リクエストに応答しているクラスタに関するフィードバックを直接提供します。次のセクションでは、両方のクラスタに whereami の 2 つの別々のデプロイ(frontend デプロイと backend デプロイ)を設定します。

    frontend デプロイは、リクエストを受信する最初のワークロードです。次に、backend デプロイを呼び出します。

    このモデルは、マルチサービス アプリケーション アーキテクチャを示すために使用されます。frontend サービスと backend サービスの両方が両方のクラスタにデプロイされます。

    1. Cloud Shell で、両方のクラスタに whereami frontend と whereami backend の Namespace を作成し、Namespace インジェクションを有効にします。

      kubectl --context=${CLUSTER_1_NAME} create ns frontend
      kubectl --context=${CLUSTER_1_NAME} label namespace frontend istio-injection=enabled
      kubectl --context=${CLUSTER_1_NAME} create ns backend
      kubectl --context=${CLUSTER_1_NAME} label namespace backend istio-injection=enabled
      kubectl --context=${CLUSTER_2_NAME} create ns frontend
      kubectl --context=${CLUSTER_2_NAME} label namespace frontend istio-injection=enabled
      kubectl --context=${CLUSTER_2_NAME} create ns backend
      kubectl --context=${CLUSTER_2_NAME} label namespace backend istio-injection=enabled
      
    2. whereami backend の kustomize バリアントを作成します。

      mkdir -p ${WORKDIR}/whereami-backend/base
      
      cat <<EOF > ${WORKDIR}/whereami-backend/base/kustomization.yaml
      resources:
        - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
      EOF
      
      mkdir ${WORKDIR}/whereami-backend/variant
      
      cat <<EOF > ${WORKDIR}/whereami-backend/variant/cm-flag.yaml
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: whereami
      data:
        BACKEND_ENABLED: "False" # assuming you don't want a chain of backend calls
        METADATA:        "backend"
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-backend/variant/service-type.yaml
      apiVersion: "v1"
      kind: "Service"
      metadata:
        name: "whereami"
      spec:
        type: ClusterIP
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-backend/variant/kustomization.yaml
      nameSuffix: "-backend"
      namespace: backend
      commonLabels:
        app: whereami-backend
      resources:
      - ../base
      patches:
      - path: cm-flag.yaml
        target:
          kind: ConfigMap
      - path: service-type.yaml
        target:
          kind: Service
      EOF
      
    3. whereami backend バリアントを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-backend/variant
      kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-backend/variant
      
    4. whereami frontend の kustomize バリアントを作成します。

      mkdir -p ${WORKDIR}/whereami-frontend/base
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/base/kustomization.yaml
      resources:
        - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
      EOF
      
      mkdir whereami-frontend/variant
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/variant/cm-flag.yaml
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: whereami
      data:
        BACKEND_ENABLED: "True"
        BACKEND_SERVICE: "http://whereami-backend.backend.svc.cluster.local"
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/variant/service-type.yaml
      apiVersion: "v1"
      kind: "Service"
      metadata:
        name: "whereami"
      spec:
        type: ClusterIP
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/variant/kustomization.yaml
      nameSuffix: "-frontend"
      namespace: frontend
      commonLabels:
        app: whereami-frontend
      resources:
      - ../base
      patches:
      - path: cm-flag.yaml
        target:
          kind: ConfigMap
      - path: service-type.yaml
        target:
          kind: Service
      EOF
      
    5. whereami frontend バリアントを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
      kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
      
    6. whereami frontend にリクエストを転送する VirtualService YAML ファイルを作成します。

      cat << EOF > ${WORKDIR}/frontend-vs.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: whereami-vs
        namespace: frontend
      spec:
        gateways:
        - asm-ingress/asm-ingressgateway
        hosts:
        - 'frontend.endpoints.PROJECT_ID.cloud.goog'
        http:
        - route:
          - destination:
              host: whereami-frontend
              port:
                number: 80
      EOF
      
    7. frontend-vs YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
      
    8. 両方のクラスタに frontend-vs.yaml をデプロイしたので、クラスタのパブリック エンドポイントを呼び出してみます。

      curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
      

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

      {
        "backend_result": {
          "cluster_name": "edge-to-mesh-02",
          "gce_instance_id": "8396338201253702608",
          "gce_service_account": "e2m-mcg-01.svc.id.goog",
          "host_header": "whereami-backend.backend.svc.cluster.local",
          "metadata": "backend",
          "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-645h",
          "pod_ip": "10.124.0.199",
          "pod_name": "whereami-backend-7cbdfd788-8mmnq",
          "pod_name_emoji": "📸",
          "pod_namespace": "backend",
          "pod_service_account": "whereami-backend",
          "project_id": "e2m-mcg-01",
          "timestamp": "2023-12-01T03:46:24",
          "zone": "us-east4-b"
        },
        "cluster_name": "edge-to-mesh-01",
        "gce_instance_id": "1047264075324910451",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
        "metadata": "frontend",
        "node_name": "gk3-edge-to-mesh-01-pool-2-d687e3c0-5kf2",
        "pod_ip": "10.54.1.71",
        "pod_name": "whereami-frontend-69c4c867cb-dgg8t",
        "pod_name_emoji": "🪴",
        "pod_namespace": "frontend",
        "pod_service_account": "whereami-frontend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T03:46:24",
        "zone": "us-central1-c"
      }
      

    curl コマンドを数回実行すると、レスポンス(frontendbackend の両方)が異なるリージョンから返されることがわかります。ロードバランサは、レスポンスで地理情報ルーティングを提供しています。つまり、ロードバランサはクライアントからのリクエストを最も近いアクティブなクラスタにルーティングしていますが、リクエストはランダムに転送されています。リクエストがリージョン間で頻繁に移動すると、レイテンシと費用が増加します。

    次のセクションでは、リクエストをローカルに維持するために、サービス メッシュに地域ロード バランシングを実装します。

    whereami の地域によるロード バランシングを有効にしてテストする

    このセクションでは、リクエストをローカルに維持するために、サービス メッシュにローカリティ ロード バランシングを実装します。また、whereami がさまざまな障害シナリオをどのように処理するかを確認するテストも実施します。

    whereami frontend サービスにリクエストを送信すると、ロードバランサはクライアントに対するレイテンシが最も低いクラスタにリクエストを送信します。つまり、メッシュ内の Ingress ゲートウェイ Pod は、両方のクラスタの whereami frontend Pod にリクエストをロードバランスします。このセクションでは、メッシュ内で局所性ロード バランシングを有効にして、この問題に対処します。

    1. Cloud Shell で、frontend サービスへのローカル ロード バランシングのリージョン フェイルオーバーを有効にする DestinationRule YAML ファイルを作成します。

      cat << EOF > ${WORKDIR}/frontend-dr.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: frontend
        namespace: frontend
      spec:
        host: whereami-frontend.frontend.svc.cluster.local
        trafficPolicy:
          connectionPool:
            http:
              maxRequestsPerConnection: 0
          loadBalancer:
            simple: LEAST_REQUEST
            localityLbSetting:
              enabled: true
          outlierDetection:
            consecutive5xxErrors: 1
            interval: 1s
            baseEjectionTime: 1m
      EOF
      

      上記のコードサンプルでは、frontend サービスのローカル ルーティングのみが有効になります。バックエンドを処理する追加の構成も必要です。

    2. frontend-dr YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
      
    3. backend サービスへのローカル ロード バランシング リージョン フェイルオーバーを有効にする DestinationRule YAML ファイルを作成します。

      cat << EOF > ${WORKDIR}/backend-dr.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: backend
        namespace: backend
      spec:
        host: whereami-backend.backend.svc.cluster.local
        trafficPolicy:
          connectionPool:
            http:
              maxRequestsPerConnection: 0
          loadBalancer:
            simple: LEAST_REQUEST
            localityLbSetting:
              enabled: true
          outlierDetection:
            consecutive5xxErrors: 1
            interval: 1s
            baseEjectionTime: 1m
      EOF
      
    4. backend-dr YAML ファイルを両方のクラスタに適用します。

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/backend-dr.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/backend-dr.yaml
      

      両方のクラスタに両方の DestinationRule YAML ファイルが適用されているため、リクエストはリクエストの転送先クラスタのローカルに留まります。

      frontend サービスのフェイルオーバーをテストするには、プライマリ クラスタの Ingress ゲートウェイのレプリカ数を減らします。

      マルチリージョン ロードバランサの観点から見ると、このアクションはクラスタ障害をシミュレートします。これにより、クラスタのロードバランサのヘルスチェックが失敗します。この例では、CLUSTER_1_REGION のクラスタを使用します。CLUSTER_2_REGION のクラスタからのレスポンスのみが表示されます。

    5. プライマリ クラスタの Ingress ゲートウェイのレプリカ数をゼロに減らし、パブリック エンドポイントを呼び出して、リクエストが他のクラスタにフェイルオーバーしたことを確認します。

      kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=0 deployment/asm-ingressgateway
      

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

      $ curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
      {
        "backend_result": {
          "cluster_name": "edge-to-mesh-02",
          "gce_instance_id": "2717459599837162415",
          "gce_service_account": "e2m-mcg-01.svc.id.goog",
          "host_header": "whereami-backend.backend.svc.cluster.local",
          "metadata": "backend",
          "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-dxs2",
          "pod_ip": "10.124.1.7",
          "pod_name": "whereami-backend-7cbdfd788-mp8zv",
          "pod_name_emoji": "🏌🏽‍♀",
          "pod_namespace": "backend",
          "pod_service_account": "whereami-backend",
          "project_id": "e2m-mcg-01",
          "timestamp": "2023-12-01T05:41:18",
          "zone": "us-east4-b"
        },
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "6983018919754001204",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
        "metadata": "frontend",
        "node_name": "gk3-edge-to-mesh-02-pool-3-d42ddfbf-qmkn",
        "pod_ip": "10.124.1.142",
        "pod_name": "whereami-frontend-69c4c867cb-xf8db",
        "pod_name_emoji": "🏴",
        "pod_namespace": "frontend",
        "pod_service_account": "whereami-frontend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T05:41:18",
        "zone": "us-east4-b"
      }
      
    6. 通常のトラフィック ルーティングを再開するには、クラスタ内の Ingress ゲートウェイ レプリカを元の値に復元します。

      kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=3 deployment/asm-ingressgateway
      
    7. プライマリ リージョンのレプリカ数を 0 に減らして、backend サービスの障害をシミュレートします。

      kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=0 deployment/whereami-backend
      

      frontend サービスからのレスポンスがロードバランサを介して us-central1 プライマリ リージョンから送信され、backend サービスからのレスポンスが us-east4 セカンダリ リージョンから送信されることを確認します。

      出力には、プライマリ リージョン(us-central1)からの frontend サービスのレスポンスと、セカンダリ リージョン(us-east4)からの backend サービスのレスポンスも含まれます。

    8. バックエンド サービス レプリカを元の値に戻して、通常のトラフィック ルーティングを再開します。

      kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=3 deployment/whereami-backend
      

    これで、サービス メッシュでホストされるマルチリージョン アプリケーションのフロントエンドとして機能するグローバル HTTP(S) ロードバランサが作成されました。

    クリーンアップ

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

    プロジェクトの削除

    1. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    2. In the project list, select the project that you want to delete, and then click Delete.
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    個々のリソースの削除

    このデプロイで使用した Google Cloud プロジェクトを残しておく場合は、個々のリソースを削除します。

    1. Cloud Shell で、次のとおり HTTPRoute リソースを削除します。

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute.yaml
      
    2. GKE Gateway リソースを削除します。

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
      
    3. ポリシーを削除します。

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      
    4. サービス エクスポートを削除します。

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/svc_export.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/svc_export.yaml
      
    5. Cloud Armor リソースを削除します。

      gcloud --project=PROJECT_ID compute security-policies rules delete 1000 --security-policy edge-fw-policy --quiet
      gcloud --project=PROJECT_ID compute security-policies delete edge-fw-policy --quiet
      
    6. Certificate Manager リソースを削除します。

      gcloud --project=PROJECT_ID certificate-manager maps entries delete mcg-cert-map-entry --map="mcg-cert-map" --quiet
      gcloud --project=PROJECT_ID certificate-manager maps delete mcg-cert-map --quiet
      gcloud --project=PROJECT_ID certificate-manager certificates delete mcg-cert --quiet
      
    7. Endpoints DNS エントリを削除します。

      gcloud --project=PROJECT_ID endpoints services delete "frontend.endpoints.PROJECT_ID.cloud.goog" --quiet
      
    8. 静的 IP アドレスを削除します。

      gcloud --project=PROJECT_ID compute addresses delete mcg-ip --global --quiet
      
    9. GKE Autopilot クラスタを削除します。このステップには数分かかります。

      gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} --quiet
      gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} --quiet
      

    次のステップ

    寄稿者

    作成者:

    • Alex Mattson | アプリケーション スペシャリスト エンジニア
    • Mark Chilvers | アプリケーション スペシャリスト エンジニア

    その他の寄稿者: