部署內部多叢集閘道

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

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

在本教學課程中,您將使用範例 store 應用程式模擬實際情況,也就是線上購物服務由不同團隊擁有及營運,並部署在共用 GKE 叢集的機群中。

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

事前準備

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

  1. 部署 GKE 叢集。

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

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

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

跨區域部署內部多叢集閘道

您可以部署多叢集閘道,在多個區域的 GKE 叢集之間提供第 7 層內部負載平衡。這些閘道會使用 gke-l7-cross-regional-internal-managed-mc GatewayClass。這個 GatewayClass 會佈建由 Google Cloud 管理的跨區域內部應用程式負載平衡器,並啟用虛擬私有 IP 位址,供虛擬私有雲網路中的用戶端存取。只要使用閘道要求這些區域中的位址,即可透過所選區域的前端公開這些閘道。內部 VIP 可以是單一 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-1us-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/Gateway):

    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 等示範應用程式部署至這兩個叢集。 gke-networking-recipes 中的 store.yaml 範例檔案會建立 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-1store-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 您應該會看到列出的 storestore-west-1store-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.iokind: 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
    

    尋找 type:Programmedand 狀態為「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_WESTVIP2_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_namezone

使用靜態 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-east1us-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)。

後續步驟