使用 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,可做為單一邏輯服務。分散式服務比 Kubernetes 服務更具彈性,因為這類服務會在相同命名空間中的多個 Kubernetes 叢集上執行。即使一或多個 GKE 叢集停止運作,只要健康狀態良好的叢集能夠處理所需負載,分散式服務仍可正常運作。

Kubernetes Service 只會向叢集的 Kubernetes API 伺服器公開,如果 Kubernetes 叢集停止運作 (例如在排定的維護期間),在該叢集上執行的所有 Kubernetes 服務也會停止運作。執行分散式服務可簡化叢集生命週期管理作業,因為您可以在其他叢集處理流量時,關閉叢集進行維護或升級。如要建立分散式服務,請使用 Cloud Service Mesh 提供的服務網格功能,將在多個叢集上執行的服務連結在一起,做為單一邏輯服務。

GKE 私人叢集可讓您將節點和 API 伺服器設為私人資源,僅供虛擬私有雲 (VPC) 網路使用。在 GKE 私有叢集中執行分散式服務,可為企業提供安全可靠的服務。

架構

本教學課程使用下圖所示的架構:

使用 Cloud Service Mesh 在 GKE 私人叢集上建構分散式服務的架構

在上圖中,架構包含下列叢集:

  • 兩個叢集 (gke-central-priv 和 gke-west-priv) 在兩個不同區域中,做為相同的 GKE 私人叢集。
  • 另一個叢集 (ingress-config) 則做為控制層叢集,負責設定多叢集 Ingress。

在本教學課程中,您會在兩個 GKE 私人叢集 (gke-central-priv 和 gke-west-priv) 上部署 Bank of Anthos 範例應用程式。Bank of Anthos 是範例微服務應用程式,由多個微服務和 SQL 資料庫組成,可模擬網路銀行應用程式。這個應用程式包含客戶可存取的網頁前端,以及多項後端服務,例如模擬銀行的餘額、帳本和帳戶服務。

應用程式包含兩個 PostgreSQL 資料庫,以 StatefulSet 形式安裝在 Kubernetes 中。一個資料庫用於交易,另一個資料庫用於使用者帳戶。除了兩個資料庫以外,所有服務都會以分散式服務的形式執行。也就是說,所有服務的 Pod 都會在兩個應用程式叢集 (位於相同命名空間) 中執行,且 Cloud Service Mesh 會經過設定,讓每個服務顯示為單一邏輯服務。

目標

  • 建立三個 GKE 叢集。
  • 將兩個 GKE 叢集設定為私人叢集 (gke-central-priv 和 gke-west-priv)。
  • 將一個 GKE 叢集 (ingress-config) 設為中央設定叢集。這個叢集會做為多叢集 Ingress 的設定叢集。
  • 設定網路 (NAT 閘道、Cloud Router 和防火牆規則),允許兩個私人 GKE 叢集之間的叢集間和輸出流量。
  • 設定授權網路,允許從 Cloud Shell 存取兩個私人 GKE 叢集的 API 服務。
  • 以多主節點模式,將多叢集 Cloud Service Mesh 部署至兩個私人叢集,並完成設定。多主要模式會在兩個叢集中部署 Cloud Service Mesh 控制層。
  • 在兩個私人叢集上部署 Bank of Anthos 應用程式。除了資料庫以外,所有服務都會部署為分散式服務 (在兩個私人叢集上執行的 Pod)。
  • 使用 Cloud Service Mesh 監控服務。
  • 在 Bank of Anthos frontend 服務上設定多叢集 Ingress。這樣一來,外部用戶端 (例如網頁瀏覽器) 就能存取在私人 GKE 叢集機群上執行的分散式服務。

費用

在本文件中,您會使用下列 Google Cloud計費元件:

您可以使用 Pricing Calculator,根據預測用量估算費用。

初次使用 Google Cloud 的使用者可能符合免費試用期資格。

事前準備

  1. 在 Google Cloud 控制台的專案選擇器頁面中,選取或建立 Google Cloud 專案。

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需具備特定 IAM 角色,只要您在專案中獲派角色,即可選取該專案。
    • 建立專案:如要建立專案,您必須具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色。

    前往專案選取器

  2. 確認 Google Cloud 專案已啟用計費功能。

  3. 在 Google Cloud 控制台啟用 Cloud Shell。

    啟用 Cloud Shell

    Google Cloud 控制台底部會開啟 Cloud Shell 工作階段,並顯示指令列提示。Cloud Shell 是已安裝 Google Cloud CLI 的殼層環境,並已設定適用於您目前專案的值。工作階段可能要幾秒鐘的時間才能初始化。

    您將透過 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 機群:

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

為私人 GKE 叢集準備網路

在本節中,您將準備私人 GKE 叢集的網路,用於執行分散式服務。

私人 GKE 叢集節點不會獲派公開 IP 位址。私人 GKE 叢集中的所有節點都會獲派私人 VPC IP 位址 (位於 RFC 1918 位址空間)。這表示需要存取外部資源 (虛擬私有雲網路外部) 的 Pod 必須使用 Cloud NAT 閘道。Cloud NAT 閘道是區域性 NAT 閘道,可讓具有內部 IP 位址的 Pod 與網際網路通訊。在本教學課程中,您會在兩個區域分別設定 Cloud NAT 閘道。區域內的多個叢集 可以使用同一個 NAT 閘道

  1. 在 Cloud Shell 中,為兩個 NAT 閘道建立並保留兩個外部 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 叢集的兩個區域中建立 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 通訊和 Pod 對 API 伺服器通訊。Pod 對 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}
    

網路已準備就緒。在本教學課程中,您會使用整個 10.0.0.0/8 IP 位址範圍,其中包含所有 Pod 範圍。建議您根據條件和需求,在實際工作環境中建立更嚴格的防火牆規則。

建立私人 GKE 叢集

在這個部分,您會建立兩個私人 GKE 叢集,用於部署範例應用程式。在本教學課程中,私人 GKE 叢集節點具有私人 IP 位址,而 API 伺服器具有公開端點。不過,API 伺服器的存取權會透過授權網路受到限制。

  1. 在 Cloud Shell 中,建立兩個具有授權網路的私人叢集。設定叢集,允許從 Pod IP CIDR 範圍 (適用於 Cloud Service Mesh 控制層) 和 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 位址不屬於這兩個叢集的授權網路。

    如果無法存取叢集,請更新叢集的授權網路,加入新的 Cloud Shell IP 位址:

    1. 取得更新後的 Cloud Shell 公開 IP 位址:

      export CLOUDSHELL_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
      
    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

在本節中,您將在兩個 GKE 叢集上安裝 Cloud Service Mesh,並設定叢集來進行跨叢集服務探索。

  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 輸入閘道:

    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 啟用跨叢集服務探索。跨叢集服務探索功能可讓兩個叢集從遠端叢集探索服務端點。分散式服務會在相同命名空間的多個叢集上執行。

    如要讓兩個 Cloud Service Mesh 控制層探索分散式服務的所有端點,Cloud Service Mesh 必須有權存取執行分散式服務的所有叢集。這個範例使用兩個叢集,因此兩個叢集都必須能向遠端叢集查詢服務端點。透過 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 命名空間。這個標籤可讓系統在標示命名空間內的每個 Pod 中,自動插入 Sidecar Envoy Proxy。

    # 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 命名空間中的兩個叢集。

    # 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,讓兩個 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 命名空間中建立 Gateway,並在 frontend 服務的 bank-of-anthos 命名空間中建立 VirtualService,讓您將輸入流量傳輸至 frontend 服務。

    Gateways 通常由平台管理員或網路管理員團隊擁有。因此,Gateway 資源會在平台管理員擁有的 Ingress Gateway 命名空間中建立,並可透過自己的 VirtualService 項目在其他命名空間中使用。這是「共用閘道」模式。

    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
    

您現在已在兩個私人 GKE 叢集上部署 Bank of Anthos 應用程式。除了資料庫以外,所有服務都以分散式服務的形式運作。

檢查分散式服務

在本節中,您將使用 istioctl 工具檢查任何 Proxy 的 proxy-config。這樣一來,您就會看到 Sidecar Proxy 為每項服務顯示兩個 Pod,每個叢集各有一個 Pod 運作。

  1. 在 Cloud Shell 中,檢查 cluster_1 中 frontend Pod 的 proxy-config 端點清單:

    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
    

    在上述輸出內容中,每個分散式服務都有兩個端點 IP 位址。這些是 Pod IP 位址,每個叢集各一個。

存取 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 位址,以便在下一步使用。

  2. 在網路瀏覽器中開啟新分頁,然後前往上述輸出內容中的任一 IP 位址。系統應會顯示 Bank of Anthos 前端,方便您登入、將資金存入帳戶,以及將資金轉移至其他帳戶。應用程式應功能完備。

以視覺化方式呈現分散式服務

您可以在 Cloud Service Mesh 中以視覺化方式呈現分散式服務。

  1. 如要查看服務,請前往 Google Cloud 控制台的「Anthos」>「服務網格」頁面。

    前往服務網格

    您可以透過「表格」或「拓撲」檢視畫面查看服務。預設檢視畫面為表格檢視畫面,會以表格格式顯示所有執行的分散式服務。如要變更檢視畫面,請按一下要顯示的檢視畫面。

  2. 在「表格」檢視畫面中,按一下 frontend distributed service。 點選個別服務後,您會看到該服務和已連結服務的詳細檢視畫面。

    在服務詳細資料檢視畫面中,您可以建立服務等級目標,並點選「Show Timeline」(顯示時間軸) 查看服務的歷來時間軸。

  3. 如要查看黃金信號,請按一下側邊面板中的「Metrics」(指標)。

  4. 在「Requests per seconds」(每秒要求數) 圖表中,按一下「Breakdown By」(細目依據),然後選取「Location」(位置)。

    結果會顯示兩個區域中兩個叢集的每秒要求數。分散式服務健康狀態良好,且兩個端點都在處理流量。

  5. 如要查看服務網格的拓撲,請在側邊面板中點選「Anthos 服務網格」,然後點選「Topology View」。

  6. 如要查看其他資料,請將滑鼠游標懸停在 frontend 服務上。這會顯示每秒從前端傳送至其他服務的要求數,以及從其他服務傳送至前端的要求數等資訊。

  7. 如要查看更多詳細資料,請按一下「frontend」服務上的「展開」。系統會顯示服務和工作負載。您可以進一步將工作負載展開為兩個 Deployment、將 Deployment 展開為 ReplicaSet,以及將 ReplicaSet 展開為 Pod。展開所有元素後,您會看到分散式 frontend 服務,基本上是由一個 Service 和兩個 Pod 組成。

設定多叢集 Ingress

在本節中,您將建立多叢集 Ingress,將流量傳送至兩個叢集中執行的 Bank of GKE Enterprise frontend 服務。您可以使用 Cloud Load Balancing 建立負載平衡器,將兩個叢集中的 asm-ingressgateway Service 做為後端。ingress-config 叢集用於自動化調度管理多叢集 Ingress 設定。

如要建立負載平衡器,請使用 MultiClusterIngress 和一或多個 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 功能。 這會在叢集上建立 MulticlusterService 和 MulticlusterIngress 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. 確認兩個 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. 套用 BackendConfig、MultiClusterService 和 MultiClusterIngress 資訊清單:

    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. 前往 Google Cloud 控制台的「Manage resources」(管理資源) 頁面。

    前往「Manage resources」(管理資源)

  2. 在專案清單中選取要刪除的專案,然後點選「Delete」(刪除)。
  3. 在對話方塊中輸入專案 ID,然後按一下 [Shut down] (關閉) 以刪除專案。

刪除叢集

  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
    

後續步驟