部署內部多叢集閘道

本文件將引導您完成實際範例,部署內部多叢集閘道,將虛擬私有雲網路中的流量轉送至在兩個不同 GKE 叢集中執行的應用程式。

多叢集閘道提供強大的方式,可管理部署在多個 GKE 叢集中的服務流量。使用 Google 的全球負載平衡基礎架構,即可為應用程式建立單一進入點,簡化管理作業並提高可靠性。

在本教學課程中,您將使用範例 store 應用程式模擬實際情境,其中線上購物服務由不同小組自有自營,並部署在共用 GKE 叢集的機群中。

這個範例說明如何設定路徑式轉送,將流量導向不同叢集。

事前準備

多叢集閘道必須先完成一些環境準備工作,才能部署。繼續操作前,請按照「準備多叢集閘道環境」一文的步驟操作:

  1. 部署 GKE 叢集。

  2. 註冊叢集至機群 (如尚未註冊)。

  3. 啟用多叢集服務和多叢集閘道控制器。

最後,請先查看 GKE Gateway 控制器的限制和已知問題,再於環境中使用控制器。

在不同區域部署內部多叢集閘道

您可以部署多叢集閘道,在多個區域的 GKE 叢集之間提供第 7 層內部負載平衡。這些閘道會使用 gke-l7-cross-regional-internal-managed-mc GatewayClass。這個 GatewayClass 會佈建由 Google Cloud 管理的跨區域內部應用程式負載平衡器,並啟用虛擬私有雲網路內用戶端可存取的內部 VIP。只要使用 Gateway 要求這些區域中的位址,即可透過所選區域中的前端公開這些 Gateway。內部 VIP 可以是單一 IP 位址,也可以是多個區域中的 IP 位址 (每個區域各有一個 IP 位址,且這些 IP 位址是在閘道中指定)。流量會導向至距離最近、健康狀態良好的後端 GKE 叢集,該叢集可處理要求。

必要條件

  1. 使用專案 ID 設定 gcloud 環境,藉此設定專案和殼層:

    export PROJECT_ID="YOUR_PROJECT_ID"
    gcloud config set project ${PROJECT_ID}
    
  2. 在不同區域中建立 GKE 叢集。

    本範例使用兩個叢集:us-west1 中的 gke-west-1 和 us-east1 中的 gke-east-1。確認已啟用 Gateway API (--gateway-api=standard),且叢集已註冊至機群。

    gcloud container clusters create gke-west-1 \
        --location=us-west1-a \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    
    gcloud container clusters create gke-east-1 \
        --location=us-east1-c \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    

    重新命名情境,方便存取:

    gcloud container clusters get-credentials gke-west-1 \
      --location=us-west1-a \
      --project=${PROJECT_ID}
    
    gcloud container clusters get-credentials gke-east-1 \
      --location=us-east1-c \
      --project=${PROJECT_ID}
    kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1
    kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1
    
  3. 啟用多叢集服務 (MCS) 和多叢集 Ingress (MCI/閘道):

    gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID}
    
    # Set the config membership to one of your clusters (e.g., gke-west-1)
    # This cluster will be the source of truth for multi-cluster Gateway and Route resources.
    gcloud container fleet ingress enable \
        --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \
        --project=${PROJECT_ID}
    
  4. 設定 Proxy 專用子網路。 在 GKE 叢集所在區域和負載平衡器運作區域中,都必須有 Proxy 專用子網路。跨區域內部應用程式負載平衡器需要將這個子網路的用途設為 GLOBAL_MANAGED_PROXY。

    # Proxy-only subnet for us-west1
    gcloud compute networks subnets create us-west1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-west1 \
        --network=default \
        --range=10.129.0.0/23 # Choose an appropriate unused CIDR range
    
    # Proxy-only subnet for us-east1
    gcloud compute networks subnets create us-east1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-east1 \
        --network=default \
        --range=10.130.0.0/23 # Choose an appropriate unused CIDR range
    

    如果您不是使用預設網路,請將 default 替換為虛擬私有雲網路名稱。確認 CIDR 範圍不重複且不重疊。

  5. 將示範應用程式 (例如 store) 部署至這兩個叢集。範例 store.yaml 檔案 (來自 gke-networking-recipes) 會建立 store 命名空間和部署作業。

    kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    
  6. 在每個叢集中建立 Kubernetes Service 資源和 ServiceExport 資源,從各個叢集匯出服務,讓機群中的服務可供探索。以下範例會從各叢集匯出一般 store 服務和特定區域服務 (store-west-1、store-east-1),全部位於 store 命名空間內。

    適用於 gke-west1:

    cat << EOF | kubectl apply --context gke-west1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-west-1 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-west-1 # Exporting the region-specific service
      namespace: store
    EOF
    

    套用至 gke-east1:

    cat << EOF | kubectl apply --context gke-east1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-east-1 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-east-1 # Exporting the region-specific service
      namespace: store
    EOF
    
  7. 檢查 ServiceImports: 確認 ServiceImport 資源是在 store 命名空間內的每個叢集中建立。建立這些項目可能需要幾分鐘。bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n store 您應該會看到列出的 store、store-west-1 和 store-east-1 (或根據傳播的相關項目)。

設定內部多區域閘道

定義參照 gke-l7-cross-regional-internal-managed-mc GatewayClass 的 Gateway 資源。將這個資訊清單套用至指定的設定叢集,例如 gke-west-1。

spec.addresses 欄位可讓您要求特定區域的臨時 IP 位址,或使用預先分配的靜態 IP 位址。

  1. 如要使用臨時 IP 位址,請將下列 Gateway 資訊清單儲存為 cross-regional-gateway.yaml:

    # cross-regional-gateway.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: internal-cross-region-gateway
      namespace: store # Namespace for the Gateway resource
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      # Addresses across regions. Address value is allowed to be empty or matching
      # the region name.
      - type: networking.gke.io/ephemeral-ipv4-address/us-west1
        value: "us-west1"
      - type: networking.gke.io/ephemeral-ipv4-address/us-east1
        value: "us-east1"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute # Only allow HTTPRoute to attach
    

    以下清單定義了上述 YAML 檔案中的部分欄位:

    • metadata.namespace:建立 Gateway 資源的命名空間,例如 store。
    • spec.gatewayClassName:GatewayClass 的名稱。必須為 gke-l7-cross-regional-internal-managed-mc。
    • spec.listeners.allowedRoutes.kinds:可附加的 Route 物件類型,例如 HTTPRoute。
    • spec.addresses:
      • type: networking.gke.io/ephemeral-ipv4-address/REGION:要求臨時 IP 位址。
      • value:指定地址的區域,例如 "us-west1" 或 "us-east1"。
  2. 將資訊清單套用至設定叢集,例如 gke-west1:

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

將 HTTPRoute 附加至 Gateway

定義 HTTPRoute 資源來管理流量路徑,並將這些資源套用至設定叢集。

  1. 將下列 HTTPRoute 資訊清單儲存為 store-route.yaml:

    # store-route.yaml
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store-route
      namespace: store
      labels:
        gateway: cross-regional-internal
    spec:
      parentRefs:
      - name: internal-cross-region-gateway
        namespace: store # Namespace where the Gateway is deployed
      hostnames:
      - "store.example.internal" # Hostname clients will use
      rules:
      - matches: # Rule for traffic to /west
        - path:
            type: PathPrefix
            value: /west
        backendRefs:
        - group: net.gke.io # Indicates a multi-cluster ServiceImport
          kind: ServiceImport
          name: store-west-1 # Targets the ServiceImport for the west cluster
          port: 8080
      - matches: # Rule for traffic to /east
        - path:
            type: PathPrefix
            value: /east
        backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-east-1 # Targets the ServiceImport for the east cluster
          port: 8080
      - backendRefs: # Default rule for other paths (e.g., /)
        - group: net.gke.io
          kind: ServiceImport
          name: store # Targets the generic 'store' ServiceImport (any region)
          port: 8080
    

    以下清單定義了上述 YAML 檔案中的部分欄位:

    • spec.parentRefs:將這個路徑附加至 store 命名空間中的 internal-cross-region-gateway。
    • spec.hostnames:代表用戶端用來存取服務的主機名稱。
    • spec.rules:定義轉送邏輯。這個範例使用路徑型轉送:
      • /west 流量會傳送至 store-west-1 ServiceImport。
      • /east 流量會傳送至 store-east-1 ServiceImport。
      • 其他所有流量 (例如 /) 都會傳送至一般 store ServiceImport。
    • backendRefs:
      • group: net.gke.io 和 kind: ServiceImport 目標多叢集服務。
  2. 將 HTTPRoute 資訊清單套用至設定叢集:

    kubectl apply --context gke-west1 -f store-route.yaml
    

驗證閘道和路徑的狀態

  1. 查看閘道狀態:

    kubectl get gateway internal-cross-region-gateway -n store -o yaml --context gke-west1
    

    尋找狀態為「True」的條件:type:Programmedandstatus: "True". You should see IP addresses assigned in thestatus.addressesfield, corresponding to the regions you specified (e.g., one forus-west1and one forus-east1。

  2. 檢查 HTTPRoute 狀態:

    kubectl get httproute store-route -n store -o yaml --context gke-west1
    

    在 status.parents[].conditions 中尋找包含 type: Accepted (或 ResolvedRefs) 和 status: "True" 的條件。

確認流量

將 IP 位址指派給閘道後,您可以從虛擬私有雲網路中某個區域的用戶端 VM,或可連線至閘道 IP 位址的區域,測試流量。

  1. 擷取閘道 IP 位址。

    下列指令會嘗試剖析 JSON 輸出內容。您可能需要根據確切的結構調整 jsonpath。

    kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".
    

    這個指令的輸出內容應包含 VIP,例如 VIP1_WEST 或 VIP2_EAST。

  2. 傳送測試要求: 從虛擬私有雲中的用戶端 VM:

    # Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1
    # Traffic to /west should ideally be served by gke-west-1
    curl -H "host: store.example.internal" http://VIP_WEST/west
    curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path
    
    # Traffic to /east should ideally be served by gke-east-1
    curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path
    curl -H "host: store.example.internal" http://VIP_EAST/east
    
    # Traffic to / (default) could be served by either cluster
    curl -H "host: store.example.internal" http://VIP_WEST/
    curl -H "host: store.example.internal" http://VIP_EAST/
    

    回覆應包含 store 應用程式的詳細資料,指出哪個後端 Pod 處理了要求,例如 cluster_name 或 zone。

使用靜態 IP 位址

您可以改用預先分配的靜態內部 IP 位址,而非臨時 IP 位址。

  1. 在要使用的區域建立靜態 IP 位址:

    gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID}
    gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}
    

    如果您不是使用預設子網路,請將 default 替換為要分配 IP 位址的子網路名稱。這些子網路是 一般子網路,不是 Proxy 專用子網路。

  2. 修改 cross-regional-gateway.yaml 檔案中的 spec.addresses 區段,更新閘道資訊清單:

    # cross-regional-gateway-static-ip.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: internal-cross-region-gateway # Or a new name if deploying alongside
      namespace: store
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      - type: networking.gke.io/named-address-with-region # Use for named static IP
        value: "regions/us-west1/addresses/cross-region-gw-ip-west"
      - type: networking.gke.io/named-address-with-region
        value: "regions/us-east1/addresses/cross-region-gw-ip-east"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    
  3. 套用更新後的 Gateway 資訊清單。

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

非預設子網路的特別注意事項

使用非預設子網路時,請注意下列事項:

  • 相同虛擬私有雲網路:所有使用者建立的資源 (例如靜態 IP 位址、僅限 Proxy 的子網路和 GKE 叢集) 都必須位於相同的虛擬私有雲網路。

  • 位址子網路:為閘道建立靜態 IP 位址時,系統會從指定區域的常規子網路分配位址。

  • 叢集子網路命名:每個區域都必須有一個子網路,名稱與 MCG 設定叢集所在的子網路相同。

    • 舉例來說,如果 gke-west-1 設定叢集位於 projects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet,則您要求位址的區域也必須有 my-custom-subnet 子網路。如果您要求 us-east1 和 us-centra1 區域中的位址,則這些區域中也必須有名為 my-custom-subnet 的子網路。

清除所用資源

完成本文件中的練習後,請按照下列步驟移除資源,以免帳戶產生不必要的費用:

  1. 刪除叢集。

  2. 如果叢集不需要註冊用於其他用途,請取消註冊機群叢集。

  3. 停用 multiclusterservicediscovery 功能:

    gcloud container fleet multi-cluster-services disable
    
  4. 停用多叢集 Ingress:

    gcloud container fleet ingress disable
    
  5. 停用 API:

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

疑難排解

內部閘道的 Proxy 專用子網路不存在

如果內部閘道上顯示下列事件,表示該區域沒有 Proxy 專用子網路。如要解決這個問題,請部署僅限 Proxy 的子網路。

generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.

沒有健康的上游

症狀:

建立閘道但無法存取後端服務時 (503 回應代碼),可能會發生下列問題:

no healthy upstream

原因:

這則錯誤訊息表示健康狀態檢查探測器找不到健康的後端服務。後端服務可能運作正常,但您可能需要自訂健康狀態檢查。

解決方法:

如要解決這個問題,請使用 HealthCheckPolicy 根據應用程式的需求自訂健康狀態檢查 (例如 /health)。

後續步驟