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

Last reviewed 2026-06-04 UTC

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

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

架構

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

外部負載平衡器會透過 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. 在 Google Cloud 控制台的專案選擇器頁面中,選取或建立 Google Cloud 專案。

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

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

    前往專案選取器

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

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

    啟用 Cloud Shell

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

  4. 設定預設 Google Cloud 專案:

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

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

  5. 建立目前使用的目錄:

    mkdir -p ${HOME}/edge-to-mesh-multi-region
    cd ${HOME}/edge-to-mesh-multi-region
    export WORKDIR=`pwd`
    

建立 GKE 叢集

在本節中,您將建立 GKE 叢集,用來代管應用程式和支援基礎架構,這些項目會在稍後建立。

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

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

    export CLUSTER_1_NAME=edge-to-mesh-01
    export CLUSTER_2_NAME=edge-to-mesh-02
    export CLUSTER_1_REGION=us-central1
    export CLUSTER_2_REGION=us-east4
    export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
    
  3. 啟用本指南中使用的 Google Cloud 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 \
    --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 \
    --enable-private-nodes --enable-fleet
    
  6. 確認叢集正在執行。最多可能需要 20 分鐘,所有叢集才會開始運作:

    gcloud container clusters list
    

    輸出結果會與下列內容相似:

    NAME             LOCATION     MASTER_VERSION      MASTER_IP      MACHINE_TYPE   NODE_VERSION        NUM_NODES  STATUS   STACK_TYPE
    edge-to-mesh-01  us-central1  1.35.5-gke.1000000  34.31.166.104  ek-standard-8  1.35.5-gke.1000000  1          RUNNING  IPV4
    edge-to-mesh-02  us-east4     1.35.5-gke.1000000  35.245.233.88  ek-standard-8  1.35.5-gke.1000000  1          RUNNING  IPV4
    
  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: '2026-06-04T23:40:02.666228685Z'
    membershipSpecs:
      projects/497535075790/locations/us-central1/memberships/edge-to-mesh-01:
        mesh:
          management: MANAGEMENT_AUTOMATIC
      projects/497535075790/locations/us-east4/memberships/edge-to-mesh-02:
        mesh:
          management: MANAGEMENT_AUTOMATIC
    membershipStates:
      projects/497535075790/locations/us-central1/memberships/edge-to-mesh-01:
        servicemesh:
          conditions:
          - code: VPCSC_GA_SUPPORTED
            details: This control plane supports VPC-SC GA.
            documentationLink: http://cloud.google.com/service-mesh/docs/managed/vpc-sc
            severity: INFO
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            implementation: TRAFFIC_DIRECTOR
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: 'Revision ready for use: asm-managed-rapid.'
          updateTime: '2026-06-04T23:45:52.958139396Z'
      projects/497535075790/locations/us-east4/memberships/edge-to-mesh-02:
        servicemesh:
          conditions:
          - code: VPCSC_GA_SUPPORTED
            details: This control plane supports VPC-SC GA.
            documentationLink: http://cloud.google.com/service-mesh/docs/managed/vpc-sc
            severity: INFO
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            implementation: TRAFFIC_DIRECTOR
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: 'Revision ready for use: asm-managed-rapid.'
          updateTime: '2026-06-04T23:45:54.621862416Z'
    name: projects/e2m-mc-h2c/locations/global/features/servicemesh
    resourceState:
      state: ACTIVE
    spec: {}
    updateTime: '2026-06-04T23:40:55.123874541Z'
    

部署外部應用程式負載平衡器,並建立 Ingress 閘道

在本節中,您將透過 GKE Gateway 控制器部署外部應用程式負載平衡器,並為兩個叢集建立 Ingress 閘道。gateway 和 gatewayClass 資源會自動佈建負載平衡器,並執行後端健康狀態檢查。如要在負載平衡器上提供 TLS 終止功能,請建立 Certificate Manager 資源,並將其附加至負載平衡器。此外,您可以使用端點,自動為應用程式佈建公用 DNS 名稱。

在兩個叢集上安裝 Ingress 閘道

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

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

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

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

    輸出結果會與下列內容相似:

    namespace/ingress-gateway labeled
    

    使用 istio-injection=enabled 為 ingress-gateway 命名空間加上標籤,可指示 Cloud Service Mesh 在部署 Pod 時,自動插入 Envoy Sidecar 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 憑證資源」一節。

    如要為 GFE 到網格的連線使用 HTTP/2,但不需要自己的加密,可以使用 H2C。

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

  4. 在每個叢集上建立 Kubernetes 密鑰,用來儲存自行簽署的憑證:

    kubectl --context ${CLUSTER_1_NAME} -n ingress-gateway 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 ingress-gateway 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: ingress-gateway
    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: ingress-gateway
    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: ingress-gateway
    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: ingress-gateway
    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: ingress-gateway
    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自訂資源匯出 Ingress 閘道 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: ingress-gateway
    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: "ingress-gateway" 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 檔案,檢查 Ingress 閘道 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: ingress-gateway
    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 檔案,讓負載平衡器對兩個叢集中的 Ingress 閘道 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: ingress-gateway
    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: ingress-gateway
      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.yaml 的 HTTPRoute YAML 檔案,指示 Gateway 資源將要求傳送至 Ingress Gateway:

    cat << EOF > ${WORKDIR}/default-httproute.yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: default-httproute
      namespace: ingress-gateway
    spec:
      parentRefs:
      - name: external-http
        namespace: ingress-gateway
        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: ingress-gateway
    spec:
      parentRefs:
      - name: external-http
        namespace: ingress-gateway
        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 ingress-gateway
    

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

部署 whereami 範例應用程式

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

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

這個模型用於展示多服務應用程式架構。frontend 和 backend 服務會部署到這兩個叢集。

  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
    labels:
    - includeSelectors: true
      includeTemplates: true
      pairs:
        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
    labels:
    - includeSelectors: true
      includeTemplates: true
      pairs:
        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:
      - ingress-gateway/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 指令,您會發現回應 (來自 frontend 和 backend) 來自不同區域。負載平衡器會在回應中提供地理位置路由。也就是說,負載平衡器會將用戶端的要求轉送至最近的現用叢集,但要求仍會隨機送達。要求偶爾會從一個區域傳送到另一個區域,這會增加延遲時間和費用。

在下一節中,您會在服務網格中實作地區負載平衡,確保要求留在本地。

為 whereami 啟用及測試地區負載平衡

在本節中,您將在服務網格中實作區域負載平衡,確保要求在本機處理。您也會執行一些測試,瞭解 whereami 如何處理各種失敗情境。

當您向 whereami frontend 服務提出要求時,負載平衡器會將要求傳送至相對於用戶端延遲時間最短的叢集。也就是說,網格內的 Ingress 閘道 Pod 會將要求負載平衡至兩個叢集中的 whereami frontend Pod。本節將在網格中啟用地區負載平衡,解決這個問題。

  1. 在 Cloud Shell 中,建立 DestinationRule YAML 檔案,啟用區域性負載平衡區域容錯移轉至 frontend 服務:

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

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

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

刪除個別資源

如要保留在此部署作業中使用的 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. 刪除端點 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
    

後續步驟

貢獻者

作者:

其他貢獻者: