在 GKE 中設定多叢集網格
Google Cloud 詳情請參閱「Cloud Service Mesh 總覽」。本指南說明如何使用 Mesh CA 或 Istio CA,將兩個叢集加入單一 Cloud Service Mesh,並啟用跨叢集負載平衡。您可以輕鬆擴展這個程序,將任意數量的叢集併入網格。
多叢集 Cloud Service Mesh 設定可解決多項企業重要情境,例如規模、位置和隔離。詳情請參閱「多叢集應用實例」。
必要條件
請務必先準備好兩個以上的 GKE 叢集,並符合下列要求,再按照本指南的說明操作: Google Cloud
在叢集上安裝 Cloud Service Mesh 1.11 以上版本,並使用
asmcli install。您需要asmcli、istioctl工具,以及asmcli下載至您在執行asmcli install時於--output_dir中指定的目錄的範例。如需設定,請按照「安裝依附工具並驗證叢集」一文中的步驟操作,以便:設定 Cloud Service Mesh 之前,網格中的叢集必須在所有 Pod 之間建立連線。此外,如果加入的叢集不在同一個專案中,則必須註冊至同一個機群主機專案,且叢集必須位於共用虛擬私有雲設定中,並共用同一個網路。此外,我們建議您使用一個專案來代管共用虛擬私有雲,並使用兩個服務專案來建立叢集。詳情請參閱「透過 Shared VPC 設定叢集」。
如果使用 Istio CA,請為兩個叢集使用相同的自訂根憑證。
如果 Cloud Service Mesh 是以私有叢集為基礎建構,建議您在同一個虛擬私有雲中建立單一子網路。否則,請務必確認下列事項:
- 控制層可透過叢集私人 IP 連線至遠端私人叢集控制層。
- 您可以將呼叫控制層的 IP 範圍新增至遠端私人叢集的授權網路。詳情請參閱「在私人叢集之間設定端點探索」。
API 伺服器必須可供多叢集網格中 Cloud Service Mesh 控制層的其他執行個體存取。
設定專案和叢集變數
為專案 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_NETWORKAutopilot
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,或是手動在公開叢集或私人叢集上啟用這項功能。
設定公有叢集之間的端點探索
如要設定 GKE 叢集之間的端點探索,請執行 asmcli create-mesh。此指令會執行下列作業:
- 將所有叢集註冊至同一個機群。
- 設定網格,以信任 Fleet Workload Identity。
- 建立遠端密鑰。
您可以指定每個叢集的 URI,或 kubeconfig 檔案的路徑。
叢集 URI
在下列指令中,將 FLEET_PROJECT_ID 替換為機群主專案的專案 ID,並將叢集 URI 替換為每個叢集的叢集名稱、可用區或區域,以及專案 ID。這個範例只顯示兩個叢集,但您可以執行指令,在其他叢集上啟用端點探索功能,但須遵守可新增至機群的叢集數量上限。
./asmcli create-mesh \
FLEET_PROJECT_ID \
${PROJECT_1}/${LOCATION_1}/${CLUSTER_1} \
${PROJECT_2}/${LOCATION_2}/${CLUSTER_2}
kubeconfig 檔案
在下列指令中,將 FLEET_PROJECT_ID 替換為機群主專案的專案 ID,並將 PATH_TO_KUBECONFIG 替換為每個 kubeconfig 檔案的路徑。這個範例只顯示兩個叢集,但您可以執行指令,在其他叢集上啟用端點探索功能,但須遵守可新增至機群的叢集數量上限。
./asmcli create-mesh \
FLEET_PROJECT_ID \
PATH_TO_KUBECONFIG_1 \
PATH_TO_KUBECONFIG_2
設定私人叢集之間的端點探索
設定遠端 Secret,允許 API 伺服器存取叢集,以便存取其他叢集的 Cloud Service Mesh 控制層。指令取決於您的 Cloud Service Mesh 類型 (叢集內或代管):
A. 如果是叢內 Cloud Service Mesh,您必須設定私人 IP,而非公開 IP,因為公開 IP 無法存取:
PRIV_IP=`gcloud container clusters describe "${CLUSTER_1}" --project "${PROJECT_1}" \ --zone "${LOCATION_1}" --format "value(privateClusterConfig.privateEndpoint)"` ./istioctl x create-remote-secret --context=${CTX_1} --name=${CLUSTER_1} --server=https://${PRIV_IP} > ${CTX_1}.secretPRIV_IP=`gcloud container clusters describe "${CLUSTER_2}" --project "${PROJECT_2}" \ --zone "${LOCATION_2}" --format "value(privateClusterConfig.privateEndpoint)"` ./istioctl x create-remote-secret --context=${CTX_2} --name=${CLUSTER_2} --server=https://${PRIV_IP} > ${CTX_2}.secretB. 如果是代管 Cloud Service Mesh:
PUBLIC_IP=`gcloud container clusters describe "${CLUSTER_1}" --project "${PROJECT_1}" \ --zone "${LOCATION_1}" --format "value(privateClusterConfig.publicEndpoint)"` ./istioctl x create-remote-secret --context=${CTX_1} --name=${CLUSTER_1} --server=https://${PUBLIC_IP} > ${CTX_1}.secretPUBLIC_IP=`gcloud container clusters describe "${CLUSTER_2}" --project "${PROJECT_2}" \ --zone "${LOCATION_2}" --format "value(privateClusterConfig.publicEndpoint)"` ./istioctl x create-remote-secret --context=${CTX_2} --name=${CLUSTER_2} --server=https://${PUBLIC_IP} > ${CTX_2}.secret將新密鑰套用至叢集:
kubectl apply -f ${CTX_1}.secret --context=${CTX_2}kubectl apply -f ${CTX_2}.secret --context=${CTX_1}
為私人叢集設定授權網路
只有在網格符合下列所有條件時,才適用本節內容:
部署多個私人叢集時,每個叢集中的 Cloud Service Mesh 控制層都需要呼叫遠端叢集的 GKE 控制層。如要允許流量,您需要在遠端叢集的授權網路中,新增呼叫叢集中的 Pod 位址範圍。
取得每個叢集的 Pod IP CIDR 區塊:
POD_IP_CIDR_1=`gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \ --format "value(ipAllocationPolicy.clusterIpv4CidrBlock)"`POD_IP_CIDR_2=`gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \ --format "value(ipAllocationPolicy.clusterIpv4CidrBlock)"`將 Kubernetes 叢集 Pod IP CIDR 區塊新增至遠端叢集:
EXISTING_CIDR_1=`gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \ --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"` gcloud container clusters update ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \ --enable-master-authorized-networks \ --master-authorized-networks ${POD_IP_CIDR_2},${EXISTING_CIDR_1//;/,}EXISTING_CIDR_2=`gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \ --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"` gcloud container clusters update ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \ --enable-master-authorized-networks \ --master-authorized-networks ${POD_IP_CIDR_1},${EXISTING_CIDR_2//;/,}詳情請參閱「建立具有授權網路的叢集」。
確認授權網路已更新:
gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \ --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \ --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"
啟用控制層全域存取權
只有在網格符合下列所有條件時,才適用本節內容:
- 您使用的是私人叢集。
- 您為網格中的叢集使用不同區域。
您必須啟用控制層全域存取權,才能讓每個叢集中的 Cloud Service Mesh 控制層呼叫遠端叢集的 GKE 控制層。
啟用控制層全域存取權:
gcloud container clusters update ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \ --enable-master-global-accessgcloud container clusters update ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \ --enable-master-global-access確認已啟用控制層全域存取權:
gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1}gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2}輸出內容中的
privateClusterConfig部分會顯示masterGlobalAccessConfig的狀態。
驗證多叢集連線
本節說明如何將範例 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在建立的命名空間中啟用補充植入功能。
建議:執行下列指令,將預設插入標籤套用至命名空間:
for CTX in ${CTX_1} ${CTX_2} do kubectl label --context=${CTX} namespace sample \ istio.io/rev- istio-injection=enabled --overwrite done建議您使用預設插入方式,但系統也支援以修訂版本為準的插入方式: 請按照下列操作說明進行:
使用下列指令找出
istiod上的修訂版本標籤:kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'將修訂版本標籤套用至命名空間。在下列指令中,
REVISION_LABEL是您在上一步記下的istiod修訂版本標籤值。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 samplekubectl 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 samplekubectl 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 sampleNAME READY STATUS RESTARTS AGE helloworld-v1-86f77cd7bd-cpxhv 2/2 Running 0 40s
kubectl get pod --context=${CTX_2} -n sampleNAME 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=sleepNAME READY STATUS RESTARTS AGE sleep-754684654f-n6bzf 2/2 Running 0 5s
kubectl get pod --context=${CTX_2} -n sample -l app=sleepNAME 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!
清理 HelloWorld 服務
完成負載平衡驗證後,請從叢集中移除 HelloWorld 和 Sleep 服務。
kubectl delete ns sample --context ${CTX_1}
kubectl delete ns sample --context ${CTX_2}