במאמר הזה מוסבר איך לבצע את הפעולות הבאות:
- פריסה של אפליקציות שמפוזרות גלובלית וחשופות דרך GKE Gateway ו-Cloud Service Mesh.
- אפשר לחשוף אפליקציה לכמה לקוחות על ידי שילוב של Cloud Load Balancing עם Cloud Service Mesh.
- שילוב מאזני עומסים עם Service mesh שנפרסה על פני Google Cloud מספר אזורים.
מדריך הפריסה הזה מיועד לאדמינים של פלטפורמות. הוא מיועד גם למשתמשים מתקדמים שמריצים את Cloud Service Mesh. ההוראות רלוונטיות גם ל-Istio ב-GKE.
ארכיטקטורה
בתרשים הבא מוצגת טופולוגיית הכניסה (ingress) שמוגדרת כברירת מחדל ב-service mesh – מאזן עומסים חיצוני של TCP/UDP שחושף את שרתי ה-proxy של שער הכניסה באשכול יחיד:
במדריך הפריסה הזה נעשה שימוש במשאבי Google Kubernetes Engine (GKE) Gateway. הוא משתמש בשער מרובה אשכולות כדי להגדיר איזון עומסים מרובה אזורים לפני כמה אשכולות של Autopilot שמפוזרים על פני שני אזורים.
בתרשים שלמעלה מוצג תרשים זרימת הנתונים בתרחישי כניסה לענן וכניסה לרשת. מידע נוסף מופיע בדיאגרמת ארכיטקטורה במסמך הארכיטקטורה הרלוונטי.
מטרות
- פריסת צמד אשכולות GKE Autopilot ב- Google Cloud באותו צי.
- פריסת Cloud Service Mesh מבוסס Istio לאותו צי.
- הגדרת מאזן עומסים באמצעות 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
כדי להעריך את ההוצאות בהתאם לתחזית השימוש שלכם, אתם יכולים להיעזר במחשבון העלויות.
כשמסיימים את המשימות שמתוארות במסמך הזה אפשר למחוק את המשאבים שיצרתם כדי להימנע מחיובים נוספים. מידע נוסף זמין בקטע הסרת המשאבים.
לפני שמתחילים
-
בדף לבחירת הפרויקט במסוף Google Cloud , בוחרים פרויקט ב- Google Cloud או יוצרים אותו.
תפקידים שנדרשים כדי לבחור או ליצור פרויקט
- Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (
roles/resourcemanager.projectCreator), שכולל את ההרשאהresourcemanager.projects.create. איך מקצים תפקידים
-
במסוף Google Cloud , מפעילים את Cloud Shell.
אתם מריצים את כל פקודות הטרמינל לפריסה הזו מ-Cloud Shell.
מגדירים את Google Cloud פרויקט ברירת המחדל:
export PROJECT=PROJECT_ID export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)") gcloud config set project PROJECT_IDמחליפים את
PROJECT_IDבמזהה הפרויקט שבו רוצים להשתמש לפריסה הזו.יוצרים ספריית עבודה:
mkdir -p ${HOME}/edge-to-mesh-multi-region cd ${HOME}/edge-to-mesh-multi-region export WORKDIR=`pwd`
יצירת אשכולות GKE
בקטע הזה יוצרים אשכולות GKE לאירוח האפליקציות והתשתית התומכת, שיוצרים בהמשך במדריך הפריסה הזה.
ב-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 APIs שבהם נעשה שימוש במדריך הזה:
gcloud services enable \ container.googleapis.com \ mesh.googleapis.com \ gkehub.googleapis.com \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ certificatemanager.googleapis.comיצירת אשכול GKE Autopilot עם צמתים פרטיים ב-
CLUSTER_1_REGION. כדי להימנע מהמתנה עד שהאשכול הראשון יוקצה וירשם ל-Fleet, משתמשים בדגל--async:gcloud container clusters create-auto --async \ ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} \ --release-channel rapid \ --enable-private-nodes --enable-fleetיוצרים ורושמים אשכול Autopilot שני ב-
CLUSTER_2_REGION:gcloud container clusters create-auto \ ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} \ --release-channel rapid \ --enable-private-nodes --enable-fleetמוודאים שהאשכולות פועלים. יכול להיות שיחלפו עד 20 דקות עד שכל האשכולות יפעלו:
gcloud container clusters listהפלט אמור להיראות כך:
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS STACK_TYPE edge-to-mesh-01 us-central1 1.35.5-gke.1000000 34.31.166.104 ek-standard-8 1.35.5-gke.1000000 1 RUNNING IPV4 edge-to-mesh-02 us-east4 1.35.5-gke.1000000 35.245.233.88 ek-standard-8 1.35.5-gke.1000000 1 RUNNING IPV4
אוספים את פרטי הכניסה של
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}
התקנת Service mesh
בקטע הזה מוסבר איך להגדיר את Cloud Service Mesh מנוהל עם Fleet API. השימוש ב-Fleet API כדי להפעיל את Cloud Service Mesh מספק גישה הצהרתית להקצאת רשת שירותים.
ב-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: '2026-06-04T23:40:02.666228685Z' membershipSpecs: projects/497535075790/locations/us-central1/memberships/edge-to-mesh-01: mesh: management: MANAGEMENT_AUTOMATIC projects/497535075790/locations/us-east4/memberships/edge-to-mesh-02: mesh: management: MANAGEMENT_AUTOMATIC membershipStates: projects/497535075790/locations/us-central1/memberships/edge-to-mesh-01: servicemesh: conditions: - code: VPCSC_GA_SUPPORTED details: This control plane supports VPC-SC GA. documentationLink: http://cloud.google.com/service-mesh/docs/managed/vpc-sc severity: INFO controlPlaneManagement: details: - code: REVISION_READY details: 'Ready: asm-managed-rapid' implementation: TRAFFIC_DIRECTOR state: ACTIVE dataPlaneManagement: details: - code: OK details: Service is running. state: ACTIVE state: code: OK description: 'Revision ready for use: asm-managed-rapid.' updateTime: '2026-06-04T23:45:52.958139396Z' projects/497535075790/locations/us-east4/memberships/edge-to-mesh-02: servicemesh: conditions: - code: VPCSC_GA_SUPPORTED details: This control plane supports VPC-SC GA. documentationLink: http://cloud.google.com/service-mesh/docs/managed/vpc-sc severity: INFO controlPlaneManagement: details: - code: REVISION_READY details: 'Ready: asm-managed-rapid' implementation: TRAFFIC_DIRECTOR state: ACTIVE dataPlaneManagement: details: - code: OK details: Service is running. state: ACTIVE state: code: OK description: 'Revision ready for use: asm-managed-rapid.' updateTime: '2026-06-04T23:45:54.621862416Z' name: projects/e2m-mc-h2c/locations/global/features/servicemesh resourceState: state: ACTIVE spec: {} updateTime: '2026-06-04T23:40:55.123874541Z'
פריסה של מאזן עומסים חיצוני של אפליקציות (ALB) ויצירה של שערי תעבורת נתונים נכנסת (ingress)
בקטע הזה פורסים מאזן עומסים של אפליקציות (ALB) חיצוני באמצעות GKE Gateway Controller ויוצרים שערי כניסת תנועה לשני האשכולות. המשאבים gateway ו-gatewayClass מבצעים אוטומציה של הקצאת מאזן העומסים ובדיקת התקינות של ה-backend. כדי לספק סיום TLS במאזן העומסים, יוצרים משאבים של Certificate Manager ומצרפים אותם למאזן העומסים. בנוסף, אפשר להשתמש בנקודות קצה כדי להקצות באופן אוטומטי שם DNS ציבורי לאפליקציה.
התקנת שער כניסה בשני האשכולות
השיטה המומלצת לאבטחה היא לפרוס את שער הכניסה במרחב שמות שונה מזה של רמת הבקרה של הרשת.
ב-Cloud Shell, יוצרים מרחב שמות ייעודי
ingress-gatewayבכל אשכול:kubectl --context=${CLUSTER_1_NAME} create namespace ingress-gateway kubectl --context=${CLUSTER_2_NAME} create namespace ingress-gatewayמוסיפים תווית של מרחב שמות למרחבי השמות
ingress-gateway:kubectl --context=${CLUSTER_1_NAME} label namespace ingress-gateway istio-injection=enabled kubectl --context=${CLUSTER_2_NAME} label namespace ingress-gateway istio-injection=enabledהפלט אמור להיראות כך:
namespace/ingress-gateway labeled
הוספת התווית
ingress-gatewayלמרחבי השמותistio-injection=enabledמורה ל-Cloud Service Mesh להוסיף אוטומטית פרוקסי Envoy sidecar כשפורסים פוד.יצירת אישור בחתימה עצמית לשימוש עתידי:
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האישור מספק שכבת הצפנה נוספת בין מאזן העומסים לבין שערי Service mesh. היא גם מאפשרת תמיכה בפרוטוקולים מבוססי HTTP/2 כמו gRPC. הוראות להוספת האישור בחתימה עצמית לשערי הכניסה מופיעות בהמשך המאמר יצירת משאבים של כתובת IP חיצונית, רשומת DNS ואישור TLS.
אם רוצים להשתמש ב-HTTP/2 לחיבור בין GFE ל-mesh אבל לא צריך הצפנה משלכם, אפשר להשתמש ב-H2C.
למידע נוסף על הדרישות של אישור שער הכניסה, אפשר לעיין במאמר בנושא הצפנה ממאזן העומסים אל השרתים העורפיים.
יוצרים סוד של Kubernetes בכל אשכול כדי לאחסן את האישור בחתימה עצמית:
kubectl --context ${CLUSTER_1_NAME} -n ingress-gateway 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 ingress-gateway create secret tls \ edge2mesh-credential \ --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \ --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crtכדי לבצע שילוב עם מאזן עומסים חיצוני של אפליקציות (ALB), צריך ליצור וריאציה של kustomize כדי להגדיר את משאבי שער הכניסה:
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: ingress-gateway 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: ingress-gateway 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: ingress-gateway 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: ingress-gateway 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: ingress-gateway resources: - ../base - role.yaml - rolebinding.yaml patches: - path: service-proto-type.yaml target: kind: Service - path: gateway.yaml target: kind: Gateway EOFמחילים את ההגדרה של שער הכניסה על שני האשכולות:
kubectl --context ${CLUSTER_1_NAME} apply -k ${WORKDIR}/asm-ig/variant kubectl --context ${CLUSTER_2_NAME} apply -k ${WORKDIR}/asm-ig/variant
חשיפת פודים של שער תעבורת נתונים נכנסת (ingress) למאזן העומסים באמצעות שירות מרובה אשכולות
בקטע הזה מייצאים את ה-pods של שער הכניסה באמצעות ServiceExport
משאב בהתאמה אישית. צריך לייצא את הפודים של שער הכניסה באמצעות משאב מותאם אישית ServiceExport מהסיבות הבאות:
- מאפשר למאזן העומסים לפנות אל ה-pods של שער הכניסה בכמה אשכולות.
- מאפשר ל-Pods של שער הכניסה להעביר בקשות לשרתים שפועלים בתוך Service mesh.
ב-Cloud Shell, מפעילים את התכונה 'שירותים מרובי אשכולות' (MCS) ב-Fleet:
gcloud container fleet multi-cluster-services enableמעניקים ל-MCS את הרשאות ה-IAM הנדרשות לפרויקט או ל-Fleet:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \ --role "roles/compute.networkViewer"יוצרים את קובץ ה-YAML
ServiceExport:cat <<EOF > ${WORKDIR}/svc_export.yaml kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: asm-ingressgateway namespace: ingress-gateway EOFמחילים את קובץ ה-
ServiceExportYAML על שני האשכולות:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/svc_export.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/svc_export.yamlאם מופיעה הודעת השגיאה הבאה, צריך להמתין כמה רגעים עד להתקנה של הגדרות משאבים מותאמים אישית (CRD) של MCS. לאחר מכן מריצים מחדש את הפקודות כדי להחיל את קובץ ה-YAML
ServiceExportעל שני האשכולות.error: resource mapping not found for name: "asm-ingressgateway" namespace: "ingress-gateway" from "svc_export.yaml": no matches for kind "ServiceExport" in version "net.gke.io/v1" ensure CRDs are installed first
יצירת משאבים של כתובת IP חיצונית, רשומת DNS ואישור TLS
בקטע הזה יוצרים משאבי רשת שתומכים במשאבי איזון העומסים שיוצרים בהמשך הפריסה הזו.
ב-Cloud Shell, שומרים כתובת IP חיצונית סטטית:
gcloud compute addresses create mcg-ip --globalכתובת IP סטטית משמשת את משאב GKE Gateway. היא מאפשרת לכתובת ה-IP להישאר זהה, גם אם מאזן העומסים החיצוני נוצר מחדש.
מקבלים את כתובת ה-IP הסטטית ומאחסנים אותה כמשתנה סביבה:
export MCG_IP=$(gcloud compute addresses describe mcg-ip --global --format "value(address)") echo ${MCG_IP}כדי ליצור מיפוי יציב וידידותי למשתמש לכתובת ה-IP של השער, צריך רשומת DNS ציבורית.
אתם יכולים להשתמש בכל ספק DNS ובכל תוכנית אוטומציה שתרצו. הפריסה הזו משתמשת ב-Endpoints במקום ליצור אזור DNS מנוהל. Endpoints מספקת רשומת DNS בניהול Google בחינם לכתובת IP חיצונית.
מריצים את הפקודה הבאה כדי ליצור קובץ YAML בשם
dns-spec.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מגדיר את רשומת ה-DNS הציבורית בפורמטfrontend.endpoints.PROJECT_ID.cloud.goog, כאשרPROJECT_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"אישור TLS בניהול Google משמש לסיום בקשות נכנסות של לקוחות במאזן העומסים.
יוצרים מיפוי אישורים:
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 עם כללים.
- יוצרים מדיניות שמאפשרת למאזן העומסים לבדוק את זמן התגובה של הפודים של שער הכניסה דרך קובץ ה-YAML
ServiceExportשיצרתם קודם. - משתמשים ב-GKE Gateway API כדי ליצור משאב של מאזן עומסים.
- משתמשים במשאב המותאם אישית
GatewayClassכדי להגדיר את הסוג הספציפי של איזון העומסים. - מפעילים איזון עומסים מרובה אשכולות עבור Fleet, ומגדירים אחד מהאשכולות כאשכול ההגדרות של Fleet.
ב-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 למדיניות האבטחה ומפנים לקובץ
ServiceExportYAML באמצעות קובץServiceImportYAML תואם:cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml apiVersion: networking.gke.io/v1 kind: GCPBackendPolicy metadata: name: cloud-armor-backendpolicy namespace: ingress-gateway 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 בהתאמה אישית שמאפשר למאזן העומסים לבצע בדיקות תקינות מול נקודת הקצה של Envoy לבדיקת תקינות (יציאה
15021בנתיב/healthz/ready) של הפודים של שער הכניסה בשני האשכולות:cat <<EOF > ${WORKDIR}/ingress-gateway-healthcheck.yaml apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: ingress-gateway-healthcheck namespace: ingress-gateway 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מפעילים איזון עומסים מרובה אשכולות עבור ה-Fleet, ומגדירים את
CLUSTER_1_NAMEכאשכול ההגדרות:gcloud container fleet ingress enable \ --config-membership=${CLUSTER_1_NAME} \ --location=${CLUSTER_1_REGION}מעניקים הרשאות IAM לבקר של שער הכניסה ב-Fleet:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \ --role "roles/container.admin"יוצרים את קובץ ה-YAML של איזון העומסים באמצעות משאב בהתאמה אישית מסוג Gateway שמפנה אל
gke-l7-global-external-managed-mcgatewayClassואל כתובת ה-IP הסטטית שיצרתם קודם:cat <<EOF > ${WORKDIR}/frontend-gateway.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http namespace: ingress-gateway 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מחילים את קובץ ה-YAML
frontend-gatewayעל שני האשכולות. רק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יוצרים קובץ YAML
HTTPRouteבשםdefault-httproute.yamlשמורה למשאב Gateway לשלוח בקשות לשערי הכניסה:cat << EOF > ${WORKDIR}/default-httproute.yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: default-httproute namespace: ingress-gateway spec: parentRefs: - name: external-http namespace: ingress-gateway sectionName: https rules: - backendRefs: - group: net.gke.io kind: ServiceImport name: asm-ingressgateway port: 443 EOFמחילים את קובץ ה-YAML
HTTPRouteשיצרתם בשלב הקודם על שני האשכולות: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), יוצרים קובץ YAML נוסף בשם
default-httproute-redirect.yaml:HTTPRoutecat << EOF > ${WORKDIR}/default-httproute-redirect.yaml kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: http-to-https-redirect-httproute namespace: ingress-gateway spec: parentRefs: - name: external-http namespace: ingress-gateway sectionName: http rules: - filters: - type: RequestRedirect requestRedirect: scheme: https statusCode: 301 EOFמחילים את קובץ ה-YAML של ההפניה האוטומטית על שני האשכולות:
HTTPRoutekubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yamlבודקים את משאב השער כדי לראות את התקדמות הפריסה של מאזן העומסים:
kubectl --context=${CLUSTER_1_NAME} describe gateway external-http -n ingress-gatewayבפלט מוצג המידע שהזנתם בקטע הזה.
פריסת האפליקציה לדוגמה whereami
במדריך הזה נעשה שימוש באפליקציה לדוגמה whereami כדי לספק משוב ישיר לגבי אילו אשכולות משיבים לבקשות. בקטע הבא מוגדרות שתי פריסות נפרדות של whereami בשני האשכולות: פריסת frontend ופריסת backend.
הפריסה של frontend היא עומס העבודה הראשון שמקבל את הבקשה. לאחר מכן, המערכת קוראת לפריסה backend.
המודל הזה משמש להדגמה של ארכיטקטורת אפליקציה מרובת שירותים.
השירותים frontend ו-backend נפרסים בשני האשכולות.
ב-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יוצרים וריאציה של kustomize עבור whereami
backend: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 labels: - includeSelectors: true includeTemplates: true pairs: 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יוצרים וריאציה של kustomize עבור whereami
frontend: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 labels: - includeSelectors: true includeTemplates: true pairs: 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יוצרים קובץ YAML
VirtualServiceכדי להפנות בקשות אלfrontend:cat << EOF > ${WORKDIR}/frontend-vs.yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: whereami-vs namespace: frontend spec: gateways: - ingress-gateway/asm-ingressgateway hosts: - 'frontend.endpoints.PROJECT_ID.cloud.goog' http: - route: - destination: host: whereami-frontend port: number: 80 EOFמחילים את קובץ ה-
frontend-vsYAML על שני האשכולות: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" }
אם מריצים את הפקודה curl כמה פעמים, אפשר לראות שהתשובות (גם מ-frontend וגם מ-backend) מגיעות מאזורים שונים. בתגובה שלו, מאזן העומסים מספק ניתוב גיאוגרפי. כלומר, מאזן העומסים מנתב בקשות מהלקוח לאשכול הפעיל הקרוב ביותר, אבל הבקשות עדיין מגיעות באופן אקראי. כשבקשות עוברות מדי פעם מאזור אחד לאזור אחר, זה מגדיל את זמן האחזור ואת העלות.
בקטע הבא, מטמיעים איזון עומסים מקומי ב-Service mesh כדי שהבקשות יישארו מקומיות.
הפעלה ובדיקה של איזון עומסים לפי אזור עבור whereami
בקטע הזה, מטמיעים איזון עומסים מקומי ב-Service mesh כדי שהבקשות יישארו מקומיות. אתם גם מבצעים כמה בדיקות כדי לראות איך הכלי whereami מתמודד עם תרחישי כשל שונים.
כששולחים בקשה לשירות whereami frontend, מאזן העומסים שולח את הבקשה לאשכול עם זמן האחזור הכי נמוך ביחס ללקוח. כלומר, תרמילי שער הכניסה ברשת מאזנים את עומס הבקשות לתרמילי whereami frontend בשני האשכולות. בקטע הזה נסביר איך לפתור את הבעיה הזו באמצעות הפעלה של איזון עומסים מקומי ברשת.
ב-Cloud Shell, יוצרים קובץ YAML
DestinationRuleשמאפשר מעבר אזורי לגיבוי (failover) של איזון עומסים לפי מיקום לשירותfrontend: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-drYAML על שני האשכולות:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-dr.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-dr.yamlיוצרים קובץ
DestinationRuleYAML שמפעיל מעבר ליתירות כשל אזורית של איזון עומסים לפי מיקום בשירות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-drYAML על שני האשכולות:kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/backend-dr.yaml kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/backend-dr.yamlאם שני סטים של קובצי YAML
DestinationRuleמוחלים על שני האשכולות, הבקשות נשארות מקומיות לאשכול שאליו הבקשה מנותבת.כדי לבדוק את המעבר לגיבוי במקרה של כשל בשירות
frontend, מצמצמים את מספר הרפליקות של שער הכניסה באשכול הראשי.מנקודת המבט של מאזן העומסים שמנוהל במספר אזורים, הפעולה הזו מדמה כשל באשכול. היא גורמת לכך שהאשכול ייכשל בבדיקות התקינות של מאזן העומסים. בדוגמה הזו נעשה שימוש באשכול ב-
CLUSTER_1_REGION. ב-CLUSTER_2_REGIONאמורות להופיע רק תשובות מהאשכול.מצמצמים את מספר הרפליקות של שער הכניסה באשכול הראשי לאפס, ומתקשרים לנקודת הקצה הציבורית כדי לוודא שהבקשות עברו לאשכול השני:
kubectl --context=${CLUSTER_1_NAME} -n ingress-gateway 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" }כדי לחזור לניתוב תנועה רגיל, משחזרים את העותקים המשוכפלים של שער הכניסה לערך המקורי באשכול:
kubectl --context=${CLUSTER_1_NAME} -n ingress-gateway scale --replicas=3 deployment/asm-ingressgatewayמדמים כשל בשירות
backendעל ידי הקטנת מספר העותקים באזור הראשי ל-0:kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=0 deployment/whereami-backendמוודאים שהתשובות משירות
frontendמגיעות מהאזור הראשיus-central1דרך מאזן העומסים, והתשובות משירותbackendמגיעות מהאזור המשניus-east4.הפלט צריך לכלול גם תשובה לשירות
frontendמהאזור הראשי (us-central1), ותשובה לשירותbackendמהאזור המשני (us-east4), כצפוי.כדי לחזור לניתוב התנועה הרגיל, צריך לשחזר את העותקים של שירות הקצה העורפי לערך המקורי:
kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=3 deployment/whereami-backend
עכשיו יש לכם מאזן עומסים גלובלי של HTTP(S) שמשמש קצה קדמי לאפליקציה שלכם שמתארחת ב-Service Mesh במספר אזורים.
הסרת המשאבים
כדי להימנע מחיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם בפריסה הזו, אתם יכולים למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים הספציפיים.
מחיקת הפרויקט
- במסוף Google Cloud , נכנסים לדף Manage resources.
- ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
- כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.
מחיקת המשאבים הבודדים
אם רוצים לשמור את Google Cloud הפרויקט שבו השתמשתם בפריסה הזו, צריך למחוק את המשאבים הבודדים:
ב-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מוחקים את רשומת ה-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 Gateway שאפשר להשתמש בהן עם Service mesh
- מידע על הסוגים השונים של Cloud Load Balancing שזמינים ל-GKE
- מידע על התכונות והפונקציות שמציע Cloud Service Mesh
- לדוגמאות נוספות של ארכיטקטורות, תרשימים ושיטות מומלצות, עיינו במאמר Cloud Architecture Center.
שותפים ביצירת התוכן
מחברים:
- אלכס מטסון | מהנדס מומחה לאפליקציות
- Mark Chilvers | מהנדס מומחה לאפליקציות
תורמי תוכן אחרים:
- Abdelfettah Sghiouar | Cloud Developer Advocate
- Greg Bray | Customer Engineer
- Paul Revello | Cloud Solutions Architect
- Valavan Rajakumar | Key Enterprise Architect