エッジからマルチクラスタ メッシュへ: 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 リソースを使用します。具体的には、マルチクラスタ ゲートウェイを使用して、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. Make sure 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`
    

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'
    

外部アプリケーション ロードバランサをデプロイして Ingress ゲートウェイを作成する

このセクションでは、GKE Gateway コントローラを介して外部アプリケーション ロードバランサをデプロイし、両方のクラスタに 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 に名前空間ラベルを追加します。

    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. プロジェクトまたはフリートに対する必要な IAM 権限を MCS に付与します。

    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"
    

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

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

  • ルールを含む Google Cloud Armor セキュリティ ポリシーを作成します。
  • 前に作成した ServiceExport YAML ファイルを使用して、ロードバランサが Ingress ゲートウェイ Pod の応答性をチェックできるようにするポリシーを作成します。
  • GKE Gateway API を使用してロードバランサ リソースを作成します。
  • GatewayClass カスタム リソースを使用して、特定のロードバランサ タイプを設定します。
  • フリートでマルチクラスタ ロード バランシングを有効にし、クラスタの 1 つをフリートの構成クラスタとして指定します。
  1. Cloud Shell で、Google 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. Google 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. Ingress ゲートウェイにリクエストを送信するように Gateway リソースに指示する 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 を使用して、リクエストに応答しているクラスタに関する直接的なフィードバックを取得します。次のセクションでは、両方のクラスタに frontend Deployment と backend Deployment の 2 つの個別の Deployment を設定します。

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

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

  1. Cloud Shell で、両方のクラスタに whereami frontend と whereami backend の名前空間を作成し、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:
    n    ame: 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 サービスのフェイルオーバーをテストするには、プライマリ クラスタのイングレス ゲートウェイのレプリカ数を減らします。

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

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

    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. Google 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 | アプリケーション スペシャリスト エンジニア

その他の寄稿者: