從邊緣到多叢集網格:透過 GKE 閘道和 Cloud Service Mesh 部署全球分散式應用程式

Last reviewed 2024-06-30 UTC

本文說明如何完成下列工作:

本部署指南適用於平台管理員。也適合執行 Cloud Service Mesh 的進階實務工作者。這些操作說明也適用於 Istio on GKE。

架構

下圖顯示服務網格的預設輸入拓撲,也就是在單一叢集上公開輸入閘道 Proxy 的外部 TCP/UDP 負載平衡器:

外部負載平衡器會透過 Ingress 閘道 Proxy,將外部用戶端導向網格。

本部署指南使用 Google Kubernetes Engine (GKE) Gateway 資源。具體來說,這項功能會使用多叢集閘道,在分布於兩個區域的多個 Autopilot 叢集前方,設定多區域負載平衡。

來自用戶端、負載平衡器和網格的 TLS 加密。

上圖顯示資料在雲端進入和網格進入情境中的流動方式。詳情請參閱相關參考架構文件中的架構圖說明。

目標

  • 在 Google Cloud 上將一對 GKE Autopilot 叢集部署至同一個車隊
  • 將以 Istio 為基礎的 Cloud Service Mesh 部署至相同機群。
  • 使用 GKE Gateway 設定負載平衡器,終止公開 HTTPS 流量。
  • 將公開 HTTPS 流量直接導向 Cloud Service Mesh 代管的應用程式,這些應用程式部署在多個叢集和區域。
  • whereami 範例應用程式部署至兩個 Autopilot 叢集。

成本最佳化

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

如要根據預測用量估算費用,請使用 Pricing Calculator

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

完成本文所述工作後,您可以刪除已建立的資源,避免繼續計費。詳情請參閱清除所用資源一節。

事前準備

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

    Go to project selector

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

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

    Activate Cloud Shell

    您將透過 Cloud Shell 執行這項部署作業的所有終端機指令。

  4. 設定預設 Google Cloud 專案:

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

    PROJECT_ID 替換為您要用於這項部署作業的專案 ID。

  5. 建立工作目錄:

    mkdir -p ${HOME}/edge-to-mesh-multi-region
    cd ${HOME}/edge-to-mesh-multi-region
    export WORKDIR=`pwd`
    
  6. 建立 GKE 叢集

    在本節中,您將建立 GKE 叢集,以託管應用程式和支援基礎架構,這些基礎架構會在稍後的部署指南中建立。

    1. 在 Cloud Shell 中,建立新的 kubeconfig 檔案。這個步驟可確保您不會與現有的 (預設) kubeconfig 檔案發生衝突。

      touch edge2mesh_mr_kubeconfig
      export KUBECONFIG=${WORKDIR}/edge2mesh_mr_kubeconfig
      
    2. 定義建立 GKE 叢集和其中資源時使用的環境變數。修改預設區域選項,以符合您的需求。

      export CLUSTER_1_NAME=edge-to-mesh-01
      export CLUSTER_2_NAME=edge-to-mesh-02
      export CLUSTER_1_REGION=us-central1
      export CLUSTER_2_REGION=us-east4
      export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
      
    3. 啟用本指南中使用的 Google Cloud API:

      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 中建立並註冊第二個 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 閘道。gatewaygatewayClass 資源會自動佈建負載平衡器,並執行後端健康狀態檢查。如要在負載平衡器上提供 TLS 終止功能,請建立 Certificate Manager 資源,並將這些資源附加至負載平衡器。此外,您可以使用 Endpoints 自動為應用程式佈建公開 DNS 名稱。

    在兩個叢集上安裝 Ingress 閘道

    為確保安全,建議您在與網格控制層不同的命名空間中部署 Ingress 閘道。

    1. 在 Cloud Shell 中,於每個叢集上建立專屬的 asm-ingress 命名空間:

      kubectl --context=${CLUSTER_1_NAME} create namespace asm-ingress
      kubectl --context=${CLUSTER_2_NAME} create namespace asm-ingress
      
    2. asm-ingress 命名空間新增命名空間標籤:

      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
      

      使用 istio-injection=enabledasm-ingress 命名空間加上標籤,即可指示 Cloud Service Mesh 在部署 Pod 時,自動插入 Envoy 輔助容器 Proxy。

    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 閘道之間,提供額外的加密層。此外,這項功能也支援以 HTTP/2 為基礎的通訊協定,例如 gRPC。如要瞭解如何將自行簽署的憑證附加至 Ingress 閘道,請參閱後續的「建立外部 IP 位址、DNS 記錄和 TLS 憑證資源」。

      如要進一步瞭解 Ingress 閘道憑證的規定,請參閱「從負載平衡器到後端的加密」。

    4. 在每個叢集上建立 Kubernetes 密鑰,以儲存自簽憑證:

      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 閘道 Pod,原因如下:

    1. 在 Cloud Shell 中,為機群啟用多叢集服務 (MCS):

      gcloud container fleet multi-cluster-services enable
      
    2. 授予 MCS 專案或機群所需的 IAM 權限:

      gcloud projects add-iam-policy-binding PROJECT_ID \
       --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \
       --role "roles/compute.networkViewer"
      
    3. 建立 ServiceExport YAML 檔案:

      cat <<EOF > ${WORKDIR}/svc_export.yaml
      kind: ServiceExport
      apiVersion: net.gke.io/v1
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      EOF
      
    4. ServiceExport YAML 檔案套用到兩個叢集:

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

      如果收到下列錯誤訊息,請稍候片刻,等待 MCS 自訂資源定義 (CRD) 安裝完成。然後重新執行指令,將 ServiceExport YAML 檔案套用至兩個叢集。

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

    建立外部 IP 位址、DNS 記錄和 TLS 憑證資源

    在本節中,您會建立網路資源,支援稍後在本部署作業中建立的負載平衡資源。

    1. 在 Cloud Shell 中,保留靜態外部 IP 位址:

      gcloud compute addresses create mcg-ip --global
      

      GKE Gateway 資源會使用靜態 IP 位址。即使重新建立外部負載平衡器,IP 位址也不會改變。

    2. 取得靜態 IP 位址,並儲存為環境變數:

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

      如要建立穩定且容易記住的閘道 IP 位址對應,您必須有公開 DNS 記錄。

      您可以選擇任何 DNS 供應商和自動化機制。這個部署作業會使用 Endpoints,而不是建立代管 DNS 區域。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. 使用 Certificate Manager 為上一步建立的 DNS 項目名稱建立憑證:

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

      Google 代管的 TLS 憑證用於在負載平衡器終止傳入的用戶端要求。

    6. 建立憑證對應關係

      gcloud certificate-manager maps create mcg-cert-map
      

      負載平衡器會透過您在下一個步驟中建立的憑證對應項目,參照憑證。

    7. 為本節稍早建立的憑證建立憑證對應關係項目

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

    建立後端服務政策和負載平衡器資源

    在本節中,您將完成下列工作:

    • 建立含有規則的 Cloud Armor 安全性政策。
    • 建立政策,讓負載平衡器透過您先前建立的 ServiceExport YAML 檔案,檢查輸入閘道 Pod 的回應能力。
    • 使用 GKE Gateway API 建立負載平衡器資源。
    • 使用 GatewayClass 自訂資源設定特定負載平衡器類型。
    • 為機群啟用多叢集負載平衡,並將其中一個叢集指定為機群的設定叢集
    1. 在 Cloud Shell 中,建立 Cloud Armor 安全性政策:

      gcloud compute security-policies create edge-fw-policy \
          --description "Block XSS attacks"
      
    2. 為安全性政策建立規則:

      gcloud compute security-policies rules create 1000 \
          --security-policy edge-fw-policy \
          --expression "evaluatePreconfiguredExpr('xss-stable')" \
          --action "deny-403" \
          --description "XSS attack filtering"
      
    3. 建立安全性原則的 YAML 檔案,並透過對應的 ServiceImport YAML 檔案參照 ServiceExport YAML 檔案:

      cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml
      apiVersion: networking.gke.io/v1
      kind: GCPBackendPolicy
      metadata:
        name: cloud-armor-backendpolicy
        namespace: asm-ingress
      spec:
        default:
          securityPolicy: edge-fw-policy
        targetRef:
          group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
      EOF
      
    4. 將 Cloud Armor 政策套用至兩個叢集:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      
    5. 建立自訂 YAML 檔案,讓負載平衡器對兩個叢集中的輸入閘道 Pod 的 Envoy 健康狀態端點 (路徑 /healthz/ready 上的連接埠 15021) 執行健康狀態檢查:

      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 位址,建立負載平衡器 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. 建立名為 default-httproute.yamlHTTPRoute YAML 檔案,指示 Gateway 資源將要求傳送至輸入閘道:

      cat << EOF > ${WORKDIR}/default-httproute.yaml
      apiVersion: gateway.networking.k8s.io/v1
      kind: HTTPRoute
      metadata:
        name: default-httproute
        namespace: asm-ingress
      spec:
        parentRefs:
        - name: external-http
          namespace: asm-ingress
          sectionName: https
        rules:
        - backendRefs:
          - group: net.gke.io
            kind: ServiceImport
            name: asm-ingressgateway
            port: 443
      EOF
      
    12. 將您在上一個步驟中建立的 HTTPRoute YAML 檔案套用至兩個叢集:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute.yaml
      
    13. 如要執行 HTTP 至 HTTP(S) 重新導向,請建立名為 default-httproute-redirect.yaml 的額外 HTTPRoute YAML 檔案:

      cat << EOF > ${WORKDIR}/default-httproute-redirect.yaml
      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1
      metadata:
        name: http-to-https-redirect-httproute
        namespace: asm-ingress
      spec:
        parentRefs:
        - name: external-http
          namespace: asm-ingress
          sectionName: http
        rules:
        - filters:
          - type: RequestRedirect
            requestRedirect:
              scheme: https
              statusCode: 301
      EOF
      
    14. 將重新導向 HTTPRoute YAML 檔案套用至兩個叢集:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
      
    15. 檢查 Gateway 資源,確認負載平衡器部署進度:

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

      輸出內容會顯示您在這個部分輸入的資訊。

    部署 whereami 範例應用程式

    本指南使用 whereami 做為範例應用程式,直接回報哪些叢集正在回覆要求。以下章節將在兩個叢集分別設定 whereami 的部署作業:frontend 部署作業和 backend 部署作業。

    frontend 部署作業是第一個收到要求的作業。接著呼叫 backend 部署作業。

    這個模型用於示範多服務應用程式架構。 frontendbackend 服務都會部署到這兩個叢集。

    1. 在 Cloud Shell 中,為兩個叢集中的 whereami frontend 和 whereami backend 建立命名空間,並啟用命名空間插入功能:

      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. 建立 VirtualService YAML 檔案,將要求轉送至 whereami frontend

      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 服務的 YAML 檔案:DestinationRule

      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. 建立 DestinationRule YAML 檔案,啟用區域負載平衡,將區域容錯移轉至 backend 服務:

      cat << EOF > ${WORKDIR}/backend-dr.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: backend
        namespace: backend
      spec:
        host: whereami-backend.backend.svc.cluster.local
        trafficPolicy:
          connectionPool:
            http:
              maxRequestsPerConnection: 0
          loadBalancer:
            simple: LEAST_REQUEST
            localityLbSetting:
              enabled: true
          outlierDetection:
            consecutive5xxErrors: 1
            interval: 1s
            baseEjectionTime: 1m
      EOF
      
    4. backend-dr YAML 檔案套用到兩個叢集:

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

      將兩組 DestinationRule YAML 檔案套用至兩個叢集後,要求仍會保留在要求路由至的叢集。

      如要測試 frontend 服務的容錯移轉,請減少主要叢集中 Ingress 閘道的副本數量。

      從多區域負載平衡器的角度來看,這項動作會模擬叢集故障。這會導致叢集無法通過負載平衡器健康狀態檢查。本範例使用 CLUSTER_1_REGION 中的叢集。 您應該只會在 CLUSTER_2_REGION 中看到叢集的回應。

    5. 將主要叢集中 Ingress 閘道的副本數減少為零,並呼叫公開端點,確認要求已容錯移轉至其他叢集:

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

      輸出應會如下所示:

      $ curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
      {
        "backend_result": {
          "cluster_name": "edge-to-mesh-02",
          "gce_instance_id": "2717459599837162415",
          "gce_service_account": "e2m-mcg-01.svc.id.goog",
          "host_header": "whereami-backend.backend.svc.cluster.local",
          "metadata": "backend",
          "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-dxs2",
          "pod_ip": "10.124.1.7",
          "pod_name": "whereami-backend-7cbdfd788-mp8zv",
          "pod_name_emoji": "🏌🏽‍♀",
          "pod_namespace": "backend",
          "pod_service_account": "whereami-backend",
          "project_id": "e2m-mcg-01",
          "timestamp": "2023-12-01T05:41:18",
          "zone": "us-east4-b"
        },
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "6983018919754001204",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
        "metadata": "frontend",
        "node_name": "gk3-edge-to-mesh-02-pool-3-d42ddfbf-qmkn",
        "pod_ip": "10.124.1.142",
        "pod_name": "whereami-frontend-69c4c867cb-xf8db",
        "pod_name_emoji": "🏴",
        "pod_namespace": "frontend",
        "pod_service_account": "whereami-frontend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T05:41:18",
        "zone": "us-east4-b"
      }
      
    6. 如要恢復一般流量路徑,請將叢集中的 Ingress 閘道副本還原為原始值:

      kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=3 deployment/asm-ingressgateway
      
    7. 將主要區域中的副本數量減少至 0,模擬 backend 服務的故障情形:

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

      確認 frontend 服務的回應是透過負載平衡器來自us-central1主要區域,而 backend 服務的回應來自us-east4次要區域。

      輸出內容也應包含主要區域 (us-central1) 的 frontend 服務回應,以及次要區域 (us-east4) 的 backend 服務回應,如預期所示。

    8. 將後端服務副本還原為原始值,以繼續進行一般流量路徑:

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

    您現在擁有全域 HTTP(S) 負載平衡器,可做為服務網格代管多區域應用程式的前端。

    清除所用資源

    如要避免系統向您的 Google Cloud 帳戶收取本次部署所用資源的費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。

    刪除專案

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

      Go to Manage resources

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

    刪除個別資源

    如要保留您在本部署作業中使用的 Google Cloud 專案,請刪除個別資源:

    1. 在 Cloud Shell 中,刪除 HTTPRoute 資源:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute.yaml
      
    2. 刪除 GKE Gateway 資源:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
      
    3. 刪除政策:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      
    4. 刪除服務匯出項目:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/svc_export.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/svc_export.yaml
      
    5. 刪除 Cloud Armor 資源:

      gcloud --project=PROJECT_ID compute security-policies rules delete 1000 --security-policy edge-fw-policy --quiet
      gcloud --project=PROJECT_ID compute security-policies delete edge-fw-policy --quiet
      
    6. 刪除 Certificate Manager 資源:

      gcloud --project=PROJECT_ID certificate-manager maps entries delete mcg-cert-map-entry --map="mcg-cert-map" --quiet
      gcloud --project=PROJECT_ID certificate-manager maps delete mcg-cert-map --quiet
      gcloud --project=PROJECT_ID certificate-manager certificates delete mcg-cert --quiet
      
    7. 刪除 Endpoints DNS 項目:

      gcloud --project=PROJECT_ID endpoints services delete "frontend.endpoints.PROJECT_ID.cloud.goog" --quiet
      
    8. 刪除靜態 IP 位址:

      gcloud --project=PROJECT_ID compute addresses delete mcg-ip --global --quiet
      
    9. 刪除 GKE Autopilot 叢集。這個步驟需要幾分鐘的時間。

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

    後續步驟

    貢獻者

    作者:

    其他貢獻者: