本文將透過實例,引導您部署外部多叢集閘道,將網際網路流量轉送至在兩個不同 GKE 叢集中執行的應用程式。
多叢集閘道提供強大的方式,可管理部署在多個 GKE 叢集中的服務流量。使用 Google 的全球負載平衡基礎架構,即可為應用程式建立單一進入點,簡化管理作業並提升可靠性。在本教學課程中,您將使用範例 store 應用程式模擬實際情況,也就是線上購物服務由不同團隊擁有及營運,並部署在共用 GKE 叢集的機群中。
事前準備
部署多叢集閘道前,需要先完成一些環境準備作業。繼續操作前,請按照「準備多叢集閘道環境」一文的步驟操作:
最後,請先查看 GKE Gateway 控制器的限制和已知問題,再於環境中使用控制器。
多叢集、多區域、外部閘道
在本教學課程中,您將建立外部多叢集閘道,為在兩個 GKE 叢集中執行的應用程式提供外部流量。
您將在後續步驟執行下列操作:
- 將範例
store應用程式部署至gke-west-1和gke-east-1叢集。 - 在每個叢集上設定要匯出至機群的服務 (多叢集服務)。
- 將外部多叢集閘道和 HTTPRoute 部署至設定叢集 (
gke-west-1)。
部署應用程式和 Gateway 資源後,您可以使用路徑式路由,控管兩個 GKE 叢集之間的流量:
- 對
/west的要求會轉送到gke-west-1叢集中的storePod。 - 對
/east的要求會轉送到gke-east-1叢集中的storePod。 - 系統會根據叢集的健康狀態、容量和與要求用戶端的距離,將其他路徑的要求轉送至任一叢集。
部署示範應用程式
在「準備多叢集閘道環境」中部署的所有三個叢集中,建立
storeDeployment 和 Namespace:kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-west-2 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml並將下列資源部署至每個叢集:
namespace/store created deployment.apps/store created本頁面的所有範例都使用這個步驟中部署的應用程式。請務必先在所有三個叢集部署應用程式,再嘗試執行其餘步驟。本範例只使用叢集
gke-west-1和gke-east-1,gke-west-2則用於其他範例。
多叢集 Service
Service 可讓用戶端存取 Pod。由於 GKE Gateway 控制器使用容器原生負載平衡,因此不會使用 ClusterIP 或 Kubernetes 負載平衡來連線至 Pod。流量會直接從負載平衡器傳送至 Pod IP 位址。不過,服務仍扮演重要角色,是 Pod 分組的邏輯 ID。
多叢集服務 (MCS) 是跨叢集服務的 API 標準,GKE 控制器則提供跨 GKE 叢集的服務探索功能。多叢集 Gateway 控制器會使用 MCS API 資源,將 Pod 分組到可跨多個叢集定址或橫跨多個叢集的 Service 中。
多叢集服務 API 定義下列自訂資源:
- ServiceExports 會對應至 Kubernetes 服務,並將該服務的端點匯出至已向機群註冊的所有叢集。如果 Service 具有對應的 ServiceExport,表示多叢集閘道可以處理該 Service。
- 多叢集服務控制器會自動產生 ServiceImports。ServiceExport 和 ServiceImport 會成對出現。如果機群中存在 ServiceExport,系統就會建立對應的 ServiceImport,讓對應至 ServiceExport 的 Service 可從各個叢集存取。
匯出服務的運作方式如下:商店服務存在於 gke-west-1 中,可選取該叢集中的一組 Pod。系統會在叢集中建立 ServiceExport,讓機群中的其他叢集可以存取 gke-west-1 中的 Pod。ServiceExport 會對應並公開與 ServiceExport 資源名稱和命名空間相同的服務。
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
下圖顯示部署 ServiceExport 後會發生什麼情況。如果存在 ServiceExport 和 Service 配對,則多叢集 Service 控制器會將對應的 ServiceImport 部署至機群中的每個 GKE 叢集。ServiceImport 是每個叢集中 store 服務的本機表示法。這會啟用 client Pod (位於 gke-east-1 中),以便使用 ClusterIP 或無標題服務連線至 gke-west-1 中的 store Pod。以這種方式使用時,多叢集服務會在叢集之間提供東西向負載平衡,無須內部 LoadBalancer 服務。如要使用多叢集服務進行叢集間的負載平衡,請參閱設定多叢集服務。
多叢集閘道也會使用 ServiceImports,但不是用於叢集間的負載平衡。而是使用 ServiceImports 做為服務的邏輯 ID,該服務存在於其他叢集,或跨越多個叢集。下列 HTTPRoute 參照的是 ServiceImport,而非 Service 資源。參照 ServiceImport 時,這表示服務會將流量轉送至一或多個叢集中執行的後端 Pod 群組。
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: store-route
namespace: store
labels:
gateway: multi-cluster-gateway
spec:
parentRefs:
- kind: Gateway
namespace: store
name: external-http
hostnames:
- "store.example.com"
rules:
- backendRefs:
- group: net.gke.io
kind: ServiceImport
name: store
port: 8080
下圖顯示 HTTPRoute 如何將 store.example.com 流量轉送至 gke-west-1 和 gke-east-1 上的 store Pod。負載平衡器會將這些後端視為一個集區。如果其中一個叢集的 Pod 狀況不佳、無法連線或沒有流量容量,流量負載會平衡至另一個叢集中的其餘 Pod。您可以使用 store 服務和 ServiceExport 新增或移除叢集。這項功能會透明地新增或移除後端 Pod,無須進行任何明確的路由設定變更。
出口服務
此時,應用程式會在兩個叢集上執行。接著,您要將服務和 ServiceExport 部署至每個叢集,藉此公開及匯出應用程式。
將下列資訊清單套用至
gke-west-1叢集,建立store和store-west-1服務和 ServiceExports:cat << EOF | kubectl apply --context gke-west-1 -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 namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-west-1 namespace: store EOF將下列資訊清單套用至
gke-east-1叢集,建立store和store-east-1服務和 ServiceExports:cat << EOF | kubectl apply --context gke-east-1 -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 namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-east-1 namespace: store EOF確認叢集中已建立正確的 ServiceExport。
kubectl get serviceexports --context CLUSTER_NAME --namespace store將 CLUSTER_NAME 替換為
gke-west-1和gke-east-1。輸出結果會與下列內容相似:# gke-west-1 NAME AGE store 2m40s store-west-1 2m40s # gke-east-1 NAME AGE store 2m25s store-east-1 2m25s輸出內容顯示
storeService 在兩個叢集中都包含storePod,而store-west-1和store-east-1Service 則只在各自的叢集中包含storePod。這些重疊的服務可用於指定多個叢集中的 Pod,或單一叢集中的部分 Pod。幾分鐘後,請確認多叢集服務控制器是否已在叢集聯盟的所有叢集中,自動建立隨附的
ServiceImports。kubectl get serviceimports --context CLUSTER_NAME --namespace store將 CLUSTER_NAME 替換為
gke-west-1和gke-east-1。輸出應會如下所示:# gke-west-1 NAME TYPE IP AGE store ClusterSetIP ["10.112.31.15"] 6m54s store-east-1 ClusterSetIP ["10.112.26.235"] 5m49s store-west-1 ClusterSetIP ["10.112.16.112"] 6m54s # gke-east-1 NAME TYPE IP AGE store ClusterSetIP ["10.72.28.226"] 5d10h store-east-1 ClusterSetIP ["10.72.19.177"] 5d10h store-west-1 ClusterSetIP ["10.72.28.68"] 4h32m這表示機群中兩個叢集都能存取這三項服務。不過,每個車隊只有一個有效的設定叢集,因此您只能在
gke-west-1中部署參照這些 ServiceImport 的 Gateway 和 HTTPRoute。當設定叢集中的 HTTPRoute 將這些 ServiceImport 參照為後端時,無論這些服務是從哪個叢集匯出,Gateway 都能將流量轉送至這些服務。
部署 Gateway 和 HTTPRoute
應用程式部署完成後,您可以使用 gke-l7-global-external-managed-mc GatewayClass 設定 Gateway。這個閘道會建立外部應用程式負載平衡器,並設定將流量分配至目標叢集。
將下列
Gateway資訊清單套用至設定叢集,在本範例中為gke-west-1:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http namespace: store spec: gatewayClassName: gke-l7-global-external-managed-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOF這項 Gateway 設定會部署外部應用程式負載平衡器資源,並採用下列命名慣例:
gkemcg1-NAMESPACE-GATEWAY_NAME-HASH。使用這項設定建立的預設資源如下:
- 1 個負載平衡器:
gkemcg1-store-external-http-HASH - 1 個公開 IP 位址:
gkemcg1-store-external-http-HASH - 1 項轉送規則:
gkemcg1-store-external-http-HASH - 2 項後端服務:
- 預設 404 後端服務:
gkemcg1-store-gw-serve404-HASH - 預設 500 後端服務:
gkemcg1-store-gw-serve500-HASH
- 預設 404 後端服務:
- 1 項健康狀態檢查:
- 預設 404 健康狀態檢查:
gkemcg1-store-gw-serve404-HASH
- 預設 404 健康狀態檢查:
- 0 個匯款規則 (URLmap 為空白)
在這個階段,對 GATEWAY_IP:80 的任何要求都會產生預設頁面,並顯示以下訊息:
fault filter abort。- 1 個負載平衡器:
將下列
HTTPRoute資訊清單套用至設定叢集,在本範例中為gke-west-1:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: public-store-route namespace: store labels: gateway: external-http spec: hostnames: - "store.example.com" parentRefs: - name: external-http rules: - matches: - path: type: PathPrefix value: /west backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-1 port: 8080 - matches: - path: type: PathPrefix value: /east backendRefs: - group: net.gke.io kind: ServiceImport name: store-east-1 port: 8080 - backendRefs: - group: net.gke.io kind: ServiceImport name: store port: 8080 EOF在這個階段,任何對 GATEWAY_IP:80 的要求都會產生預設頁面,並顯示以下訊息:
fault filter abort。部署後,這個 HTTPRoute 會設定下列轉送行為:
- 對
/west的要求會路由到gke-west-1叢集中的storePod,因為store-west-1ServiceExport 選取的 Pod 只存在於gke-west-1叢集。 - 對
/east的要求會路由到gke-east-1叢集中的storePod,因為store-east-1ServiceExport 選取的 Pod 只存在於gke-east-1叢集。 - 系統會根據健康狀態、容量和與要求用戶端的距離,將其他路徑的要求轉送至任一叢集中的
storePod。 - 對 GATEWAY_IP:80 發出的要求會導致預設頁面顯示以下訊息:
fault filter abort。
請注意,如果特定叢集上的所有 Pod 都不正常 (或不存在),則傳送至
store服務的流量只會傳送至實際有storePod 的叢集。特定叢集上存在 ServiceExport 和 Service,並不保證流量會傳送至該叢集。Pod 必須存在,且對負載平衡器健康狀態檢查有正面回應,否則負載平衡器只會將流量傳送至其他叢集中健康狀態良好的storePod。系統會使用這項設定建立新資源:
- 3 項後端服務:
store後端服務:gkemcg1-store-store-8080-HASHstore-east-1後端服務:gkemcg1-store-store-east-1-8080-HASHstore-west-1後端服務:gkemcg1-store-store-west-1-8080-HASH
- 3 項健康檢查:
store健康狀態檢查:gkemcg1-store-store-8080-HASHstore-east-1健康狀態檢查:gkemcg1-store-store-east-1-8080-HASHstore-west-1健康狀態檢查:gkemcg1-store-store-west-1-8080-HASH
- URLmap 中的 1 項轉送規則:
store.example.com匯款規則:- 1 位主辦人:
store.example.com - 多個
matchRules,可將流量轉送至新的後端服務
- 對
下圖顯示您在兩個叢集中部署的資源。由於 gke-west-1 是 Gateway 設定叢集,因此 Gateway 控制器會監控這個叢集中的 Gateway、HTTPRoute 和 ServiceImport。每個叢集都有一個 store ServiceImport,以及另一個專屬於該叢集的 ServiceImport。兩者都指向相同的 Pod。這可讓 HTTPRoute 準確指定流量的去向,例如特定叢集上的 store Pod,或是所有叢集中的 store Pod。
請注意,這是邏輯資源模型,並非流量流程的描述。流量路徑會直接從負載平衡器傳送至後端 Pod,與哪個叢集是設定叢集沒有直接關係。
驗證部署作業
您現在可以向多叢集閘道發出要求,並在兩個 GKE 叢集之間分配流量。
檢查 Gateway 狀態和事件,確認 Gateway 和 HTTPRoute 是否已成功部署。
kubectl describe gateways.gateway.networking.k8s.io external-http --context gke-west-1 --namespace store輸出內容應類似以下所示:
Name: external-http Namespace: store Labels: <none> Annotations: networking.gke.io/addresses: /projects/PROJECT_NUMBER/global/addresses/gkemcg1-store-external-http-laup24msshu4 networking.gke.io/backend-services: /projects/PROJECT_NUMBER/global/backendServices/gkemcg1-store-gw-serve404-80-n65xmts4xvw2, /projects/PROJECT_NUMBER/global/backendServices/gke... networking.gke.io/firewalls: /projects/PROJECT_NUMBER/global/firewalls/gkemcg1-l7-default-global networking.gke.io/forwarding-rules: /projects/PROJECT_NUMBER/global/forwardingRules/gkemcg1-store-external-http-a5et3e3itxsv networking.gke.io/health-checks: /projects/PROJECT_NUMBER/global/healthChecks/gkemcg1-store-gw-serve404-80-n65xmts4xvw2, /projects/PROJECT_NUMBER/global/healthChecks/gkemcg1-s... networking.gke.io/last-reconcile-time: 2023-10-12T17:54:24Z networking.gke.io/ssl-certificates: networking.gke.io/target-http-proxies: /projects/PROJECT_NUMBER/global/targetHttpProxies/gkemcg1-store-external-http-94oqhkftu5yz networking.gke.io/target-https-proxies: networking.gke.io/url-maps: /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-store-external-http-94oqhkftu5yz API Version: gateway.networking.k8s.io/v1 Kind: Gateway Metadata: Creation Timestamp: 2023-10-12T06:59:32Z Finalizers: gateway.finalizer.networking.gke.io Generation: 1 Resource Version: 467057 UID: 1dcb188e-2917-404f-9945-5f3c2e907b4c Spec: Gateway Class Name: gke-l7-global-external-managed-mc Listeners: Allowed Routes: Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute Namespaces: From: Same Name: http Port: 80 Protocol: HTTP Status: Addresses: Type: IPAddress Value: 34.36.127.249 Conditions: Last Transition Time: 2023-10-12T07:00:41Z Message: The OSS Gateway API has deprecated this condition, do not depend on it. Observed Generation: 1 Reason: Scheduled Status: True Type: Scheduled Last Transition Time: 2023-10-12T07:00:41Z Message: Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Last Transition Time: 2023-10-12T07:00:41Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T07:00:41Z Message: The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use. GKE Gateway will stop emitting it in a future update, use "Programmed" instead. Observed Generation: 1 Reason: Ready Status: True Type: Ready Listeners: Attached Routes: 1 Conditions: Last Transition Time: 2023-10-12T07:00:41Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T07:00:41Z Message: The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use. GKE Gateway will stop emitting it in a future update, use "Programmed" instead. Observed Generation: 1 Reason: Ready Status: True Type: Ready Name: http Supported Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal UPDATE 35m (x4 over 10h) mc-gateway-controller store/external-http Normal SYNC 4m22s (x216 over 10h) mc-gateway-controller SYNC on store/external-http was a success閘道部署完成後,請從
external-http閘道擷取外部 IP 位址。kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store在下列步驟中,將
VIP替換為您收到的輸出 IP 位址。將流量傳送至網域的根路徑。這會將流量負載平衡至跨叢集
store和gke-west-1的 ServiceImport。gke-east-1負載平衡器會將流量傳送到離您最近的區域,因此您可能不會看到其他區域的回應。curl -H "host: store.example.com" http://VIP輸出內容會確認要求是由叢集中的 Pod 提供服務:
gke-east-1{ "cluster_name": "gke-east-1", "zone": "us-east1-b", "host_header": "store.example.com", "node_name": "gke-gke-east-1-default-pool-7aa30992-t2lp.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-dg22z", "pod_name_emoji": "⏭", "project_id": "agmsb-k8s", "timestamp": "2021-06-01T17:32:51" }接著,將流量傳送至
/west路徑。這會將流量轉送至store-west-1ServiceImport,該 ServiceImport 只會在gke-west-1叢集上執行 Pod。叢集專用的 ServiceImport (例如store-west-1) 可讓應用程式擁有者明確將流量傳送至特定叢集,而不是讓負載平衡器做出決定。curl -H "host: store.example.com" http://VIP/west輸出內容會確認要求是由叢集中的 Pod 提供服務:
gke-west-1{ "cluster_name": "gke-west-1", "zone": "us-west1-a", "host_header": "store.example.com", "node_name": "gke-gke-west-1-default-pool-65059399-2f41.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-d25m5", "pod_name_emoji": "🍾", "project_id": "agmsb-k8s", "timestamp": "2021-06-01T17:39:15", }最後,將流量傳送至
/east路徑。curl -H "host: store.example.com" http://VIP/east輸出內容會確認要求是由叢集中的 Pod 提供服務:
gke-east-1{ "cluster_name": "gke-east-1", "zone": "us-east1-b", "host_header": "store.example.com", "node_name": "gke-gke-east-1-default-pool-7aa30992-7j7z.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-hz6mw", "pod_name_emoji": "🧜🏾", "project_id": "agmsb-k8s", "timestamp": "2021-06-01T17:40:48" }
清除所用資源
完成本文件的練習後,請按照下列步驟移除資源,以免您的帳戶產生不必要的費用:
刪除叢集。
如果叢集不需要註冊用於其他用途,請取消註冊機群叢集。
停用
multiclusterservicediscovery功能:gcloud container fleet multi-cluster-services disable停用多叢集 Ingress:
gcloud container fleet ingress disable停用 API:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
疑難排解
沒有健康的上游
症狀:
建立閘道但無法存取後端服務時 (503 回應碼),可能會發生下列問題:
no healthy upstream
原因:
這則錯誤訊息表示健康狀態檢查探測器找不到健康狀態良好的後端服務。後端服務可能運作正常,但您可能需要自訂健康狀態檢查。
解決方法:
如要解決這個問題,請使用 HealthCheckPolicy,根據應用程式的需求自訂健康狀態檢查 (例如 /health)。
後續步驟
- 進一步瞭解 Gateway 控制器。