本文將引導您在兩個 GKE 叢集之間,對範例store
應用程式進行藍綠部署。藍綠部署是將應用程式遷移至新 GKE 叢集的有效策略,可將風險降至最低。將流量從目前的叢集 (藍色) 逐步轉移至新的叢集 (綠色),即可在正式環境中驗證新環境,然後再全面轉換。
在本教學課程中,您將使用範例 store 應用程式模擬實際情況,也就是線上購物服務由不同團隊擁有及營運,並部署在共用 GKE 叢集的機群中。
事前準備
部署多叢集閘道前,需要先完成一些環境準備作業。繼續操作前,請按照「準備多叢集閘道環境」一文的步驟操作:
最後,請先查看 GKE Gateway 控制器的限制和已知問題,再於環境中使用控制器。
藍綠部署,透過閘道進行多叢集轉送
gke-l7-global-external-managed-*、gke-l7-regional-external-managed-* 和 gke-l7-rilb-* GatewayClass 具有許多進階流量轉送功能,包括流量拆分、標頭比對、標頭操控、流量鏡像等。在本範例中,您將示範如何使用權重式流量分割,明確控管兩個 GKE 叢集之間的流量比例。
本範例將逐步說明服務擁有者在遷移或擴展應用程式至新 GKE 叢集時,會採取哪些實際步驟。藍綠部署的目標是透過多個驗證步驟降低風險,確認新叢集運作正常。這個範例將逐步說明部署作業的四個階段:
- 100% - 以標頭為準的金絲雀部署: 使用 HTTP 標頭路由,只將測試或合成流量傳送至新叢集。
- 100% - 鏡像流量: 將使用者流量鏡像至 Canary 叢集。這項測試會將 100% 的使用者流量複製到 Canary 叢集,藉此測試叢集的容量。
- 90%-10%:將流量分配給新叢集 10%,讓新叢集逐漸處理實際流量。
- 0%-100%: 完全轉換至新叢集,如果發現任何錯誤,可以選擇切換回舊叢集。
這個範例與前一個範例類似,差別在於這個範例部署的是內部多叢集閘道。這會部署內部應用程式負載平衡器,只能從 VPC 內部以私有方式存取。您將使用先前步驟中部署的叢集和相同應用程式,但會透過不同的 Gateway 部署。
必要條件
下列範例以「部署外部多叢集閘道」中的部分步驟為基礎。請先完成下列步驟,再繼續進行這個範例:
-
本範例使用您已設定的
gke-west-1和gke-west-2叢集。這些叢集位於相同區域,因為gke-l7-rilb-mcGatewayClass 是區域性的,且僅支援相同區域中的叢集後端。 在每個叢集上部署所需的 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。
您必須先建立僅限 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。
部署閘道
下列閘道是從 gke-l7-rilb-mc GatewayClass 建立,屬於地區內部閘道,只能以相同地區的 GKE 叢集為目標。
將下列
Gateway資訊清單套用至設定叢集,在本範例中為gke-west-1:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1 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/v1 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: canaryHTTP 標頭的內部要求,會路由至gke-west-1叢集上的storePod - 對
store.example.internalwith 的內部要求會連同env: canaryHTTP 標頭,一併路由至gke-west-2叢集上的storePod
將流量傳送至 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: canaryHTTP 標頭將要求傳送至 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/v1 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-httpGateway。 使用/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叢集上storePod 的應用程式記錄。記錄應會確認 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/v1 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- httpGateway 傳送 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/v1 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- httpGateway 傳送 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 叢集。
清除所用資源
完成本文件的練習後,請按照下列步驟移除資源,以免您的帳戶產生不必要的費用:
刪除叢集。
如果叢集不需要註冊用於其他用途,請取消註冊機群叢集。
停用
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 控制器。