本頁說明如何部署 Kubernetes Gateway 資源,在多個 Google Kubernetes Engine (GKE) 叢集 (或機群) 之間平衡 Ingress 流量負載。部署多叢集閘道前,請參閱「啟用多叢集閘道」一文,準備好環境。
如要部署閘道,將 Ingress 流量負載平衡至單一 GKE 叢集,請參閱「部署閘道」。
多叢集閘道
多叢集閘道是一種閘道資源,可跨多個 Kubernetes 叢集進行流量負載平衡。在 GKE 中,gke-l7-global-external-managed-mc
、gke-l7-regional-external-managed-mc
、gke-l7-rilb-mc
和 gke-l7-gxlb-mc
GatewayClass 會部署多叢集閘道,在不同 GKE 叢集、Kubernetes 命名空間和不同區域之間,提供 HTTP 路由、流量分割、流量鏡像、以健康狀態為準的容錯移轉等功能。基礎架構管理員可透過多叢集閘道,輕鬆、安全且大規模地管理多個叢集和團隊的應用程式網路。
本頁面提供三個範例,說明如何使用 GKE Gateway 控制器部署多叢集 Gateway:
- 範例 1:外部多叢集閘道,可為兩個 GKE 叢集的網際網路流量提供負載平衡。
- 範例 2:第 7 層跨區域閘道。
- 範例 3:在兩個 GKE 叢集之間,根據權重分配流量,並鏡像處理內部 VPC 流量,以進行藍綠部署。
- 示例 4:以容量為基礎的閘道,可根據不同後端的容量上限,將要求負載平衡至這些後端。
每個範例都會使用相同的 store 和 site 應用程式,模擬實際情況:線上購物服務和網站服務由不同團隊擁有及營運,並部署在共用 GKE 叢集的機群中。每個範例都著重於多叢集閘道支援的不同拓撲和用途。
部署多叢集閘道前,需要先完成一些環境準備作業。請先按照「啟用多叢集閘道」一節中的步驟操作,再繼續進行:
最後,請先查看 GKE Gateway 控制器的限制和已知問題,再於環境中使用。
多叢集、多區域、外部閘道
在本教學課程中,您將建立外部多叢集閘道,為在兩個 GKE 叢集中執行的應用程式提供外部流量服務。
您將在後續步驟執行下列操作:
- 將範例
store
應用程式部署至gke-west-1
和gke-east-1
叢集。 - 在每個叢集上設定要匯出至機群的服務 (多叢集服務)。
- 將外部多叢集閘道和 HTTPRoute 部署至設定叢集 (
gke-west-1
)。
部署應用程式和閘道資源後,您可以使用路徑導向功能,控管兩個 GKE 叢集之間的流量:
- 對
/west
的要求會轉送到gke-west-1
叢集中的store
Pod。 - 對
/east
的要求會轉送到gke-east-1
叢集中的store
Pod。 - 系統會根據叢集的健康狀態、容量,以及與要求用戶端的距離,將其他路徑的要求轉送至任一叢集。
部署示範應用程式
在「啟用多叢集閘道」中部署的所有三個叢集中,建立
store
Deployment 和 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 分組的邏輯識別碼,扮演重要角色。
多叢集服務 (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
服務的本機表示法。這會啟用 gke-east-1
中的 client
Pod,以便使用 ClusterIP 或無標題服務連線至 gke-west-1
中的 store
Pod。以這種方式使用時,多叢集服務會在叢集之間提供東西向負載平衡,無須內部 LoadBalancer 服務。如要使用多叢集服務進行叢集間的負載平衡,請參閱「設定多叢集服務」。
多叢集閘道也會使用 ServiceImport,但不是用於叢集間的負載平衡。而是使用 ServiceImports 做為服務的邏輯 ID,該服務存在於其他叢集,或跨越多個叢集。下列 HTTPRoute 參照的是 ServiceImport,而非 Service 資源。參照 ServiceImport 時,這表示服務會將流量轉送至一或多個叢集中執行的後端 Pod 群組。
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
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,而不會有任何明確的路由設定變更。
出口服務
此時,應用程式會在兩個叢集上執行。接下來,您將在每個叢集中部署 Service 和 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
這表示
store
Service 包含兩個叢集中的store
Pod,而store-west-1
和store-east-1
Service 只包含各自叢集中的store
Pod。這些重疊的服務可用於指定多個叢集中的 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/v1beta1 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/v1beta1 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
叢集中的store
Pod,因為store-west-1
ServiceExport 選取的 Pod 只存在於gke-west-1
叢集。 - 對
/east
的要求會路由到gke-east-1
叢集中的store
Pod,因為store-east-1
ServiceExport 選取的 Pod 只存在於gke-east-1
叢集。 - 系統會根據健康狀態、容量和與要求用戶端的距離,將任何其他路徑的要求轉送至任一叢集中的
store
Pod。 - 對 GATEWAY_IP:80 的要求會導致預設頁面顯示以下訊息:
fault filter abort
。
請注意,如果特定叢集上的所有 Pod 都不正常 (或不存在),則傳送至
store
服務的流量只會傳送至實際有store
Pod 的叢集。特定叢集上存在 ServiceExport 和 Service,並不保證流量會傳送至該叢集。Pod 必須存在,且對負載平衡器健康狀態檢查有正面回應,否則負載平衡器只會將流量傳送至其他叢集中健康狀態良好的store
Pod。系統會使用這項設定建立新資源:
- 3 項後端服務:
store
後端服務:gkemcg1-store-store-8080-HASH
store-east-1
後端服務:gkemcg1-store-store-east-1-8080-HASH
store-west-1
後端服務:gkemcg1-store-store-west-1-8080-HASH
- 3 項健康檢查:
store
健康狀態檢查:gkemcg1-store-store-8080-HASH
store-east-1
健康狀態檢查:gkemcg1-store-store-east-1-8080-HASH
store-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 叢集之間分配流量。
檢查閘道狀態和事件,確認閘道和 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/v1beta1 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-1
ServiceImport,該 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" }
跨區域部署內部多叢集閘道
您可以部署多叢集閘道,在多個區域的 GKE 叢集之間提供第 7 層內部負載平衡。這些閘道會使用 gke-l7-cross-regional-internal-managed-mc
GatewayClass。這個 GatewayClass 會佈建跨區域內部應用程式負載平衡器,由 Google Cloud 管理,並啟用內部 VIP,供虛擬私有雲網路內的用戶端存取。只要使用閘道要求這些區域中的位址,即可透過所選區域的前端公開這些閘道。內部 VIP 可以是單一 IP 位址,也可以是多個區域中的 IP 位址,每個區域各有一個 IP 位址 (在閘道中指定)。流量會導向至最接近且健康狀態良好的後端 GKE 叢集,該叢集可處理要求。
事前準備
使用專案 ID 設定
gcloud
環境,藉此設定專案和殼層:export PROJECT_ID="YOUR_PROJECT_ID" gcloud config set project ${PROJECT_ID}
在不同地區建立 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
啟用多叢集服務 (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}
設定僅限 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 範圍不得重複或重疊。將
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
在每個叢集中建立 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
檢查 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 位址。
如要使用臨時 IP 位址,請將下列
Gateway
資訊清單儲存為cross-regional-gateway.yaml
:# cross-regional-gateway.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 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
:可附加的路徑物件類型,例如HTTPRoute
。spec.addresses
:type: networking.gke.io/ephemeral-ipv4-address/REGION
:要求臨時 IP 位址。value
:指定地址的區域,例如"us-west1"
或"us-east1"
。
將資訊清單套用至設定叢集,例如
gke-west1
:kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
將 HTTPRoute 附加至 Gateway
定義 HTTPRoute
資源來管理流量轉送,並將這些資源套用至設定叢集。
將下列
HTTPRoute
資訊清單儲存為store-route.yaml
:# store-route.yaml kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 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
命名空間中的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
目標多叢集服務。
將
HTTPRoute
資訊清單套用至設定叢集:kubectl apply --context gke-west1 -f store-route.yaml
確認閘道和路徑的狀態
檢查閘道狀態:
kubectl get gateway cross-region-gateway -n store -o yaml --context gke-west1
尋找
type:
Programmedand
狀態為「True」的條件:. You should see IP addresses assigned in the
status.addressesfield, corresponding to the regions you specified (e.g., one for
us-west1and one for
us-east1。檢查 HTTPRoute 狀態:
kubectl get httproute store-route -n store -o yaml --context gke-west1
在
status.parents[].conditions
中尋找含有type: Accepted
(或ResolvedRefs
) 和status: "True"
的條件。
確認流量
將 IP 位址指派給閘道後,您可以從位於虛擬私有雲網路內,且位於其中一個區域的用戶端 VM,或位於可連線至閘道 IP 位址的區域,測試流量。
擷取閘道 IP 位址。
下列指令會嘗試剖析 JSON 輸出內容。您可能需要根據確切的結構調整
jsonpath
。kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".
這項指令的輸出內容應包含 VIP,例如
VIP1_WEST
或VIP2_EAST
。傳送測試要求: 從虛擬私有雲中的用戶端 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 位址。
在要使用的區域中建立靜態 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 的子網路。修改
cross-regional-gateway.yaml
檔案中的spec.addresses
區段,更新閘道資訊清單:# cross-regional-gateway-static-ip.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 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-west1/addresses/cross-region-gw-ip-east" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute
套用更新後的 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
的子網路。
- 舉例來說,如果您的
藍綠部署,透過閘道進行多叢集轉送
gke-l7-global-external-managed-*
、gke-l7-regional-external-managed-*
和 gke-l7-rilb-*
GatewayClass 具有許多進階流量轉送功能,包括流量拆分、標頭比對、標頭操控、流量鏡像等。在本範例中,您將示範如何使用權重式流量分割,明確控管兩個 GKE 叢集之間的流量比例。
本範例將逐步說明服務擁有者如何將應用程式遷移或擴展至新的 GKE 叢集。藍綠部署的目標是透過多個驗證步驟降低風險,確認新叢集運作正常。這個範例將逐步說明部署的四個階段:
- 100% - 以標頭為準的 Canary 測試: 使用 HTTP 標頭路由,只將測試或合成流量傳送至新叢集。
- 100% - 鏡像流量: 將鏡像使用者流量傳送至 Canary 叢集。這項測試會將 100% 的使用者流量複製到 Canary 叢集,藉此測試叢集的容量。
- 90%-10%:將流量分配設為 10%,逐步將新叢集開放給實際流量。
- 0%-100%: 完全轉換至新叢集,如果發現任何錯誤,可選擇切換回舊叢集。
這個範例與前一個範例類似,差別在於這個範例部署的是內部多叢集閘道。這會部署內部應用程式負載平衡器,只能從 VPC 內部私下存取。您將使用先前步驟中部署的叢集和相同應用程式,但會透過不同的 Gateway 部署。
必要條件
下列範例以「部署外部多叢集閘道」中的部分步驟為基礎。請確認您已完成下列步驟,再繼續進行這個範例:
-
這個範例會使用您已設定的
gke-west-1
和gke-west-2
叢集。這些叢集位於相同區域,因為gke-l7-rilb-mc
GatewayClass 是區域性的,且僅支援相同區域中的叢集後端。 在每個叢集上部署所需的 Service 和 ServiceExports。如果您從上一個範例部署了服務和 ServiceExports,則您已部署其中一些項目。
kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-1-service.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-west-2-service.yaml
這會將類似的資源組合部署到每個叢集:
service/store created serviceexport.net.gke.io/store created service/store-west-2 created serviceexport.net.gke.io/store-west-2 created
設定僅限 Proxy 的子網路
如果您尚未設定,請為部署內部閘道的每個區域設定僅限 Proxy 的子網路。這個子網路用於為負載平衡器 Proxy 提供內部 IP 位址,且必須設定為 --purpose
設為 REGIONAL_MANAGED_PROXY
only。
您必須先建立僅限 Proxy 的子網路,才能建立管理內部應用程式負載平衡器的閘道。您在使用內部應用程式負載平衡器的虛擬私有雲 (VPC) 網路的每個區域,都必須有僅限 Proxy 的子網路。
gcloud compute networks subnets create
指令會建立僅限 Proxy 的子網路。
gcloud compute networks subnets create SUBNET_NAME \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE \
--region=REGION \
--network=VPC_NETWORK_NAME \
--range=CIDR_RANGE
更改下列內容:
SUBNET_NAME
:僅限 Proxy 子網路的名稱。REGION
:僅限 Proxy 子網路的區域。VPC_NETWORK_NAME
:包含子網路的虛擬私有雲網路名稱。CIDR_RANGE
:子網路的主要 IP 位址範圍。 您必須使用不超過/26
的子網路遮罩,使該地區的 Proxy 至少有 64 個 IP 位址可用。建議使用的子網路遮罩為/23
。
部署閘道
下列 Gateway 是從 gke-l7-rilb-mc
GatewayClass 建立,屬於地區內部 Gateway,只能以相同地區的 GKE 叢集為目標。
將下列
Gateway
資訊清單套用至設定叢集,在本範例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-http namespace: store spec: gatewayClassName: gke-l7-rilb-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOF
確認閘道已成功啟動。您可以使用下列指令,只篩選出這個閘道的事件:
kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace store
如果輸出內容與下列內容相似,表示 Gateway 部署作業成功:
LAST SEEN TYPE REASON OBJECT MESSAGE 5m18s Normal ADD gateway/internal-http store/internal-http 3m44s Normal UPDATE gateway/internal-http store/internal-http 3m9s Normal SYNC gateway/internal-http SYNC on store/internal-http was a success
以標頭為準的初期測試
服務擁有者可透過以標頭為準的 Canary 測試,比對非來自真實使用者的合成測試流量。這樣一來,您就能輕鬆驗證應用程式的基本網路功能是否正常運作,不必直接向使用者公開。
將下列
HTTPRoute
資訊清單套用至設定叢集,在本範例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: # Matches for env=canary and sends it to store-west-2 ServiceImport - matches: - headers: - name: env value: canary backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-2 port: 8080 # All other traffic goes to store-west-1 ServiceImport - backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-1 port: 8080 EOF
部署後,這個 HTTPRoute 會設定下列轉送行為:
- 傳送至
store.example.internal
沒有env: canary
HTTP 標頭的內部要求,會路由至gke-west-1
叢集上的store
Pod - 傳送至
store.example.internal
with 的內部要求會連同env: canary
HTTP 標頭,一併路由至gke-west-2
叢集上的store
Pod
將流量傳送至 Gateway IP 位址,驗證 HTTPRoute 是否正常運作。
- 傳送至
從
internal-http
擷取內部 IP 位址。kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
在下列步驟中,將 VIP 替換為您收到的輸出 IP 位址。
使用
env: canary
HTTP 標頭將要求傳送至 Gateway,這會確認流量是否轉送到gke-west-2
。在與 GKE 叢集相同的 VPC 中使用私人用戶端,確認要求是否正確傳送。您必須在可私下存取閘道 IP 位址的機器上執行下列指令,否則指令不會運作。curl -H "host: store.example.internal" -H "env: canary" http://VIP
輸出內容會確認要求是由
gke-west-2
叢集的 Pod 處理:{ "cluster_name": "gke-west-2", "host_header": "store.example.internal", "node_name": "gke-gke-west-2-default-pool-4cde1f72-m82p.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-9kdb5", "pod_name_emoji": "😂", "project_id": "agmsb-k8s", "timestamp": "2021-05-31T01:21:55", "zone": "us-west1-a" }
流量鏡像
這個階段會將流量傳送至預期叢集,但也會將流量鏡像至 Canary 叢集。
使用鏡像功能有助於判斷流量負載對應用程式效能的影響,且不會以任何方式影響對用戶的回應。並非所有類型的推出作業都必須進行這項測試,但如果推出的大幅變更可能會影響效能或負載,這項測試就很有用。
將下列
HTTPRoute
資訊清單套用至設定叢集,在本例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: # Sends all traffic to store-west-1 ServiceImport - backendRefs: - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 # Also mirrors all traffic to store-west-2 ServiceImport filters: - type: RequestMirror requestMirror: backendRef: group: net.gke.io kind: ServiceImport name: store-west-2 port: 8080 EOF
使用私人用戶端,將要求傳送至
internal-http
Gateway。 使用/mirror
路徑,以便在後續步驟中,於應用程式記錄中明確識別這項要求。curl -H "host: store.example.internal" http://VIP/mirror
輸出內容確認用戶端已收到
gke-west-1
叢集中 Pod 的回應:{ "cluster_name": "gke-west-1", "host_header": "store.example.internal", "node_name": "gke-gke-west-1-default-pool-65059399-ssfq.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-brg5w", "pod_name_emoji": "🎖", "project_id": "agmsb-k8s", "timestamp": "2021-05-31T01:24:51", "zone": "us-west1-a" }
這可確認主要叢集正在回應流量。您仍須確認要遷移的叢集是否收到鏡像流量。
檢查
gke-west-2
叢集上store
Pod 的應用程式記錄。記錄應會確認 Pod 已收到負載平衡器的鏡像流量。kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
這項輸出內容確認
gke-west-2
叢集上的 Pod 也收到相同要求,但對這些要求的回應不會傳回給用戶端。記錄中顯示的 IP 位址是負載平衡器的內部 IP 位址,這些位址會與 Pod 通訊。Found 2 pods, using pod/store-5c65bdf74f-vpqbs [2023-10-12 21:05:20,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:20] "GET /mirror HTTP/1.1" 200 - [2023-10-12 21:05:27,158] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 - [2023-10-12 21:05:27,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
流量拆分
流量分割是推出新程式碼或安全部署至新環境最常見的方法之一。服務擁有者會明確設定要傳送至 Canary 後端的流量百分比,通常是整體流量的一小部分,這樣才能在可接受的風險範圍內,判斷推出作業是否成功。
服務擁有者可以透過少數流量進行流量分割,檢查應用程式的健康狀態和回應。如果所有信號都正常,即可繼續進行全面轉換。
將下列
HTTPRoute
資訊清單套用至設定叢集,在本範例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: - backendRefs: # 90% of traffic to store-west-1 ServiceImport - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 weight: 90 # 10% of traffic to store-west-2 ServiceImport - name: store-west-2 group: net.gke.io kind: ServiceImport port: 8080 weight: 10 EOF
使用私人用戶端,持續向
internal- http
Gateway 傳送 curl 要求。while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
輸出內容大致如下,表示流量分配比例為 90/10。
"cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-2", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", ...
流量切換
藍綠遷移的最後階段是完全切換至新叢集,並移除舊叢集。如果服務擁有者實際上是將第二個叢集加入現有叢集,則最後一個步驟會有所不同,因為最終步驟會將流量導向兩個叢集。在這種情況下,建議使用單一 store
ServiceImport,其中包含 gke-west-1
和 gke-west-2
叢集的 Pod。負載平衡器可根據鄰近程度、健康狀態和容量,判斷流量應導向何處,以供主動-主動應用程式使用。
將下列
HTTPRoute
資訊清單套用至設定叢集,在本範例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: - backendRefs: # No traffic to the store-west-1 ServiceImport - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 weight: 0 # All traffic to the store-west-2 ServiceImport - name: store-west-2 group: net.gke.io kind: ServiceImport port: 8080 weight: 100 EOF
使用私人用戶端,持續向
internal- http
Gateway 傳送 curl 要求。while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
輸出內容會與下列內容相似,表示所有流量現在都會前往
gke-west-2
。"cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", ...
最後這個步驟會完成應用程式的完整藍綠遷移作業,從一個 GKE 叢集遷移至另一個 GKE 叢集。
部署以容量為基礎的負載平衡
本節的練習會跨不同區域的兩個 GKE 叢集部署應用程式,示範全域負載平衡和服務容量概念。系統會以各種每秒要求數 (RPS) 層級傳送產生的流量,顯示流量如何在叢集和區域之間進行負載平衡。
下圖顯示您將部署的拓撲,以及流量超出服務容量時,流量如何在叢集和區域之間溢出:
如要進一步瞭解流量管理,請參閱 GKE 流量管理。
準備環境
按照「啟用多叢集閘道」一文的指示準備環境。
確認 GatewayClass 資源已安裝在設定叢集上:
kubectl get gatewayclasses --context=gke-west-1
輸出結果會與下列內容相似:
NAME CONTROLLER ACCEPTED AGE gke-l7-global-external-managed networking.gke.io/gateway True 16h gke-l7-global-external-managed-mc networking.gke.io/gateway True 14h gke-l7-gxlb networking.gke.io/gateway True 16h gke-l7-gxlb-mc networking.gke.io/gateway True 14h gke-l7-regional-external-managed networking.gke.io/gateway True 16h gke-l7-regional-external-managed-mc networking.gke.io/gateway True 14h gke-l7-rilb networking.gke.io/gateway True 16h gke-l7-rilb-mc networking.gke.io/gateway True 14h
部署應用程式
將範例網頁應用程式伺服器部署至這兩個叢集:
kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
輸出結果會與下列內容相似:
namespace/store created
deployment.apps/store created
部署服務、閘道和 HTTPRoute
將下列
Service
資訊清單套用至gke-west-1
和gke-east-1
叢集:cat << EOF | kubectl apply --context gke-west-1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: traffic-test annotations: networking.gke.io/max-rate-per-endpoint: "10" spec: ports: - port: 8080 targetPort: 8080 name: http selector: app: store type: ClusterIP --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: traffic-test EOF
cat << EOF | kubectl apply --context gke-east-1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: traffic-test annotations: networking.gke.io/max-rate-per-endpoint: "10" spec: ports: - port: 8080 targetPort: 8080 name: http selector: app: store type: ClusterIP --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: traffic-test EOF
服務會加上
max-rate-per-endpoint
註解,並設為每秒 10 個要求。每個叢集有 2 個副本,因此每個叢集中的每個服務都有 20 RPS 的容量。如要進一步瞭解如何為服務選擇服務容量等級,請參閱「判斷服務容量」。
將下列
Gateway
資訊清單套用至設定叢集,在本範例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store namespace: traffic-test spec: gatewayClassName: gke-l7-global-external-managed-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOF
這個資訊清單說明外部全域多叢集閘道,會部署具有可公開存取 IP 位址的外部應用程式負載平衡器。
將下列
HTTPRoute
資訊清單套用至設定叢集,在本範例中為gke-west-1
:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store namespace: traffic-test labels: gateway: store spec: parentRefs: - kind: Gateway namespace: traffic-test name: store rules: - backendRefs: - name: store group: net.gke.io kind: ServiceImport port: 8080 EOF
資訊清單說明 HTTPRoute,該 HTTPRoute 會使用路由規則設定 Gateway,將所有流量導向商店 ServiceImport。
store
ServiceImport 會將兩個叢集中的store
Service Pod 分組,並允許負載平衡器將這些 Pod 視為單一 Service。幾分鐘後,您可以檢查 Gateway 的事件,確認是否已完成部署:
kubectl describe gateway store -n traffic-test --context gke-west-1
輸出結果會與下列內容相似:
... Status: Addresses: Type: IPAddress Value: 34.102.159.147 Conditions: Last Transition Time: 2023-10-12T21:40:59Z 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-12T21:40:59Z Message: Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Last Transition Time: 2023-10-12T21:40:59Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T21:40:59Z 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-12T21:40:59Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T21:40:59Z 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 ADD 12m mc-gateway-controller traffic-test/store Normal SYNC 6m43s mc-gateway-controller traffic-test/store Normal UPDATE 5m40s (x4 over 12m) mc-gateway-controller traffic-test/store Normal SYNC 118s (x6 over 10m) mc-gateway-controller SYNC on traffic-test/store was a success
這項輸出內容顯示閘道已成功部署。閘道部署完成後,可能仍需幾分鐘才會開始傳輸流量。請記下這項輸出內容中的 IP 位址,因為後續步驟會用到。
確認流量
使用 curl 指令測試閘道 IP 位址,確認流量是否傳遞至應用程式:
curl GATEWAY_IP_ADDRESS
輸出結果會與下列內容相似:
{
"cluster_name": "gke-west-1",
"host_header": "34.117.182.69",
"pod_name": "store-54785664b5-mxstv",
"pod_name_emoji": "👳🏿",
"project_id": "project",
"timestamp": "2021-11-01T14:06:38",
"zone": "us-west1-a"
}
這項輸出內容會顯示 Pod 中繼資料,指出要求服務的區域。
使用負載測試驗證流量
如要確認負載平衡器是否正常運作,可以在 gke-west-1
叢集中部署流量產生器。流量產生器會在不同負載層級產生流量,以展示負載平衡器的容量和溢位功能。以下步驟會示範三種負載等級:
- 10 RPS,低於商店服務的容量 (位於
gke-west-1
中)。 - 30 RPS,超過
gke-west-1
商店服務的容量,導致流量溢出至gke-east-1
。 - 60 RPS,超過兩個叢集內服務的容量。
設定資訊主頁
取得 Gateway 的基礎 URLmap 名稱:
kubectl get gateway store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
輸出結果會與下列內容相似:
/projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-traffic-test-store-armvfyupay1t
前往 Google Cloud 控制台的「指標探索器」頁面。
在「選取指標」下方,按一下「代碼:MQL」。
輸入下列查詢,觀察兩個叢集中商店服務的流量指標:
fetch https_lb_rule | metric 'loadbalancing.googleapis.com/https/backend_request_count' | filter (resource.url_map_name == 'GATEWAY_URL_MAP') | align rate(1m) | every 1m | group_by [resource.backend_scope], [value_backend_request_count_aggregate: aggregate(value.backend_request_count)]
將
GATEWAY_URL_MAP
替換為上一步的 URLmap 名稱。按一下 [Run query] (執行查詢)。在下一節中部署負載產生器後,請等待至少 5 分鐘,圖表才會顯示指標。
以每秒 10 個要求的速度進行測試
將 Pod 部署至
gke-west-1
叢集:kubectl run --context gke-west-1 -i --tty --rm loadgen \ --image=cyrilbkr/httperf \ --restart=Never \ -- /bin/sh -c 'httperf \ --server=GATEWAY_IP_ADDRESS \ --hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 10'
將
GATEWAY_IP_ADDRESS
替換為上一步的閘道 IP 位址。輸出內容會與下列內容相似,表示流量產生器正在傳送流量:
If you don't see a command prompt, try pressing enter.
負載產生器會持續將 10 RPS 傳送至閘道。即使流量來自 Google Cloud 區域內部,負載平衡器仍會將其視為來自美國西岸的用戶端流量。為模擬真實的用戶端多樣性,負載產生器會將每個 HTTP 要求做為新的 TCP 連線傳送,也就是說,流量會更平均地分配到後端 Pod。
產生器最多需要 5 分鐘,才能為資訊主頁產生流量。
查看 Metrics Explorer 資訊主頁。系統會顯示兩條線,指出負載平衡至各叢集的流量:
您應該會看到
us-west1-a
接收到大約 10 RPS 的流量,而us-east1-b
則未接收到任何流量。由於流量產生器是在us-west1
中執行,所有流量都會傳送至gke-west-1
叢集中的服務。使用 Ctrl+C 停止負載產生器,然後刪除 Pod:
kubectl delete pod loadgen --context gke-west-1
以 30 RPS 進行測試
再次部署負載產生器,但這次設定為傳送 30 RPS:
kubectl run --context gke-west-1 -i --tty --rm loadgen \ --image=cyrilbkr/httperf \ --restart=Never \ -- /bin/sh -c 'httperf \ --server=GATEWAY_IP_ADDRESS \ --hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 30'
產生器最多需要 5 分鐘,才能為資訊主頁產生流量。
查看 Cloud Ops 資訊主頁。
您應該會看到大約有 20 個 RPS 傳送至
us-west1-a
,10 個 RPS 傳送至us-east1-b
。這表示gke-west-1
中的服務已充分利用,且流量溢出 10 RPS 至gke-east-1
中的服務。使用 Ctrl+C 停止負載產生器,然後刪除 Pod:
kubectl delete pod loadgen --context gke-west-1
以 60 RPS 進行測試
部署設定為傳送 60 RPS 的負載產生器:
kubectl run --context gke-west-1 -i --tty --rm loadgen \ --image=cyrilbkr/httperf \ --restart=Never \ -- /bin/sh -c 'httperf \ --server=GATEWAY_IP_ADDRESS \ --hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 60'
等待 5 分鐘,然後查看 Cloud Ops 資訊主頁。現在應該會顯示兩個叢集都收到大約 30 RPS。由於全球所有服務都過度使用,因此不會有流量溢出,服務會吸收所有可吸收的流量。
使用 Ctrl+C 停止負載產生器,然後刪除 Pod:
kubectl delete pod loadgen --context gke-west-1
清除所用資源
完成本頁的練習後,請按照下列步驟移除資源,以免您的帳戶產生不必要的費用:
刪除叢集。
如果叢集不需要註冊其他用途,請取消註冊機群叢集。
停用
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
使用共用虛擬私有雲的多叢集閘道
多叢集閘道也可以部署在共用虛擬私有雲環境中,並視用途採用不同拓撲。
下表說明共用 VPC 環境中支援的多叢集閘道拓撲:
情境 | 機群主專案 | 設定叢集 | 工作負載叢集 |
---|---|---|---|
1 | 共用虛擬私有雲主專案 | 共用虛擬私有雲主專案 | 共用虛擬私有雲主專案 |
2 | 共用虛擬私有雲服務專案 | 共用虛擬私有雲服務專案 (與車隊服務專案相同) |
共用虛擬私有雲服務專案 (與車隊服務專案相同) |
如要在共用虛擬私有雲環境中建立多叢集閘道,請按照下列步驟操作:
按照步驟使用共用虛擬私有雲設定多叢集服務
如果您打算使用多叢集內部閘道,請建立僅限 Proxy 的子網路
完成上述步驟後,即可根據拓撲驗證部署作業。
疑難排解
內部閘道的 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
)。
後續步驟
- 進一步瞭解 Gateway 控制器。