本文說明如何完成下列工作:
- 部署透過 GKE 閘道和 Cloud Service Mesh 公開的全球分散式應用程式。
- 結合 Cloud Load Balancing 和 Cloud Service Mesh,向多個用戶端公開應用程式。
- 將負載平衡器與部署在多個Google Cloud 區域的服務網格整合。
本部署指南適用於平台管理員。也適合執行 Cloud Service Mesh 的進階實務工作者。這些操作說明也適用於 Istio on GKE。
架構
下圖顯示服務網格的預設輸入拓撲,也就是在單一叢集上公開輸入閘道 Proxy 的外部 TCP/UDP 負載平衡器:
本部署指南使用 Google Kubernetes Engine (GKE) Gateway 資源。具體來說,這項功能會使用多叢集閘道,在分布於兩個區域的多個 Autopilot 叢集前方,設定多區域負載平衡。
上圖顯示資料在雲端進入和網格進入情境中的流動方式。詳情請參閱相關參考架構文件中的架構圖說明。
目標
- 在 Google Cloud 上將一對 GKE Autopilot 叢集部署至同一個車隊。
- 將以 Istio 為基礎的 Cloud Service Mesh 部署至相同機群。
- 使用 GKE Gateway 設定負載平衡器,終止公開 HTTPS 流量。
- 將公開 HTTPS 流量直接導向 Cloud Service Mesh 代管的應用程式,這些應用程式部署在多個叢集和區域。
- 將 whereami 範例應用程式部署至兩個 Autopilot 叢集。
成本最佳化
在本文件中,您會使用 Google Cloud的下列計費元件:
- Google Kubernetes Engine
- Cloud Load Balancing
- Cloud Service Mesh
- Multi Cluster Ingress
- Google Cloud Armor
- Certificate Manager
- Cloud Endpoints
如要根據預測用量估算費用,請使用 Pricing Calculator。
完成本文所述工作後,您可以刪除已建立的資源,避免繼續計費。詳情請參閱清除所用資源一節。
事前準備
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
您將透過 Cloud Shell 執行這項部署作業的所有終端機指令。
設定預設 Google Cloud 專案:
export PROJECT=YOUR_PROJECT export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)") gcloud config set project PROJECT_ID
將
PROJECT_ID
替換為您要用於這項部署作業的專案 ID。建立工作目錄:
mkdir -p ${HOME}/edge-to-mesh-multi-region cd ${HOME}/edge-to-mesh-multi-region export WORKDIR=`pwd`
在 Cloud Shell 中,建立新的
kubeconfig
檔案。這個步驟可確保您不會與現有的 (預設)kubeconfig
檔案發生衝突。touch edge2mesh_mr_kubeconfig export KUBECONFIG=${WORKDIR}/edge2mesh_mr_kubeconfig
定義建立 GKE 叢集和其中資源時使用的環境變數。修改預設區域選項,以符合您的需求。
export CLUSTER_1_NAME=edge-to-mesh-01 export CLUSTER_2_NAME=edge-to-mesh-02 export CLUSTER_1_REGION=us-central1 export CLUSTER_2_REGION=us-east4 export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
啟用本指南中使用的 Google Cloud API:
gcloud services enable \ container.googleapis.com \ mesh.googleapis.com \ gkehub.googleapis.com \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ certificatemanager.googleapis.com
在
CLUSTER_1_REGION
中建立具備私人節點的 GKE Autopilot 叢集。使用--async
標記,避免等待第一個叢集佈建並向機群註冊:gcloud container clusters create-auto --async \ ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} \ --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \ --enable-private-nodes --enable-fleet
在
CLUSTER_2_REGION
中建立並註冊第二個 Autopilot 叢集:gcloud container clusters create-auto \ ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} \ --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \ --enable-private-nodes --enable-fleet
確認叢集正在執行。所有叢集都開始運作最多可能需要 20 分鐘:
gcloud container clusters list
輸出結果會與下列內容相似:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS edge-to-mesh-01 us-central1 1.27.5-gke.200 34.27.171.241 e2-small 1.27.5-gke.200 RUNNING edge-to-mesh-02 us-east4 1.27.5-gke.200 35.236.204.156 e2-small 1.27.5-gke.200 RUNNING
收集
CLUSTER_1_NAME
的憑證。您是以非同步方式建立CLUSTER_1_NAME
,因此可以在佈建叢集時執行其他指令。gcloud container clusters get-credentials ${CLUSTER_1_NAME} \ --region ${CLUSTER_1_REGION}
如要清楚瞭解 Kubernetes 背景資訊的名稱,請將其重新命名為叢集名稱:
kubectl config rename-context gke_PROJECT_ID_${CLUSTER_1_REGION}_${CLUSTER_1_NAME} ${CLUSTER_1_NAME} kubectl config rename-context gke_PROJECT_ID_${CLUSTER_2_REGION}_${CLUSTER_2_NAME} ${CLUSTER_2_NAME}
在 Cloud Shell 中,為機群啟用 Cloud Service Mesh:
gcloud container fleet mesh enable
啟用自動控制層和資料層管理功能:
gcloud container fleet mesh update \ --management automatic \ --memberships ${CLUSTER_1_NAME},${CLUSTER_2_NAME}
等待約 20 分鐘。然後確認控制層狀態為
ACTIVE
:gcloud container fleet mesh describe
輸出結果會與下列內容相似:
createTime: '2023-11-30T19:23:21.713028916Z' membershipSpecs: projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01: mesh: management: MANAGEMENT_AUTOMATIC projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02: mesh: management: MANAGEMENT_AUTOMATIC membershipStates: projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01: servicemesh: controlPlaneManagement: details: - code: REVISION_READY details: 'Ready: asm-managed-rapid' implementation: ISTIOD state: ACTIVE dataPlaneManagement: details: - code: OK details: Service is running. state: ACTIVE state: code: OK description: |- Revision ready for use: asm-managed-rapid. All Canonical Services have been reconciled successfully. updateTime: '2024-06-27T09:00:21.333579005Z' projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02: servicemesh: controlPlaneManagement: details: - code: REVISION_READY details: 'Ready: asm-managed-rapid' implementation: ISTIOD state: ACTIVE dataPlaneManagement: details: - code: OK details: Service is running. state: ACTIVE state: code: OK description: |- Revision ready for use: asm-managed-rapid. All Canonical Services have been reconciled successfully. updateTime: '2024-06-27T09:00:24.674852751Z' name: projects/e2m-private-test-01/locations/global/features/servicemesh resourceState: state: ACTIVE spec: {} updateTime: '2024-06-04T17:16:28.730429993Z'
在 Cloud Shell 中,於每個叢集上建立專屬的
asm-ingress
命名空間:kubectl --context=${CLUSTER_1_NAME} create namespace asm-ingress kubectl --context=${CLUSTER_2_NAME} create namespace asm-ingress
為
asm-ingress
命名空間新增命名空間標籤:kubectl --context=${CLUSTER_1_NAME} label namespace asm-ingress istio-injection=enabled kubectl --context=${CLUSTER_2_NAME} label namespace asm-ingress istio-injection=enabled
輸出結果會與下列內容相似:
namespace/asm-ingress labeled
使用
istio-injection=enabled
為asm-ingress
命名空間加上標籤,即可指示 Cloud Service Mesh 在部署 Pod 時,自動插入 Envoy 輔助容器 Proxy。產生自行簽署的憑證,以供日後使用:
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ -subj "/CN=frontend.endpoints.PROJECT_ID.cloud.goog/O=Edge2Mesh Inc" \ -keyout ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \ -out ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
憑證可在負載平衡器與服務網格 Ingress 閘道之間,提供額外的加密層。此外,這項功能也支援以 HTTP/2 為基礎的通訊協定,例如 gRPC。如要瞭解如何將自行簽署的憑證附加至 Ingress 閘道,請參閱後續的「建立外部 IP 位址、DNS 記錄和 TLS 憑證資源」。
如要進一步瞭解 Ingress 閘道憑證的規定,請參閱「從負載平衡器到後端的加密」。
在每個叢集上建立 Kubernetes 密鑰,以儲存自簽憑證:
kubectl --context ${CLUSTER_1_NAME} -n asm-ingress create secret tls \ edge2mesh-credential \ --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \ --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt kubectl --context ${CLUSTER_2_NAME} -n asm-ingress create secret tls \ edge2mesh-credential \ --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \ --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
如要與外部應用程式負載平衡器整合,請建立 kustomize 變體,設定 Ingress 閘道資源:
mkdir -p ${WORKDIR}/asm-ig/base cat <<EOF > ${WORKDIR}/asm-ig/base/kustomization.yaml resources: - github.com/GoogleCloudPlatform/anthos-service-mesh-samples/docs/ingress-gateway-asm-manifests/base EOF mkdir ${WORKDIR}/asm-ig/variant cat <<EOF > ${WORKDIR}/asm-ig/variant/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: asm-ingressgateway namespace: asm-ingress rules: - apiGroups: [""] resources: ["secrets"] verbs: ["get", "watch", "list"] EOF cat <<EOF > ${WORKDIR}/asm-ig/variant/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: asm-ingressgateway namespace: asm-ingress roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: asm-ingressgateway subjects: - kind: ServiceAccount name: asm-ingressgateway EOF cat <<EOF > ${WORKDIR}/asm-ig/variant/service-proto-type.yaml apiVersion: v1 kind: Service metadata: name: asm-ingressgateway namespace: asm-ingress spec: ports: - name: status-port port: 15021 protocol: TCP targetPort: 15021 - name: http port: 80 targetPort: 8080 appProtocol: HTTP - name: https port: 443 targetPort: 8443 appProtocol: HTTP2 type: ClusterIP EOF cat <<EOF > ${WORKDIR}/asm-ig/variant/gateway.yaml apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: asm-ingressgateway namespace: asm-ingress spec: servers: - port: number: 443 name: https protocol: HTTPS hosts: - "*" # IMPORTANT: Must use wildcard here when using SSL, as SNI isn't passed from GFE tls: mode: SIMPLE credentialName: edge2mesh-credential EOF cat <<EOF > ${WORKDIR}/asm-ig/variant/kustomization.yaml namespace: asm-ingress resources: - ../base - role.yaml - rolebinding.yaml patches: - path: service-proto-type.yaml target: kind: Service - path: gateway.yaml target: kind: Gateway EOF
將 Ingress 閘道設定套用至兩個叢集:
kubectl --context ${CLUSTER_1_NAME} apply -k ${WORKDIR}/asm-ig/variant kubectl --context ${CLUSTER_2_NAME} apply -k ${WORKDIR}/asm-ig/variant
- 讓負載平衡器處理多個叢集中的 Ingress 閘道 Pod。
- 允許 Ingress 閘道 Pod 將要求 Proxy 至在服務網格中執行的服務。
在 Cloud Shell 中,為機群啟用多叢集服務 (MCS):
gcloud container fleet multi-cluster-services enable
授予 MCS 專案或機群所需的 IAM 權限:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \ --role "roles/compute.networkViewer"
建立
ServiceExport
YAML 檔案:cat <<EOF > ${WORKDIR}/svc_export.yaml kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: asm-ingressgateway namespace: asm-ingress EOF
將
ServiceExport
YAML 檔案套用到兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/svc_export.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/svc_export.yaml
如果收到下列錯誤訊息,請稍候片刻,等待 MCS 自訂資源定義 (CRD) 安裝完成。然後重新執行指令,將
ServiceExport
YAML 檔案套用至兩個叢集。error: resource mapping not found for name: "asm-ingressgateway" namespace: "asm-ingress" from "svc_export.yaml": no matches for kind "ServiceExport" in version "net.gke.io/v1" ensure CRDs are installed first
在 Cloud Shell 中,保留靜態外部 IP 位址:
gcloud compute addresses create mcg-ip --global
GKE Gateway 資源會使用靜態 IP 位址。即使重新建立外部負載平衡器,IP 位址也不會改變。
取得靜態 IP 位址,並儲存為環境變數:
export MCG_IP=$(gcloud compute addresses describe mcg-ip --global --format "value(address)") echo ${MCG_IP}
如要建立穩定且容易記住的閘道 IP 位址對應,您必須有公開 DNS 記錄。
您可以選擇任何 DNS 供應商和自動化機制。這個部署作業會使用 Endpoints,而不是建立代管 DNS 區域。Endpoints 會為外部 IP 位址提供免費的 Google 管理 DNS 記錄。
執行下列指令,建立名為
dns-spec.yaml
的 YAML 檔案:cat <<EOF > ${WORKDIR}/dns-spec.yaml swagger: "2.0" info: description: "Cloud Endpoints DNS" title: "Cloud Endpoints DNS" version: "1.0.0" paths: {} host: "frontend.endpoints.PROJECT_ID.cloud.goog" x-google-endpoints: - name: "frontend.endpoints.PROJECT_ID.cloud.goog" target: "${MCG_IP}" EOF
dns-spec.yaml
檔案會以frontend.endpoints.PROJECT_ID.cloud.goog
的形式定義公開 DNS 記錄,其中PROJECT_ID
是專案的專屬 ID。部署
dns-spec.yaml
檔案,建立 DNS 項目。這項程序需要幾分鐘才能完成。gcloud endpoints services deploy ${WORKDIR}/dns-spec.yaml
使用 Certificate Manager 為上一步建立的 DNS 項目名稱建立憑證:
gcloud certificate-manager certificates create mcg-cert \ --domains="frontend.endpoints.PROJECT_ID.cloud.goog"
Google 代管的 TLS 憑證用於在負載平衡器終止傳入的用戶端要求。
建立憑證對應關係:
gcloud certificate-manager maps create mcg-cert-map
負載平衡器會透過您在下一個步驟中建立的憑證對應項目,參照憑證。
為本節稍早建立的憑證建立憑證對應關係項目:
gcloud certificate-manager maps entries create mcg-cert-map-entry \ --map="mcg-cert-map" \ --certificates="mcg-cert" \ --hostname="frontend.endpoints.PROJECT_ID.cloud.goog"
- 建立含有規則的 Cloud Armor 安全性政策。
- 建立政策,讓負載平衡器透過您先前建立的
ServiceExport
YAML 檔案,檢查輸入閘道 Pod 的回應能力。 - 使用 GKE Gateway API 建立負載平衡器資源。
- 使用
GatewayClass
自訂資源設定特定負載平衡器類型。 - 為機群啟用多叢集負載平衡,並將其中一個叢集指定為機群的設定叢集。
在 Cloud Shell 中,建立 Cloud Armor 安全性政策:
gcloud compute security-policies create edge-fw-policy \ --description "Block XSS attacks"
為安全性政策建立規則:
gcloud compute security-policies rules create 1000 \ --security-policy edge-fw-policy \ --expression "evaluatePreconfiguredExpr('xss-stable')" \ --action "deny-403" \ --description "XSS attack filtering"
建立安全性原則的 YAML 檔案,並透過對應的
ServiceImport
YAML 檔案參照ServiceExport
YAML 檔案:cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml apiVersion: networking.gke.io/v1 kind: GCPBackendPolicy metadata: name: cloud-armor-backendpolicy namespace: asm-ingress spec: default: securityPolicy: edge-fw-policy targetRef: group: net.gke.io kind: ServiceImport name: asm-ingressgateway EOF
將 Cloud Armor 政策套用至兩個叢集:
kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
建立自訂 YAML 檔案,讓負載平衡器對兩個叢集中的輸入閘道 Pod 的 Envoy 健康狀態端點 (路徑
/healthz/ready
上的連接埠15021
) 執行健康狀態檢查:cat <<EOF > ${WORKDIR}/ingress-gateway-healthcheck.yaml apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: ingress-gateway-healthcheck namespace: asm-ingress spec: default: config: httpHealthCheck: port: 15021 portSpecification: USE_FIXED_PORT requestPath: /healthz/ready type: HTTP targetRef: group: net.gke.io kind: ServiceImport name: asm-ingressgateway EOF
將您在上一個步驟中建立的自訂 YAML 檔案套用至兩個叢集:
kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
為機群啟用多叢集負載平衡,並將
CLUSTER_1_NAME
指定為設定叢集:gcloud container fleet ingress enable \ --config-membership=${CLUSTER_1_NAME} \ --location=${CLUSTER_1_REGION}
在車隊中授予 Gateway 控制器的 IAM 權限:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \ --role "roles/container.admin"
透過參照
gke-l7-global-external-managed-mc
gatewayClass
和您先前建立的靜態 IP 位址,建立負載平衡器 YAML 檔案:cat <<EOF > ${WORKDIR}/frontend-gateway.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http namespace: asm-ingress annotations: networking.gke.io/certmap: mcg-cert-map spec: gatewayClassName: gke-l7-global-external-managed-mc listeners: - name: http # list the port only so we can redirect any incoming http requests to https protocol: HTTP port: 80 - name: https protocol: HTTPS port: 443 allowedRoutes: kinds: - kind: HTTPRoute addresses: - type: NamedAddress value: mcg-ip EOF
將
frontend-gateway
YAML 檔案套用到這兩個叢集。除非您將其他設定叢集指定為授權叢集,否則只有CLUSTER_1_NAME
具有授權:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
建立名為
default-httproute.yaml
的HTTPRoute
YAML 檔案,指示 Gateway 資源將要求傳送至輸入閘道:cat << EOF > ${WORKDIR}/default-httproute.yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: default-httproute namespace: asm-ingress spec: parentRefs: - name: external-http namespace: asm-ingress sectionName: https rules: - backendRefs: - group: net.gke.io kind: ServiceImport name: asm-ingressgateway port: 443 EOF
將您在上一個步驟中建立的
HTTPRoute
YAML 檔案套用至兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute.yaml
如要執行 HTTP 至 HTTP(S) 重新導向,請建立名為
default-httproute-redirect.yaml
的額外HTTPRoute
YAML 檔案:cat << EOF > ${WORKDIR}/default-httproute-redirect.yaml kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: http-to-https-redirect-httproute namespace: asm-ingress spec: parentRefs: - name: external-http namespace: asm-ingress sectionName: http rules: - filters: - type: RequestRedirect requestRedirect: scheme: https statusCode: 301 EOF
將重新導向
HTTPRoute
YAML 檔案套用至兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
檢查 Gateway 資源,確認負載平衡器部署進度:
kubectl --context=${CLUSTER_1_NAME} describe gateway external-http -n asm-ingress
輸出內容會顯示您在這個部分輸入的資訊。
在 Cloud Shell 中,為兩個叢集中的 whereami
frontend
和 whereamibackend
建立命名空間,並啟用命名空間插入功能:kubectl --context=${CLUSTER_1_NAME} create ns frontend kubectl --context=${CLUSTER_1_NAME} label namespace frontend istio-injection=enabled kubectl --context=${CLUSTER_1_NAME} create ns backend kubectl --context=${CLUSTER_1_NAME} label namespace backend istio-injection=enabled kubectl --context=${CLUSTER_2_NAME} create ns frontend kubectl --context=${CLUSTER_2_NAME} label namespace frontend istio-injection=enabled kubectl --context=${CLUSTER_2_NAME} create ns backend kubectl --context=${CLUSTER_2_NAME} label namespace backend istio-injection=enabled
為 whereami
backend
建立 kustomize 變體:mkdir -p ${WORKDIR}/whereami-backend/base cat <<EOF > ${WORKDIR}/whereami-backend/base/kustomization.yaml resources: - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s EOF mkdir ${WORKDIR}/whereami-backend/variant cat <<EOF > ${WORKDIR}/whereami-backend/variant/cm-flag.yaml apiVersion: v1 kind: ConfigMap metadata: name: whereami data: BACKEND_ENABLED: "False" # assuming you don't want a chain of backend calls METADATA: "backend" EOF cat <<EOF > ${WORKDIR}/whereami-backend/variant/service-type.yaml apiVersion: "v1" kind: "Service" metadata: name: "whereami" spec: type: ClusterIP EOF cat <<EOF > ${WORKDIR}/whereami-backend/variant/kustomization.yaml nameSuffix: "-backend" namespace: backend commonLabels: app: whereami-backend resources: - ../base patches: - path: cm-flag.yaml target: kind: ConfigMap - path: service-type.yaml target: kind: Service EOF
將 whereami
backend
變體套用至兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-backend/variant kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-backend/variant
為 whereami
frontend
建立 kustomize 變體:mkdir -p ${WORKDIR}/whereami-frontend/base cat <<EOF > ${WORKDIR}/whereami-frontend/base/kustomization.yaml resources: - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s EOF mkdir whereami-frontend/variant cat <<EOF > ${WORKDIR}/whereami-frontend/variant/cm-flag.yaml apiVersion: v1 kind: ConfigMap metadata: name: whereami data: BACKEND_ENABLED: "True" BACKEND_SERVICE: "http://whereami-backend.backend.svc.cluster.local" EOF cat <<EOF > ${WORKDIR}/whereami-frontend/variant/service-type.yaml apiVersion: "v1" kind: "Service" metadata: name: "whereami" spec: type: ClusterIP EOF cat <<EOF > ${WORKDIR}/whereami-frontend/variant/kustomization.yaml nameSuffix: "-frontend" namespace: frontend commonLabels: app: whereami-frontend resources: - ../base patches: - path: cm-flag.yaml target: kind: ConfigMap - path: service-type.yaml target: kind: Service EOF
將 whereami
frontend
變體套用至兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-frontend/variant kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
建立
VirtualService
YAML 檔案,將要求轉送至 whereamifrontend
:cat << EOF > ${WORKDIR}/frontend-vs.yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: whereami-vs namespace: frontend spec: gateways: - asm-ingress/asm-ingressgateway hosts: - 'frontend.endpoints.PROJECT_ID.cloud.goog' http: - route: - destination: host: whereami-frontend port: number: 80 EOF
將
frontend-vs
YAML 檔案套用到兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-vs.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
現在您已將
frontend-vs.yaml
部署至兩個叢集,請嘗試呼叫叢集的公開端點:curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
輸出結果會與下列內容相似:
{ "backend_result": { "cluster_name": "edge-to-mesh-02", "gce_instance_id": "8396338201253702608", "gce_service_account": "e2m-mcg-01.svc.id.goog", "host_header": "whereami-backend.backend.svc.cluster.local", "metadata": "backend", "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-645h", "pod_ip": "10.124.0.199", "pod_name": "whereami-backend-7cbdfd788-8mmnq", "pod_name_emoji": "📸", "pod_namespace": "backend", "pod_service_account": "whereami-backend", "project_id": "e2m-mcg-01", "timestamp": "2023-12-01T03:46:24", "zone": "us-east4-b" }, "cluster_name": "edge-to-mesh-01", "gce_instance_id": "1047264075324910451", "gce_service_account": "e2m-mcg-01.svc.id.goog", "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog", "metadata": "frontend", "node_name": "gk3-edge-to-mesh-01-pool-2-d687e3c0-5kf2", "pod_ip": "10.54.1.71", "pod_name": "whereami-frontend-69c4c867cb-dgg8t", "pod_name_emoji": "🪴", "pod_namespace": "frontend", "pod_service_account": "whereami-frontend", "project_id": "e2m-mcg-01", "timestamp": "2023-12-01T03:46:24", "zone": "us-central1-c" }
在 Cloud Shell 中,建立啟用區域負載平衡區域容錯移轉至
frontend
服務的 YAML 檔案:DestinationRule
cat << EOF > ${WORKDIR}/frontend-dr.yaml apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: frontend namespace: frontend spec: host: whereami-frontend.frontend.svc.cluster.local trafficPolicy: connectionPool: http: maxRequestsPerConnection: 0 loadBalancer: simple: LEAST_REQUEST localityLbSetting: enabled: true outlierDetection: consecutive5xxErrors: 1 interval: 1s baseEjectionTime: 1m EOF
上述程式碼範例只會為
frontend
服務啟用本機路由。您也需要處理後端的額外設定。將
frontend-dr
YAML 檔案套用到兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-dr.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
建立
DestinationRule
YAML 檔案,啟用區域負載平衡,將區域容錯移轉至backend
服務:cat << EOF > ${WORKDIR}/backend-dr.yaml apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: backend namespace: backend spec: host: whereami-backend.backend.svc.cluster.local trafficPolicy: connectionPool: http: maxRequestsPerConnection: 0 loadBalancer: simple: LEAST_REQUEST localityLbSetting: enabled: true outlierDetection: consecutive5xxErrors: 1 interval: 1s baseEjectionTime: 1m EOF
將
backend-dr
YAML 檔案套用到兩個叢集:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/backend-dr.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/backend-dr.yaml
將兩組
DestinationRule
YAML 檔案套用至兩個叢集後,要求仍會保留在要求路由至的叢集。如要測試
frontend
服務的容錯移轉,請減少主要叢集中 Ingress 閘道的副本數量。從多區域負載平衡器的角度來看,這項動作會模擬叢集故障。這會導致叢集無法通過負載平衡器健康狀態檢查。本範例使用
CLUSTER_1_REGION
中的叢集。 您應該只會在CLUSTER_2_REGION
中看到叢集的回應。將主要叢集中 Ingress 閘道的副本數減少為零,並呼叫公開端點,確認要求已容錯移轉至其他叢集:
kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=0 deployment/asm-ingressgateway
輸出應會如下所示:
$ curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq { "backend_result": { "cluster_name": "edge-to-mesh-02", "gce_instance_id": "2717459599837162415", "gce_service_account": "e2m-mcg-01.svc.id.goog", "host_header": "whereami-backend.backend.svc.cluster.local", "metadata": "backend", "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-dxs2", "pod_ip": "10.124.1.7", "pod_name": "whereami-backend-7cbdfd788-mp8zv", "pod_name_emoji": "🏌🏽♀", "pod_namespace": "backend", "pod_service_account": "whereami-backend", "project_id": "e2m-mcg-01", "timestamp": "2023-12-01T05:41:18", "zone": "us-east4-b" }, "cluster_name": "edge-to-mesh-02", "gce_instance_id": "6983018919754001204", "gce_service_account": "e2m-mcg-01.svc.id.goog", "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog", "metadata": "frontend", "node_name": "gk3-edge-to-mesh-02-pool-3-d42ddfbf-qmkn", "pod_ip": "10.124.1.142", "pod_name": "whereami-frontend-69c4c867cb-xf8db", "pod_name_emoji": "🏴", "pod_namespace": "frontend", "pod_service_account": "whereami-frontend", "project_id": "e2m-mcg-01", "timestamp": "2023-12-01T05:41:18", "zone": "us-east4-b" }
如要恢復一般流量路徑,請將叢集中的 Ingress 閘道副本還原為原始值:
kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=3 deployment/asm-ingressgateway
將主要區域中的副本數量減少至 0,模擬
backend
服務的故障情形:kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=0 deployment/whereami-backend
確認
frontend
服務的回應是透過負載平衡器來自us-central1
主要區域,而backend
服務的回應來自us-east4
次要區域。輸出內容也應包含主要區域 (
us-central1
) 的frontend
服務回應,以及次要區域 (us-east4
) 的backend
服務回應,如預期所示。將後端服務副本還原為原始值,以繼續進行一般流量路徑:
kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=3 deployment/whereami-backend
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
在 Cloud Shell 中,刪除
HTTPRoute
資源:kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute.yaml kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute.yaml
刪除 GKE Gateway 資源:
kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
刪除政策:
kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
刪除服務匯出項目:
kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/svc_export.yaml kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/svc_export.yaml
刪除 Cloud Armor 資源:
gcloud --project=PROJECT_ID compute security-policies rules delete 1000 --security-policy edge-fw-policy --quiet gcloud --project=PROJECT_ID compute security-policies delete edge-fw-policy --quiet
刪除 Certificate Manager 資源:
gcloud --project=PROJECT_ID certificate-manager maps entries delete mcg-cert-map-entry --map="mcg-cert-map" --quiet gcloud --project=PROJECT_ID certificate-manager maps delete mcg-cert-map --quiet gcloud --project=PROJECT_ID certificate-manager certificates delete mcg-cert --quiet
刪除 Endpoints DNS 項目:
gcloud --project=PROJECT_ID endpoints services delete "frontend.endpoints.PROJECT_ID.cloud.goog" --quiet
刪除靜態 IP 位址:
gcloud --project=PROJECT_ID compute addresses delete mcg-ip --global --quiet
刪除 GKE Autopilot 叢集。這個步驟需要幾分鐘的時間。
gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} --quiet gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} --quiet
- 瞭解更多 GKE 閘道提供的功能,可與服務網格搭配使用。
- 瞭解適用於 GKE 的不同類型 Cloud Load Balancing。
- 瞭解 Cloud Service Mesh 提供的功能。
- 如需更多參考架構、圖表和最佳做法,請瀏覽 Cloud 架構中心。
- Alex Mattson | 應用程式專員工程師
- Mark Chilvers | 應用程式專員工程師
- Abdelfettah Sghiouar | 雲端開發人員服務代表
- Greg Bray | 客戶工程師
- Paul Revello | 雲端解決方案架構師
- Valavan Rajakumar | 主要企業架構師
建立 GKE 叢集
在本節中,您將建立 GKE 叢集,以託管應用程式和支援基礎架構,這些基礎架構會在稍後的部署指南中建立。
安裝服務網格
在本節中,您將透過 Fleet API 設定代管 Cloud Service Mesh。使用 Fleet API 啟用 Cloud Service Mesh,可透過宣告式方法佈建服務網格。
部署外部應用程式負載平衡器並建立 Ingress 閘道
在本節中,您將透過 GKE Gateway 控制器部署外部應用程式負載平衡器,並為兩個叢集建立 Ingress 閘道。gateway
和 gatewayClass
資源會自動佈建負載平衡器,並執行後端健康狀態檢查。如要在負載平衡器上提供 TLS 終止功能,請建立 Certificate Manager 資源,並將這些資源附加至負載平衡器。此外,您可以使用 Endpoints 自動為應用程式佈建公開 DNS 名稱。
在兩個叢集上安裝 Ingress 閘道
為確保安全,建議您在與網格控制層不同的命名空間中部署 Ingress 閘道。
使用多叢集服務,將 Ingress 閘道 Pod 公開至負載平衡器
在本節中,您將透過 ServiceExport
自訂資源匯出輸入閘道 Pod。您必須透過 ServiceExport
自訂資源匯出 Ingress 閘道 Pod,原因如下:
建立外部 IP 位址、DNS 記錄和 TLS 憑證資源
在本節中,您會建立網路資源,支援稍後在本部署作業中建立的負載平衡資源。
建立後端服務政策和負載平衡器資源
在本節中,您將完成下列工作:
部署 whereami 範例應用程式
本指南使用 whereami 做為範例應用程式,直接回報哪些叢集正在回覆要求。以下章節將在兩個叢集分別設定 whereami 的部署作業:frontend
部署作業和 backend
部署作業。
frontend
部署作業是第一個收到要求的作業。接著呼叫 backend
部署作業。
這個模型用於示範多服務應用程式架構。
frontend
和 backend
服務都會部署到這兩個叢集。
如果多次執行 curl
指令,您會發現回應 (來自 frontend
和 backend
) 來自不同區域。在回應中,負載平衡器會提供地理位置路由。也就是說,負載平衡器會將用戶端的要求轉送至最近的叢集,但要求仍會隨機抵達。如果要求偶爾會從一個地區傳送到另一個地區,就會增加延遲時間和費用。
在下一節中,您會在服務網格中實作地區負載平衡,確保要求留在本地。
為 whereami 啟用並測試地區負載平衡
在本節中,您將在服務網格中實作區域性負載平衡,確保要求留在本機。您也會執行一些測試,瞭解 whereami 如何處理各種失敗情境。
當您向 whereami frontend
服務提出要求時,負載平衡器會將要求傳送至相對於用戶端延遲時間最短的叢集。也就是說,網格內的 Ingress 閘道 Pod 會以負載平衡的方式,將要求傳送至兩個叢集中的 whereami frontend
Pod。本節將在網格中啟用地區負載平衡,解決這個問題。
您現在擁有全域 HTTP(S) 負載平衡器,可做為服務網格代管多區域應用程式的前端。
清除所用資源
如要避免系統向您的 Google Cloud 帳戶收取本次部署所用資源的費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。
刪除專案
刪除個別資源
如要保留您在本部署作業中使用的 Google Cloud 專案,請刪除個別資源:
後續步驟
貢獻者
作者:
其他貢獻者: