Cloud Service Mesh を使用した GKE 限定公開クラスタでの分散サービスの実行

このドキュメントでは、Cloud Service Mesh を使用して、Google Cloud の複数の Google Kubernetes Engine(GKE)クラスタで分散サービスを実行する方法について説明します。また、マルチクラスタ Ingress と Cloud Service Mesh を使用して分散サービスを公開する方法についても説明します。このドキュメントを使用して、非限定公開 GKE クラスタを構成できます。このドキュメントでは、限定公開クラスタを念頭に置いた構成について説明します。

このドキュメントは、Kubernetes の基本的な知識を持つプラットフォーム管理者とサービス オペレータを対象としています。必須ではありませんが、サービス メッシュに関する知識は約に立ちます。Cloud Service Mesh は、オープンソースの Istio テクノロジーをベースとしています。サービス メッシュと Istio の詳細については、istio.io をご覧ください。

分散サービスは、単一の論理サービスとして機能する Kubernetes Service です。分散 Service は、同じ Namespace 内の複数の Kubernetes クラスタで実行されるため、Kubernetes サービスよりも復元力があります。正常なクラスタが目的の負荷を処理できる限り、1 つ以上の GKE クラスタが停止しても、分散サービスは引き続き機能します。

Kubernetes Services が認識するのは、実行するクラスタの Kubernetes API サーバーのみです。Kubernetes クラスタがダウンしている場合(定期メンテナンス中など)、そのクラスタ上で実行されているすべての Kubernetes Services もダウンします。分散サービスを実行すると、他のクラスタがトラフィックを処理している間に、メンテナンスやアップグレードのためにクラスタを止めることができます。分散サービスを作成するには、Cloud Service Mesh のサービス メッシュ機能を使用して、複数のクラスタで実行中のサービスをリンクし、1 つの論理サービスとして機能させます。

GKE 限定公開クラスタを使用すると、Virtual Private Cloud(VPC)ネットワーク上でのみ利用可能なプライベート リソースとしてノードと API サーバーを構成できます。GKE 限定公開クラスタで分散サービスを実行すると、企業に安全で信頼性の高いサービスが提供されます。

アーキテクチャ

このチュートリアルでは、次の図に示すアーキテクチャを使用します。

Cloud Service Mesh を使用した GKE 限定公開クラスタ上の分散サービスのアーキテクチャ

上図では、アーキテクチャに次のクラスタが含まれています。

  • 2 つのクラスタ(gke-central-privgke-west-priv)は、2 つの異なるリージョンで同じ GKE 限定公開クラスタとして機能します。
  • 別のクラスタ(ingress-config)。マルチクラスタ Ingress を構成するコントロール プレーン クラスタとして機能します。

このチュートリアルでは、2 つの GKE 限定公開クラスタ(gke-central-privgke-west-priv)に Bank of Anthos のサンプル アプリケーションをデプロイします。Bank of Anthos は、オンライン バンキング アプリをシミュレートする複数のマイクロサービスと SQL データベースで構成されるマイクロサービス アプリケーションのサンプルです。このアプリケーションは、クライアントがアクセスできるウェブ フロントエンドと、銀行サービスをシミュレートする残高、台帳、アカウント サービスなどの複数のバックエンド サービスから構成されます。

アプリケーションには 2 つの PostgreSQL データベースがあり、Kubernetes に StatefulSet としてインストールされています。1 つのデータベースがトランザクション用、もう 1 つのデータベースがユーザー アカウント用に使われます。この 2 つのデータベースを除くすべてのサービスは分散サービスとして実行されます。つまり、すべてのサービスの Pod が、同じ名前空間内の両方のアプリケーション クラスタ内で実行され、各サービスが 1 つの論理サービスとして扱われるように Cloud Service Mesh が構成されます。

目標

  • 3 つの GKE クラスタを作成します。
  • GKE クラスタのうち 2 つを限定公開クラスタ(gke-central-privgke-west-priv)として構成します。
  • 1 つの GKE クラスタ(ingress-config)を中央構成クラスタとして構成します。このクラスタはマルチクラスタ Ingress の構成クラスタとして機能します。
  • クラスタ間のトラフィックと 2 つの限定公開 GKE のクラスタからの下り(外向き)トラフィックを許可するように、ネットワーキング(NAT ゲートウェイ、Cloud Router、ファイアウォール ルール)を構成します。
  • Cloud Shell から 2 つの限定公開 GKE クラスタへの API サービスによるアクセスを許可するように、承認済みネットワークを構成します。
  • マルチクラスタの Cloud Service Mesh をマルチプライマリ モードで 2 つの限定公開クラスタにデプロイして構成します。マルチプライマリ モードでは、Cloud Service Mesh コントロール プレーンが両方のクラスタにデプロイされます。
  • Bank of Anthos アプリケーションを 2 つの限定公開クラスタにデプロイします。データベースを除くすべてのサービスは、分散サービス(両方の限定公開クラスタで実行されている Pod)としてデプロイされます。
  • Cloud Service Mesh を使用してサービスをモニタリングします。
  • Bank of Anthos の frontend サービスでマルチクラスタ Ingress を構成します。これにより、外部クライアント(ウェブブラウザなど)は、限定公開 GKE クラスタのフリートで実行されている分散サービスにアクセスできます。

費用

このドキュメントでは、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

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

    このチュートリアルでは、Cloud Shell からすべてのコマンドを実行します。

  4. このチュートリアル全体を通して使用する環境変数を定義します。変数は、このチュートリアルで使用するクラスタ名、リージョン、ゾーン、IP アドレス指定、Cloud Service Mesh バージョンを定義します。

    1. YOUR_PROJECT_ID は、プロジェクト ID で置き換えてください。

      export PROJECT_ID=YOUR_PROJECT_ID
      gcloud config set project ${PROJECT_ID}
      
    2. 残りの環境変数を設定します。

      export CLUSTER_1=gke-west-priv
      export CLUSTER_2=gke-central-priv
      export CLUSTER_1_ZONE=us-west2-a
      export CLUSTER_1_REGION=us-west2
      export CLUSTER_1_MASTER_IPV4_CIDR=172.16.0.0/28
      export CLUSTER_2_ZONE=us-central1-a
      export CLUSTER_2_REGION=us-central1
      export CLUSTER_2_MASTER_IPV4_CIDR=172.16.1.0/28
      export CLUSTER_INGRESS=gke-ingress
      export CLUSTER_INGRESS_ZONE=us-west1-a
      export CLUSTER_INGRESS_REGION=us-west1
      export CLUSTER_INGRESS_MASTER_IPV4_CIDR=172.16.2.0/28
      export WORKLOAD_POOL=${PROJECT_ID}.svc.id.goog
      export ASM_VERSION=1.10
      export CLOUDSHELL_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
      

環境を準備する

  1. Cloud Shell で API を有効にします。

    gcloud services enable \
      --project=${PROJECT_ID} \
      container.googleapis.com \
      mesh.googleapis.com \
      gkehub.googleapis.com
    
  2. プロジェクトで Cloud Service Mesh Fleet を有効にします。

    gcloud container fleet mesh enable --project=${PROJECT_ID}
    

限定公開 GKE クラスタのネットワーキングを準備する

このセクションでは、分散サービスの実行に使用する限定公開 GKE クラスタ用にネットワーキングを準備します。

限定公開 GKE クラスタノードには、パブリック IP アドレスが割り当てられません。限定公開 GKE クラスタ内のすべてのノードには、プライベート VPC の IP アドレス(RFC 1918 アドレス空間)が割り当てられます。つまり、VPC ネットワーク外にある外部リソースにアクセスする必要がある Pod には Cloud NAT ゲートウェイが必要です。Cloud NAT ゲートウェイは、内部 IP アドレスを持つ Pod がインターネットと通信できるようにするリージョン NAT ゲートウェイです。このチュートリアルでは、2 つのリージョンのそれぞれで Cloud NAT ゲートウェイを構成します。リージョン内の複数のクラスタは同じ NAT ゲートウェイを使用できます。

  1. Cloud Shell で、2 つの NAT ゲートウェイ用に 2 つの外部 IP アドレスを作成して予約します。

    gcloud compute addresses create ${CLUSTER_1_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_1_REGION}
    
    gcloud compute addresses create ${CLUSTER_2_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_2_REGION}
    
  2. IP アドレスと IP アドレスの名前を変数に保存します。

    export NAT_REGION_1_IP_ADDR=$(gcloud compute addresses describe ${CLUSTER_1_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_1_REGION} \
      --format='value(address)')
    
    export NAT_REGION_1_IP_NAME=$(gcloud compute addresses describe ${CLUSTER_1_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_1_REGION} \
      --format='value(name)')
    
    export NAT_REGION_2_IP_ADDR=$(gcloud compute addresses describe ${CLUSTER_2_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_2_REGION} \
      --format='value(address)')
    
    export NAT_REGION_2_IP_NAME=$(gcloud compute addresses describe ${CLUSTER_2_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_2_REGION} \
      --format='value(name)')
    
  3. 限定公開 GKE クラスタの 2 つのリージョンに Cloud NAT ゲートウェイを作成します。

    gcloud compute routers create rtr-${CLUSTER_1_REGION} \
      --network=default \
      --region ${CLUSTER_1_REGION}
    
    gcloud compute routers nats create nat-gw-${CLUSTER_1_REGION} \
      --router=rtr-${CLUSTER_1_REGION} \
      --region ${CLUSTER_1_REGION} \
      --nat-external-ip-pool=${NAT_REGION_1_IP_NAME} \
      --nat-all-subnet-ip-ranges \
      --enable-logging
    
    gcloud compute routers create rtr-${CLUSTER_2_REGION} \
      --network=default \
      --region ${CLUSTER_2_REGION}
    
    gcloud compute routers nats create nat-gw-${CLUSTER_2_REGION} \
      --router=rtr-${CLUSTER_2_REGION} \
      --region ${CLUSTER_2_REGION} \
      --nat-external-ip-pool=${NAT_REGION_2_IP_NAME} \
      --nat-all-subnet-ip-ranges \
      --enable-logging
    
  4. Pod 間の通信と Pod から API サーバーへの通信を可能にするファイアウォール ルールを作成します。Pod 間の通信により、分散サービスが GKE クラスタ間で相互に通信できるようになります。Pod から API サーバーへの通信により、Cloud Service Mesh のコントロール プレーンは GKE クラスタに対してサービス ディスカバリのクエリを行います。

    gcloud compute firewall-rules create all-pods-and-master-ipv4-cidrs \
      --project ${PROJECT_ID} \
      --network default \
      --allow all \
      --direction INGRESS \
      --source-ranges 10.0.0.0/8,${CLUSTER_1_MASTER_IPV4_CIDR},${CLUSTER_2_MASTER_IPV4_CIDR},${CLUSTER_INGRESS_MASTER_IPV4_CIDR}
    

これでネットワークの準備が整いました。このチュートリアルでは、すべての Pod 範囲を含む 10.0.0.0/8 IP アドレス範囲全体を使用します。本番環境では、条件と要件に基づいて、より厳格なファイアウォール ルールを作成することをおすすめします。

限定公開 GKE クラスタを作成する

このセクションでは、サンプルアプリがデプロイされる 2 つの限定公開 GKE クラスタを作成します。このチュートリアルでは、プライベート GKE クラスタノードにプライベート IP アドレスがあり、API サーバーにパブリック エンドポイントがあります。ただし、API サーバーへのアクセスは、承認済みネットワークを使用して制限されます。

  1. Cloud Shell で、認可済みネットワークを持つ 2 つの限定公開クラスタを作成します。ターミナルからクラスタにアクセスできるように、(Cloud Service Mesh コントロール プレーンの)Pod IP CIDR 範囲と、Cloud Shell からのアクセスを許可するようにクラスタを構成します。

    gcloud container clusters create ${CLUSTER_1} \
      --project ${PROJECT_ID} \
      --zone=${CLUSTER_1_ZONE} \
      --machine-type "e2-standard-4" \
      --num-nodes "3" --min-nodes "3" --max-nodes "5" \
      --enable-ip-alias --enable-autoscaling \
      --workload-pool=${WORKLOAD_POOL} \
      --enable-private-nodes \
      --master-ipv4-cidr=${CLUSTER_1_MASTER_IPV4_CIDR} \
      --enable-master-authorized-networks \
      --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
    
    gcloud container clusters create ${CLUSTER_2} \
      --project ${PROJECT_ID} \
      --zone=${CLUSTER_2_ZONE} \
      --machine-type "e2-standard-4" \
      --num-nodes "3" --min-nodes "3" --max-nodes "5" \
      --enable-ip-alias --enable-autoscaling \
      --workload-pool=${WORKLOAD_POOL} \
      --enable-private-nodes \
      --master-ipv4-cidr=${CLUSTER_2_MASTER_IPV4_CIDR} \
      --enable-master-authorized-networks \
      --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
    

    認可済みネットワークには、Cloud NAT ゲートウェイのパブリック IP アドレスが含まれています。限定公開クラスタの API サーバー エンドポイントは、パブリック エンドポイントのため、限定公開クラスタで実行される Pod は、Cloud NAT ゲートウェイを使用してパブリック API サーバー エンドポイントにアクセスする必要があります。

    Cloud Shell の IP アドレスは認可済みネットワークの一部でもあり、Cloud Shell ターミナルからクラスタにアクセスして管理できます。Cloud Shell の一般公開 IP アドレスは動的なアドレスのため、Cloud Shell を起動するたびに、異なるパブリック IP アドレスが取得される場合があります。新しい IP アドレスを取得すると、その新しい IP アドレスは 2 つのクラスタの認可済みネットワークに含まれていないため、クラスタにアクセスできなくなります。

    クラスタにアクセスできなくなった場合は、クラスタの認可済みネットワークを更新して新しい Cloud Shell IP アドレスを追加します。

    1. 更新された Cloud Shell パブリック IP アドレスを取得します。

      export CLOUDSHELL_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
      
    2. 2 つのクラスタの認可済みネットワークを更新します。

      gcloud container clusters update ${CLUSTER_1} \
        --zone=${CLUSTER_1_ZONE} \
        --enable-master-authorized-networks \
        --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
      
      gcloud container clusters update ${CLUSTER_2} \
        --zone=${CLUSTER_2_ZONE} \
        --enable-master-authorized-networks \
        --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
      
  2. すべてのクラスタが実行されていることを確認します。

    gcloud container clusters list
    

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

    NAME              LOCATION       MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    gke-central-priv  us-central1-a  1.16.15-gke.6000  35.238.99.104  e2-standard-4  1.16.15-gke.6000  3          RUNNING
    gke-west-priv     us-west2-a     1.16.15-gke.6000  34.94.188.180  e2-standard-4  1.16.15-gke.6000  3          RUNNING
    
  3. 両方のクラスタに接続して、kubeconfig ファイルにエントリを生成します。

    touch ~/asm-kubeconfig && export KUBECONFIG=~/asm-kubeconfig
    gcloud container clusters get-credentials ${CLUSTER_1} --zone ${CLUSTER_1_ZONE}
    gcloud container clusters get-credentials ${CLUSTER_2} --zone ${CLUSTER_2_ZONE}
    

    kubeconfig ファイルを使用して、クラスタごとにユーザーとコンテキストを作成し、クラスタに対する認証を行います。kubeconfig ファイルでエントリを生成したら、クラスタ間でコンテキストをすばやく切り替えることができます。

  4. 利便性のため、クラスタ コンテキストの名前を変更します。

    kubectl config rename-context \
    gke_${PROJECT_ID}_${CLUSTER_1_ZONE}_${CLUSTER_1} ${CLUSTER_1}
    
    kubectl config rename-context \
    gke_${PROJECT_ID}_${CLUSTER_2_ZONE}_${CLUSTER_2} ${CLUSTER_2}
    
  5. 両方のクラスタ コンテキストの名前が正しく変更され構成されていることを確認します。

    kubectl config get-contexts --output="name"
    

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

    gke-central-priv
    gke-west-priv
    
  6. フリートにクラスタを登録します。

    gcloud container fleet memberships register ${CLUSTER_1} --gke-cluster=${CLUSTER_1_ZONE}/${CLUSTER_1} --enable-workload-identity
    gcloud container fleet memberships register ${CLUSTER_2} --gke-cluster=${CLUSTER_2_ZONE}/${CLUSTER_2} --enable-workload-identity
    

これで、限定公開 GKE クラスタの作成と名前の変更が完了しました。

Cloud Service Mesh をインストールする

このセクションでは、Cloud Service Mesh を 2 つの GKE クラスタにインストールし、クラスタ間でサービス ディスカバリを行うようにクラスタを構成します。

  1. Cloud Shell で、fleet API を使用して両方のクラスタに Cloud Service Mesh をインストールします。

    gcloud container fleet mesh update --management automatic --memberships ${CLUSTER_1},${CLUSTER_2}
    
  2. クラスタでマネージド Cloud Service Mesh が有効になったら、メッシュがインストールされるように監視します。

    watch -g "gcloud container fleet mesh describe | grep 'code: REVISION_READY'"
    
  3. 両方のクラスタに Cloud Service Mesh Ingress ゲートウェイをインストールします。

    kubectl --context=${CLUSTER_1} create namespace asm-ingress
    kubectl --context=${CLUSTER_1} label namespace asm-ingress istio-injection=enabled --overwrite
    kubectl --context=${CLUSTER_2} create namespace asm-ingress
    kubectl --context=${CLUSTER_2} label namespace asm-ingress istio-injection=enabled --overwrite
    
    cat <<'EOF' > asm-ingress.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      type: LoadBalancer
      selector:
        asm: ingressgateway
      ports:
      - port: 80
        name: http
      - port: 443
        name: https
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        matchLabels:
          asm: ingressgateway
      template:
        metadata:
          annotations:
            # This is required to tell Anthos Service Mesh to inject the gateway with the
            # required configuration.
            inject.istio.io/templates: gateway
          labels:
            asm: ingressgateway
        spec:
          containers:
          - name: istio-proxy
            image: auto # The image will automatically update each time the pod starts.
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway-sds
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway-sds
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway-sds
    subjects:
    - kind: ServiceAccount
      name: default
    EOF
    
    kubectl --context=${CLUSTER_1} apply -f asm-ingress.yaml
    kubectl --context=${CLUSTER_2} apply -f asm-ingress.yaml
    
  4. Cloud Service Mesh Ingress ゲートウェイがデプロイされていることを確認します。

    kubectl --context=${CLUSTER_1} get pod,service -n asm-ingress
    kubectl --context=${CLUSTER_2} get pod,service -n asm-ingress
    

    両方のクラスタの出力は次のようになります。

    NAME                                        READY   STATUS    RESTARTS   AGE
    pod/asm-ingressgateway-5894744dbd-zxlgc   1/1     Running   0          84s
    
    NAME                           TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)                      AGE
    service/asm-ingressgateway   LoadBalancer   10.16.2.131   34.102.100.138   80:30432/TCP,443:30537/TCP   92s
    

    両方のクラスタに Cloud Service Mesh コントロール プレーンと Ingress ゲートウェイがインストールされると、Fleet API でのクラスタ間のサービス ディスカバリが有効になります。クラスタ間のサービス ディスカバリを使用すると、2 つのクラスタで異なるクラスタからサービス エンドポイントを検出できます。分散サービスは、同じ Namespace 内の複数のクラスタで実行されます。

    Cloud Service Mesh の両方のコントロール プレーンが分散サービスのすべてのエンドポイントを検出するには、Cloud Service Mesh が分散サービスを実行しているすべてのクラスタにアクセスできる必要があります。この例では 2 つのクラスタを使用しているため、両方のクラスタで相手のクラスタに対してサービス エンドポイントのクエリを実行できる必要があります。Fleet API でマネージド Cloud Service Mesh を有効にすると、エンドポイントの検出が自動的に構成されます。

これで、クラスタと Cloud Service Mesh が構成されました。

Bank of Anthos アプリケーションをデプロイする

  1. Cloud Shell で、Bank of Anthos の GitHub リポジトリのクローンを作成します。

    git clone https://github.com/GoogleCloudPlatform/bank-of-anthos.git ${HOME}/bank-of-anthos
    
  2. 両方のクラスタで bank-of-anthos Namespace を作成してラベルを付けます。このラベルを使用すると、ラベルが付けられた Namespace 内のすべての Pod にサイドカー Envoy プロキシを自動的に挿入できます。

    # cluster_1
    kubectl create --context=${CLUSTER_1} namespace bank-of-anthos
    kubectl label --context=${CLUSTER_1} namespace bank-of-anthos istio-injection=enabled
    
    # cluster_2
    kubectl create --context=${CLUSTER_2} namespace bank-of-anthos
    kubectl label --context=${CLUSTER_2} namespace bank-of-anthos istio-injection=enabled
    
  3. Bank of Anthos アプリケーションを bank-of-anthos Namespace の両方のクラスタにデプロイします。

    # The following secret is used for user account creation and authentication
    kubectl --context=$CLUSTER_1 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/extras/jwt/jwt-secret.yaml
    kubectl --context=$CLUSTER_2 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/extras/jwt/jwt-secret.yaml
    
    # Deploy all manifests to both clusters
    kubectl --context=$CLUSTER_1 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/kubernetes-manifests
    kubectl --context=$CLUSTER_2 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/kubernetes-manifests
    

    サービス ディスカバリを行うには、Kubernetes サービスが両方のクラスタに存在する必要があります。いずれかのクラスタのサービスがリクエストを試みると、まずホスト名の DNS ルックアップが行われ、IP アドレスが取得されます。GKE では、クラスタで実行されている kube-dns サーバーがこのルックアップを処理するため、構成済みの Service 定義が必要になります。

  4. 一方のクラスタから StatefulSets を削除し、2 つの PostgreSQL データベースがもう一方のクラスタにのみ存在するようにします。

    # Delete the two DB statefulSets from Cluster2
    kubectl --context=$CLUSTER_2 -n bank-of-anthos delete statefulset accounts-db
    kubectl --context=$CLUSTER_2 -n bank-of-anthos delete statefulset ledger-db
    
  5. すべての Pod が両方のクラスタで実行されるようにします。

    1. cluster_1 から Pod を取得します。

      kubectl --context=${CLUSTER_1} -n bank-of-anthos get pod
      

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

      NAME                                  READY   STATUS    RESTARTS   AGE
      accounts-db-0                         2/2     Running   0          9m54s
      balancereader-c5d664b4c-xmkrr         2/2     Running   0          9m54s
      contacts-7fd8c5fb6-wg9xn              2/2     Running   1          9m53s
      frontend-7b7fb9b665-m7cw7             2/2     Running   1          9m53s
      ledger-db-0                           2/2     Running   0          9m53s
      ledgerwriter-7b5b6db66f-xhbp4         2/2     Running   0          9m53s
      loadgenerator-7fb54d57f8-g5lz5        2/2     Running   0          9m52s
      transactionhistory-7fdb998c5f-vqh5w   2/2     Running   1          9m52s
      userservice-76996974f5-4wlpf          2/2     Running   1          9m52s
      
    2. cluster_2 から Pod を取得します。

      kubectl --context=${CLUSTER_2} -n bank-of-anthos get pod
      

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

      NAME                                  READY   STATUS    RESTARTS   AGE
      balancereader-c5d664b4c-bn2pl         2/2     Running   0          9m54s
      contacts-7fd8c5fb6-kv8cp              2/2     Running   0          9m53s
      frontend-7b7fb9b665-bdpp4             2/2     Running   0          9m53s
      ledgerwriter-7b5b6db66f-297c2         2/2     Running   0          9m52s
      loadgenerator-7fb54d57f8-tj44v        2/2     Running   0          9m52s
      transactionhistory-7fdb998c5f-xvmtn   2/2     Running   0          9m52s
      userservice-76996974f5-mg7t6          2/2     Running   0          9m51s
      
  6. Cloud Service Mesh の構成を両方のクラスタにデプロイします。これにより、asm-ingress Namespace に Gateway が作成され、frontend Service の bank-of-anthos Namespace に VirtualService が作成され、上り(内向き)トラフィックを frontend サービスに転送できるようになります。

    Gateways は通常、プラットフォーム管理者またはネットワーク管理者チームが所有します。したがって、Gateway リソースは、プラットフォーム管理者が所有する Ingress Gateway Namespace に作成され、独自の VirtualService エントリを介して他の Namespace で使用できます。これが「共有ゲートウェイ」モデルです。

    cat <<'EOF' > asm-vs-gateway.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        asm: ingressgateway
      servers:
        - port:
            number: 80
            name: http
            protocol: HTTP
          hosts:
            - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: frontend
      namespace: bank-of-anthos
    spec:
      hosts:
      - "*"
      gateways:
      - asm-ingress/asm-ingressgateway
      http:
      - route:
        - destination:
            host: frontend
            port:
              number: 80
    EOF
    
    kubectl --context=$CLUSTER_1 apply -f asm-vs-gateway.yaml
    
    kubectl --context=$CLUSTER_2 apply -f asm-vs-gateway.yaml
    

これで、Bank of Anthos アプリケーションが 2 つの限定公開 GKE クラスタにデプロイされました。データベースを除くすべてのサービスは、分散サービスとして実行されます。

分散サービスを検査する

このセクションでは、istioctl ツールを使用して、いずれかのプロキシの proxy-config を検査します。これにより、サイドカー プロキシがサービスごとに 2 つの Pod を検出し、各クラスタで 1 つの Pod が実行されていることがわかります。

  1. Cloud Shell で、cluster_1frontend Pod のプロキシ構成エンドポイント リストを調べます。

    export FRONTEND1=$(kubectl get pod -n bank-of-anthos -l app=frontend \
      --context=${CLUSTER_1} -o jsonpath='{.items[0].metadata.name}')
    istioctl proxy-config endpoints \
    --context $CLUSTER_1 -n bank-of-anthos $FRONTEND1 | grep bank-of-anthos
    

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

    10.12.0.6:5432                   HEALTHY     OK                outbound|5432||accounts-db.bank-of-anthos.svc.cluster.local
    10.12.0.7:8080                   HEALTHY     OK                outbound|8080||balancereader.bank-of-anthos.svc.cluster.local
    10.12.0.8:8080                   HEALTHY     OK                outbound|8080||transactionhistory.bank-of-anthos.svc.cluster.local
    10.12.0.9:8080                   HEALTHY     OK                outbound|8080||userservice.bank-of-anthos.svc.cluster.local
    10.12.1.10:8080                  HEALTHY     OK                outbound|8080||ledgerwriter.bank-of-anthos.svc.cluster.local
    10.12.1.9:8080                   HEALTHY     OK                outbound|8080||contacts.bank-of-anthos.svc.cluster.local
    10.12.2.11:5432                  HEALTHY     OK                outbound|5432||ledger-db.bank-of-anthos.svc.cluster.local
    10.12.2.13:8080                  HEALTHY     OK                outbound|80||frontend.bank-of-anthos.svc.cluster.local
    10.76.1.10:8080                  HEALTHY     OK                outbound|8080||transactionhistory.bank-of-anthos.svc.cluster.local
    10.76.1.8:8080                   HEALTHY     OK                outbound|8080||balancereader.bank-of-anthos.svc.cluster.local
    10.76.1.9:8080                   HEALTHY     OK                outbound|80||frontend.bank-of-anthos.svc.cluster.local
    10.76.2.10:8080                  HEALTHY     OK                outbound|8080||userservice.bank-of-anthos.svc.cluster.local
    10.76.2.8:8080                   HEALTHY     OK                outbound|8080||contacts.bank-of-anthos.svc.cluster.local
    10.76.2.9:8080                   HEALTHY     OK                outbound|8080||ledgerwriter.bank-of-anthos.svc.cluster.local
    

    上記の出力では、各分散サービスに 2 つのエンドポイント IP アドレスがあります。これらは Pod の IP アドレスで、クラスタごとに 1 つあります。

Bank of Anthos にアクセスする

Bank of Anthos アプリケーションにアクセスするには、いずれかのクラスタの asm-ingressgateway Service のパブリック IP アドレスを使用します。

  1. 両方のクラスタから asm-ingressgateway IP アドレスを取得します。

    kubectl --context ${CLUSTER_1} \
    --namespace asm-ingress get svc asm-ingressgateway -o jsonpath='{.status.loadBalancer}' | grep "ingress"
    
    kubectl --context ${CLUSTER_2} \
    --namespace asm-ingress get svc asm-ingressgateway -o jsonpath='{.status.loadBalancer}' | grep "ingress"
    
    

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

    {"ingress":[{"ip":"35.236.4.18"}]}
    {"ingress":[{"ip":"34.68.94.81"}]}
    

    IP アドレスの 1 つをコピーして、次のステップで使用します。

  2. ウェブブラウザで新しいタブを開き、前の出力の IP アドレスのいずれかに移動します。Bank of Anthos のフロントエンドが表示され、ログイン、口座への入金、他の口座への送金を行うことができます。このアプリケーションは完全に機能します。

分散サービスを可視化する

分散サービスは Cloud Service Mesh で可視化できます。

  1. サービスを表示するには、Google Cloud コンソールの [サービス メッシュ] ページに移動します。

    [サービス メッシュ] に移動

    サービスは、テーブルビューまたはトポロジビューで確認できます。デフォルトのビューは表形式で、実行中のすべての分散サービスが表形式で表示されます。ビューを変更するには、表示するビューをクリックします。

  2. [テーブル] ビューで frontend distributed service をクリックします。個々のサービスをクリックすると、サービスの詳細と接続されたサービスが表示されます。

    サービスの詳細ビューで [タイムラインを表示] をクリックすると、SLO を作成し、サービスの履歴タイムラインを表示できます。

  3. ゴールデン シグナルを表示するには、サイドパネルで [指標] をクリックします。

  4. Requests per seconds のグラフで、[データの内訳基準] をクリックして [ロケーション] を選択します。

    結果では、2 つのリージョンに存在する両方のクラスタからの 1 秒あたりのリクエスト数が表示されます。分散サービスは正常であり、両方のエンドポイントがトラフィックを処理しています。

  5. サービス メッシュのトポロジを表示するには、サイドパネルで [Anthos Service Mesh] をクリックし、[Topology View] をクリックします。

  6. 補足データを表示するには、マウスポインタを frontend サービスの上に置きます。これにより、フロントエンドから他のサービスに対する 1 秒あたりの送受信リクエスト数などの情報が表示されます。

  7. さらに詳細を表示するには、frontend サービスで [展開] をクリックします。[Service] と [Workload] が表示されます。つづいて、[Workload] を 2 つの [Deployment] に展開し、[Deployment] を [ReplicaSet] に展開して、[ReplicaSet] を [Pod] に展開できます。すべての要素を展開すると、分散 frontend サービスを確認できます。これは、基本的には 1 つの Service と 2 つの Pod です。

複数クラスタ Ingress を構成する

このセクションでは、両方のクラスタで実行されている Bank of GKE Enterprise の frontend サービスにトラフィックを送信するマルチクラスタ Ingress を作成します。Cloud Load Balancing を使用して、両方のクラスタで asm-ingressgateway Service をバックエンドとして使用するロードバランサを作成します。ingress-config クラスタは、マルチクラスタ Ingress 構成のオーケストレーションに使用されます。

ロードバランサを作成するには、MultiClusterIngress と 1 つ以上の MultiClusterServices を使用します。MultiClusterIngress オブジェクトと MultiClusterService オブジェクトには、単一クラスタ コンテキストで使用される既存の Kubernetes Ingress および Service リソースとのマルチクラスタの類似性があります。

  1. 必要な GKE Enterprise、GKE フリート、マルチクラスタ Ingress API を有効にします。

    gcloud services enable \
      anthos.googleapis.com \
      multiclusterservicediscovery.googleapis.com \
      multiclusteringress.googleapis.com
    
  2. ingress-config クラスタを作成します。任意のクラスタを使用できますが、ここでは個別のクラスタを作成することをおすすめします。

    gcloud container clusters create ${CLUSTER_INGRESS} \
      --zone ${CLUSTER_INGRESS_ZONE} \
      --num-nodes=1 \
      --enable-ip-alias \
      --workload-pool=${WORKLOAD_POOL}
    
  3. クラスタの認証情報を取得し、利便性のためにコンテキストの名前を変更します。

    gcloud container clusters get-credentials ${CLUSTER_INGRESS} \
      --zone ${CLUSTER_INGRESS_ZONE} --project ${PROJECT_ID}
    
    kubectl config rename-context \
      gke_${PROJECT_ID}_${CLUSTER_INGRESS_ZONE}_${CLUSTER_INGRESS} ${CLUSTER_INGRESS}
    
  4. マルチクラスタ Ingress を使用するには、参加するすべてのクラスタ(構成クラスタを含む)を GKE Enterprise フリートに登録します。

  5. 構成クラスタを登録します。

    gcloud container fleet memberships register ${CLUSTER_INGRESS} \
      --project=${PROJECT_ID} \
      --gke-cluster=${CLUSTER_INGRESS_ZONE}/${CLUSTER_INGRESS} \
      --enable-workload-identity
    
  6. すべてのクラスタが GKE Enterprise フリートに登録されていることを確認します。

    gcloud container fleet memberships list
    

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

    NAME            EXTERNAL_ID
    gke-west        7fe5b7ce-50d0-4e64-a9af-55d37b3dd3fa
    gke-central     6f1f6bb2-a3f6-4e9c-be52-6907d9d258cd
    gke-ingress     3574ee0f-b7e6-11ea-9787-42010a8a019c
    
  7. ingress-config クラスタで、マルチクラスタ Ingress 機能を有効にします。これにより、クラスタに MulticlusterServiceMulticlusterIngress CustomResourceDefinitions(CRD)が作成されます。

    gcloud container fleet ingress enable \
      --config-membership=projects/${PROJECT_ID}/locations/global/memberships/${CLUSTER_INGRESS}
    
  8. ingress-config クラスタで、マルチクラスタ Ingress が有効になっていることを確認します。

    gcloud container fleet ingress describe
    

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

    membershipStates:
      projects/986443280307/locations/global/memberships/gke-central-priv:
        state:
          code: OK
          updateTime: '2022-09-29T13:57:02.972748202Z'
      projects/986443280307/locations/global/memberships/gke-ingress:
        state:
          code: OK
          updateTime: '2022-09-29T13:57:02.972744692Z'
      projects/986443280307/locations/global/memberships/gke-west-priv:
        state:
          code: OK
          updateTime: '2022-09-29T13:57:02.972746497Z'
    
  9. 2 つの CRD が ingress-config クラスタにデプロイされていることを確認します。

    kubectl --context=${CLUSTER_INGRESS} get crd | grep multicluster
    

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

    multiclusteringresses.networking.gke.io     2020-10-29T17:32:50Z
    multiclusterservices.networking.gke.io      2020-10-29T17:32:50Z
    
  10. ingress-config クラスタに asm-ingress 名前空間を作成します。

    kubectl --context ${CLUSTER_INGRESS} create namespace asm-ingress
    
  11. MultiClusterIngress リソースを作成します。

    cat <<EOF > ${HOME}/mci.yaml
    apiVersion: networking.gke.io/v1beta1
    kind: MultiClusterIngress
    metadata:
      name: asm-ingressgateway-multicluster-ingress
    spec:
      template:
        spec:
          backend:
           serviceName: asm-ingressgateway-multicluster-svc
           servicePort: 80
    EOF
    
  12. MultiClusterService リソースを作成します。

    cat <<'EOF' > $HOME/mcs.yaml
    apiVersion: networking.gke.io/v1beta1
    kind: MultiClusterService
    metadata:
      name: asm-ingressgateway-multicluster-svc
      annotations:
        beta.cloud.google.com/backend-config: '{"ports": {"80":"gke-ingress-config"}}'
    spec:
      template:
        spec:
          selector:
            asm: ingressgateway
          ports:
          - name: frontend
            protocol: TCP
            port: 80 # servicePort defined in Multi Cluster Ingress
      clusters:
      - link: "us-west2-a/gke-west-priv"
      - link: "us-central1-a/gke-central-priv"
    EOF
    
  13. ヘルスチェック用の BackendConfig リソースを作成します。

    cat <<EOF > $HOME/backendconfig.yaml
    apiVersion: cloud.google.com/v1beta1
    kind: BackendConfig
    metadata:
      name: gke-ingress-config
    spec:
      healthCheck:
        type: HTTP
        port: 15021
        requestPath: /healthz/ready
    EOF
    
  14. BackendConfigMultiClusterServiceMultiClusterIngress の各マニフェストを適用します。

    kubectl --context ${CLUSTER_INGRESS} -n asm-ingress apply -f ${HOME}/backendconfig.yaml
    kubectl --context ${CLUSTER_INGRESS} -n asm-ingress apply -f ${HOME}/mci.yaml
    kubectl --context ${CLUSTER_INGRESS} -n asm-ingress apply -f ${HOME}/mcs.yaml
    
  15. Ingress クラスタにデプロイした MultiClusterService によって、クラスタ 1 とクラスタ 2 にヘッドレス Service が作成されます。ヘッドレス Services が作成されていることを確認します。

    kubectl --context=${CLUSTER_1} -n asm-ingress \
      get services | grep multicluster-svc
    kubectl --context=${CLUSTER_2} -n asm-ingress \
      get services | grep multicluster-svc
    

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

    mci-frontend-multi-cluster-service-svc-f7rcyqry22iq8nmw   ClusterIP      None          <none>          80/TCP         77s
    mci-frontend-multi-cluster-service-svc-f7rcyqry22iq8nmw   ClusterIP      None          <none>          80/TCP         78s
    
  16. 次のコマンドを実行し、Cloud Load Balancing IP アドレスを取得するまで待ちます。

    watch kubectl --context ${CLUSTER_INGRESS} -n asm-ingress get multiclusteringress \
      -o jsonpath="{.items[].status.VIP}"
    

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

    35.35.23.11
    

    watch コマンドを終了するには、Ctrl+C キーを押します。

  17. ウェブブラウザで Cloud Load Balancing の IP アドレスに移動し、Bank of Anthos のフロントエンドに移動します。

    kubectl --context ${CLUSTER_INGRESS} \
      -n asm-ingress get multiclusteringress \
      -o jsonpath="{.items[].status.VIP}"
    

    404 エラー(または 502 エラー)が表示された場合は、数分待ってから、ウェブブラウザでページを更新します。

クリーンアップ

アカウントに課金されないようにするには、プロジェクトまたはクラスタを削除します。

プロジェクトの削除

課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

  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.

クラスタを削除する

  1. Cloud Shell で、blue クラスタと green クラスタの登録を解除して削除します。

    gcloud container fleet memberships unregister ${CLUSTER_1} \
      --project=${PROJECT} \
      --gke-uri=${CLUSTER_1_URI}
    gcloud container clusters delete ${CLUSTER_1} \
      --zone ${CLUSTER_1_ZONE} \
      --quiet
    
    gcloud container fleet memberships unregister ${CLUSTER_2} \
      --project=${PROJECT} \
      --gke-uri=${CLUSTER_2_URI}
    gcloud container clusters delete ${CLUSTER_2} \
      --zone ${CLUSTER_2_ZONE} \
      --quiet
    
  2. ingress-config クラスタから MuticlusterIngress リソースを削除します。

    kubectl --context ${CLUSTER_INGRESS} -n istio-system delete -f $HOME/mci.yaml
    

    これにより、プロジェクトから Cloud Load Balancing リソースが削除されます。

  3. ingress-config クラスタの登録を解除して削除します。

    gcloud container fleet memberships unregister ${CLUSTER_INGRESS} \
      --project=${PROJECT} \
      --gke-uri=${CLUSTER_INGRESS_URI}
    gcloud container clusters delete ${CLUSTER_INGRESS} \
      --zone ${CLUSTER_INGRESS_ZONE} \
      --quiet
    
  4. すべてのクラスタが削除されていることを確認します。

    gcloud container clusters list
    

    次のような出力が表示されます。

    <null>
  5. kubeconfig ファイルをリセットします。

    unset KUBECONFIG
    

次のステップ