在代管 Cloud Service Mesh 中設定多叢集網格
Google Cloud 詳情請參閱 Cloud Service Mesh 總覽。本指南說明如何使用 Mesh CA 或 Certificate Authority Service,將兩個叢集加入單一 Cloud Service Mesh,並啟用跨叢集負載平衡。您可以輕鬆擴充這個程序,將任意數量的叢集併入網格。
多叢集 Cloud Service Mesh 設定可解決多個重要的企業情境,例如規模、位置和隔離。詳情請參閱多叢集應用實例。
必要條件
請務必先準備好兩個以上的 GKE 叢集,並符合下列要求,再按照本指南的說明操作: Google Cloud
- 叢集上已安裝 Cloud Service Mesh。您需要
asmcli
、istioctl
工具,以及asmcli
下載至--output_dir
中指定目錄的範例。 - 設定 Cloud Service Mesh 之前,網格中的叢集必須在所有 Pod 之間建立連線。此外,如果加入的叢集不在同一個專案中,則必須註冊至同一個機群主專案,且叢集必須位於共用虛擬私有雲設定中,並共用同一個網路。此外,我們建議您使用一個專案來代管共用虛擬私有雲,並使用兩個服務專案來建立叢集。詳情請參閱「透過共用虛擬私有雲設定叢集」。
- 如果您使用憑證授權單位服務,所有叢集都必須有各自的從屬 CA 集區,並鏈結至同一個根 CA 集區。否則,所有這些服務都必須使用相同的 CA 集區。
設定專案和叢集變數
為專案 ID、叢集可用區/地區、叢集名稱和環境建立下列環境變數。
export PROJECT_1=PROJECT_ID_1 export LOCATION_1=CLUSTER_LOCATION_1 export CLUSTER_1=CLUSTER_NAME_1 export CTX_1="gke_${PROJECT_1}_${LOCATION_1}_${CLUSTER_1}" export PROJECT_2=PROJECT_ID_2 export LOCATION_2=CLUSTER_LOCATION_2 export CLUSTER_2=CLUSTER_NAME_2 export CTX_2="gke_${PROJECT_2}_${LOCATION_2}_${CLUSTER_2}"
如果是新建立的叢集,請務必使用下列
gcloud
指令擷取每個叢集的憑證,否則相關聯的context
將無法在本指南的後續步驟中使用。指令取決於叢集類型 (區域或可用區):
區域
gcloud container clusters get-credentials ${CLUSTER_1} --region ${LOCATION_1} gcloud container clusters get-credentials ${CLUSTER_2} --region ${LOCATION_2}
可用區
gcloud container clusters get-credentials ${CLUSTER_1} --zone ${LOCATION_1} gcloud container clusters get-credentials ${CLUSTER_2} --zone ${LOCATION_2}
建立防火牆規則
在某些情況下,您需要建立防火牆規則,允許跨叢集流量。舉例來說,如果發生下列情況,您就需要建立防火牆規則:
- 您為網格中的叢集使用不同的子網路。
- Pod 開啟的通訊埠不是 443 和 15002。
GKE 會自動為每個節點新增防火牆規則,允許同一個子網路內的流量。如果網狀網路包含多個子網路,您必須明確設定防火牆規則,允許跨子網路流量。您必須為每個子網路新增防火牆規則,允許所有輸入流量的來源 IP CIDR 區塊和目標連接埠。
下列操作說明可讓專案中的所有叢集之間通訊,或僅限 $CLUSTER_1
和 $CLUSTER_2
之間通訊。
收集叢集網路的相關資訊。
所有專案叢集
如果叢集位於同一個專案中,可以使用下列指令,允許專案中的所有叢集進行通訊。如果專案中有不想公開的叢集,請使用「特定叢集」分頁中的指令。
function join_by { local IFS="$1"; shift; echo "$*"; } ALL_CLUSTER_CIDRS=$(gcloud container clusters list --project $PROJECT_1 --format='value(clusterIpv4Cidr)' | sort | uniq) ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}")) ALL_CLUSTER_NETTAGS=$(gcloud compute instances list --project $PROJECT_1 --format='value(tags.items.[0])' | sort | uniq) ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
特定叢集
下列指令可讓
$CLUSTER_1
和$CLUSTER_2
之間進行通訊,且不會公開專案中的其他叢集。function join_by { local IFS="$1"; shift; echo "$*"; } ALL_CLUSTER_CIDRS=$(for P in $PROJECT_1 $PROJECT_2; do gcloud --project $P container clusters list --filter="name:($CLUSTER_1,$CLUSTER_2)" --format='value(clusterIpv4Cidr)'; done | sort | uniq) ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}")) ALL_CLUSTER_NETTAGS=$(for P in $PROJECT_1 $PROJECT_2; do gcloud --project $P compute instances list --filter="name:($CLUSTER_1,$CLUSTER_2)" --format='value(tags.items.[0])' ; done | sort | uniq) ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
建立防火牆規則。
GKE
gcloud compute firewall-rules create istio-multicluster-pods \ --allow=tcp,udp,icmp,esp,ah,sctp \ --direction=INGRESS \ --priority=900 \ --source-ranges="${ALL_CLUSTER_CIDRS}" \ --target-tags="${ALL_CLUSTER_NETTAGS}" --quiet \ --network=YOUR_NETWORK
Autopilot
TAGS="" for CLUSTER in ${CLUSTER_1} ${CLUSTER_2} do TAGS+=$(gcloud compute firewall-rules list --filter="Name:$CLUSTER*" --format="value(targetTags)" | uniq) && TAGS+="," done TAGS=${TAGS::-1} echo "Network tags for pod ranges are $TAGS" gcloud compute firewall-rules create asm-multicluster-pods \ --allow=tcp,udp,icmp,esp,ah,sctp \ --network=gke-cluster-vpc \ --direction=INGRESS \ --priority=900 --network=VPC_NAME \ --source-ranges="${ALL_CLUSTER_CIDRS}" \ --target-tags=$TAGS
設定端點探索
使用宣告式 API 啟用公有或私有叢集之間的端點探索
使用機群 API 啟用代管 Cloud Service Mesh 時,系統會為這個叢集啟用端點探索功能。如果您使用其他工具佈建代管 Cloud Service Mesh,可以透過在 asm-options
configmap 中套用 "multicluster_mode":"connected"
設定,手動啟用艦隊中公有或私有叢集的端點探索功能。在同一個機群中啟用這項設定的叢集,會自動啟用彼此之間的跨叢集服務探索功能。
如果您有 Managed (TD) 控制平面實作,這是設定多叢集端點探索的唯一方法。如果您有 Managed (Istiod) 實作,建議您使用這種方法設定。
請先建立防火牆規則,再繼續操作。
啟用
如果叢集中asm-options
已有 configmap,請為叢集啟用端點探索功能:
kubectl patch configmap/asm-options -n istio-system --type merge -p '{"data":{"multicluster_mode":"connected"}}'
如果叢集中asm-options
尚未有 configmap ,請建立 configmap 並加入相關資料,然後為叢集啟用端點探索功能:
kubectl --context ${CTX_1} create configmap asm-options -n istio-system --from-file <(echo '{"data":{"multicluster_mode":"connected"}}')
停用
停用叢集的端點探索功能:
kubectl patch configmap/asm-options -n istio-system --type merge -p '{"data":{"multicluster_mode":"manual"}}'
如果取消註冊機群叢集時未停用端點探索功能,叢集中可能會保留密鑰。您必須手動清除所有剩餘的密鑰。
執行下列指令,找出需要清除的密鑰:
kubectl get secrets -n istio-system -l istio.io/owned-by=mesh.googleapis.com,istio/multiCluster=true
刪除各個密鑰:
kubectl delete secret SECRET_NAME
針對每個剩餘的密鑰重複這個步驟。
驗證多叢集連線
本節說明如何將範例 HelloWorld
和 Sleep
服務部署至多叢集環境,以驗證跨叢集負載平衡是否正常運作。
設定範例目錄的變數
前往
asmcli
的下載位置,然後執行下列指令來設定ASM_VERSION
:export ASM_VERSION="$(./asmcli --version)"
將工作資料夾設為您用來驗證跨叢集負載平衡是否正常運作的範例。這些範例位於
asmcli install
指令中指定的--output_dir
目錄子目錄中。在下列指令中,將OUTPUT_DIR
變更為您在--output_dir
中指定的目錄。export SAMPLES_DIR=OUTPUT_DIR/istio-${ASM_VERSION%+*}
啟用 Sidecar 注入功能
在每個叢集中建立範例命名空間。
for CTX in ${CTX_1} ${CTX_2} do kubectl create --context=${CTX} namespace sample done
啟用要用於注入的命名空間。步驟取決於控制層實作。
受管理 (TD)
- 將預設插入標籤套用至命名空間:
for CTX in ${CTX_1} ${CTX_2} do kubectl label --context=${CTX} namespace sample \ istio.io/rev- istio-injection=enabled --overwrite done
受管理 (Istiod)
建議:執行下列指令,將預設插入標籤套用至命名空間:
for CTX in ${CTX_1} ${CTX_2} do kubectl label --context=${CTX} namespace sample \ istio.io/rev- istio-injection=enabled --overwrite done
如果您是使用受管理 Istiod 控制平面的現有使用者: 建議您使用預設注入,但系統也支援以修訂版本為準的注入。請按照下列指示操作:
執行下列指令,找出可用的發布管道:
kubectl -n istio-system get controlplanerevision
輸出結果會與下列內容相似:
NAME AGE asm-managed-rapid 6d7h
在輸出內容中,「
NAME
」欄下方的值是與 Cloud Service Mesh 版本可用發布管道對應的修訂版本標籤。將修訂版本標籤套用至命名空間:
for CTX in ${CTX_1} ${CTX_2} do kubectl label --context=${CTX} namespace sample \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite done
安裝 HelloWorld 服務
在兩個叢集中建立 HelloWorld 服務:
kubectl create --context=${CTX_1} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l service=helloworld -n sample
kubectl create --context=${CTX_2} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l service=helloworld -n sample
將 HelloWorld v1 和 v2 部署到每個叢集
將
HelloWorld v1
部署至CLUSTER_1
,並將v2
部署至CLUSTER_2
,這有助於稍後驗證跨叢集負載平衡:kubectl create --context=${CTX_1} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l version=v1 -n sample
kubectl create --context=${CTX_2} \ -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \ -l version=v2 -n sample
使用下列指令,確認
HelloWorld v1
和v2
是否正在執行。確認輸出內容與下圖類似:kubectl get pod --context=${CTX_1} -n sample
NAME READY STATUS RESTARTS AGE helloworld-v1-86f77cd7bd-cpxhv 2/2 Running 0 40s
kubectl get pod --context=${CTX_2} -n sample
NAME READY STATUS RESTARTS AGE helloworld-v2-758dd55874-6x4t8 2/2 Running 0 40s
部署 Sleep 服務
將
Sleep
服務部署至兩個叢集。這個 Pod 會產生人工網路流量,以供示範:for CTX in ${CTX_1} ${CTX_2} do kubectl apply --context=${CTX} \ -f ${SAMPLES_DIR}/samples/sleep/sleep.yaml -n sample done
等待每個叢集中的
Sleep
服務啟動。確認輸出內容與下圖類似:kubectl get pod --context=${CTX_1} -n sample -l app=sleep
NAME READY STATUS RESTARTS AGE sleep-754684654f-n6bzf 2/2 Running 0 5s
kubectl get pod --context=${CTX_2} -n sample -l app=sleep
NAME READY STATUS RESTARTS AGE sleep-754684654f-dzl9j 2/2 Running 0 5s
驗證跨叢集負載平衡
多次呼叫 HelloWorld
服務,並檢查輸出內容,確認 v1 和 v2 交替回覆:
呼叫
HelloWorld
服務:kubectl exec --context="${CTX_1}" -n sample -c sleep \ "$(kubectl get pod --context="${CTX_1}" -n sample -l \ app=sleep -o jsonpath='{.items[0].metadata.name}')" \ -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'
輸出結果會與下列內容相似:
Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8 Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv ...
再次呼叫
HelloWorld
服務:kubectl exec --context="${CTX_2}" -n sample -c sleep \ "$(kubectl get pod --context="${CTX_2}" -n sample -l \ app=sleep -o jsonpath='{.items[0].metadata.name}')" \ -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'
輸出結果會與下列內容相似:
Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8 Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv ...
恭喜!您已驗證負載平衡的多叢集 Cloud Service Mesh!
將流量保留在叢集內
在某些情況下,預設的跨叢集負載平衡行為並不理想。如要將流量保留在「叢集本機」(也就是從 cluster-a
傳送的流量只會抵達 cluster-a
中的目的地),請使用 MeshConfig.serviceSettings
將主機名稱或萬用字元標示為 clusterLocal
。
舉例來說,您可以為個別服務、特定命名空間中的所有服務,或網格中的所有服務強制執行叢集本機流量,如下所示:
每項服務
serviceSettings:
- settings:
clusterLocal: true
hosts:
- "mysvc.myns.svc.cluster.local"
每個命名空間
serviceSettings:
- settings:
clusterLocal: true
hosts:
- "*.myns.svc.cluster.local"
全球
serviceSettings:
- settings:
clusterLocal: true
hosts:
- "*"
您也可以設定全域叢集本機規則並新增明確例外狀況 (可為特定或萬用字元),進一步調整服務存取權。在下列範例中,除了 myns 命名空間中的服務外,叢集中的所有服務都會保留叢集本機:
serviceSettings:
- settings:
clusterLocal: true
hosts:
- "*"
- settings:
clusterLocal: false
hosts:
- "*.myns.svc.cluster.local"
啟用本機叢集服務
檢查叢集中的 MeshConfig config map
kubectl get configmap -n istio-system
您應該會看到名稱為
istio-asm-managed
、istio-asm-managed-rapid
或istio-asm-managed-stable
的設定對應。如果您已從
ISTIOD
實作遷移至TRAFFIC_DIRECTOR
實作,可能會看到多個設定地圖。在這種情況下,您可以執行下列指令來判斷管道:kubectl get controlplanerevision -n istio-system
您要選取的通道是已調解的控制層修訂版本通道。
更新 ConfigMap
cat <<EOF > config.yaml apiVersion: v1 kind: ConfigMap metadata: name: CONFIGMAP_NAME namespace: istio-system data: config: | serviceSettings: - settings: clusterLocal: true hosts: - "*" EOF
將
CONFIGMAP_NAME
改成您在步驟 1 中找到的 Config Map 名稱,然後更新 Config Map。kubectl apply --context=${CTX_1} -f config.yaml
使用下列指令,確認本機叢集功能運作正常。使用
CTX_1
呼叫HelloWorld
的輸出內容類似於:kubectl exec --context="${CTX_1}" -n sample -c sleep \ "$(kubectl get pod --context="${CTX_1}" -n sample -l \ app=sleep -o jsonpath='{.items[0].metadata.name}')" \ -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'
輸出內容應會顯示「Only v1 is response」:
Hello version: v1, instance: helloworld-v2-758dd55874-6x4t8 Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv ...
如果您使用
CTX_2
呼叫HelloWorld
:kubectl exec --context="${CTX_2}" -n sample -c sleep \ "$(kubectl get pod --context="${CTX_2}" -n sample -l \ app=sleep -o jsonpath='{.items[0].metadata.name}')" \ -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'
輸出內容中應該會顯示 v1 和 v2 交替回覆的內容。
Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8 Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv ...
清除 HelloWorld 服務
完成負載平衡驗證後,請從叢集中移除 HelloWorld
和 Sleep
服務。
kubectl delete ns sample --context ${CTX_1} kubectl delete ns sample --context ${CTX_2}