פריסת שער פנימי מרובה אשכולות

במאמר הזה מוסבר באמצעות דוגמה מעשית איך לפרוס שער פנימי של כמה אשכולות כדי לנתב תעבורה בתוך רשת ה-VPC לאפליקציה שפועלת בשני אשכולות GKE שונים.

שערים מרובי אשכולות הם דרך יעילה לנהל את התעבורה של שירותים שנפרסו בכמה אשכולות GKE. באמצעות תשתית איזון העומסים הגלובלית של Google, אתם יכולים ליצור נקודת כניסה אחת לאפליקציות שלכם, וכך לפשט את הניהול ולשפר את המהימנות.

במדריך הזה משתמשים באפליקציית store לדוגמה כדי לדמות תרחיש מהעולם האמיתי שבו שירות קניות אונליין נמצא בבעלות ובהפעלה של צוותים נפרדים, ונפרס בצי של אשכולות GKE משותפים.

בדוגמה הזו מוסבר איך להגדיר ניתוב מבוסס-נתיב כדי להפנות תנועה לאשכולות שונים.

לפני שמתחילים

כדי לפרוס שערים מרובי-אשכולות, צריך לבצע הכנה מסוימת של הסביבה. לפני שממשיכים, פועלים לפי השלבים שמפורטים במאמר הכנת הסביבה לשימוש בשערי גישה מרובי-אשכולות:

  1. פריסה של אשכולות GKE.

  2. רושמים את האשכולות ב-Fleet (אם הם עדיין לא רשומים).

  3. מפעילים את בקרי השירות מרובי האשכולות והשער מרובה האשכולות.

לבסוף, מומלץ לעיין במגבלות ובבעיות הידועות של GKE Gateway Controller לפני שמשתמשים בבקר בסביבה שלכם.

פריסת שער פנימי מרובה אשכולות באזורים שונים

אתם יכולים לפרוס שערים מרובי-אשכולות שמספקים איזון עומסים פנימי בשכבה 7 באשכולות GKE בכמה אזורים. השערים האלה משתמשים ב-gke-l7-cross-regional-internal-managed-mc GatewayClass. ה-GatewayClass הזה מספק מאזן עומסים פנימי של אפליקציות (ALB) בין אזורים שמנוהל על ידי Google Cloud ומאפשר כתובות IP וירטואליות פנימיות שלקוחות ברשת ה-VPC יכולים לגשת אליהן. אפשר לחשוף את השערים האלה דרך ממשקי קצה באזורים שתבחרו, פשוט באמצעות השער כדי לבקש כתובות באזורים האלה. ה-VIP הפנימי יכול להיות כתובת IP אחת, או כתובות IP בכמה אזורים, עם כתובת IP אחת לכל אזור שמוגדר בשער. התעבורה מנותבת לאשכול ה-GKE העורפי הקרוב ביותר שפועל בצורה תקינה ויכול לטפל בבקשה.

דרישות מוקדמות

  1. מגדירים את הפרויקט ואת המעטפת על ידי הגדרת סביבת gcloud עם מזהה הפרויקט:

    export PROJECT_ID="YOUR_PROJECT_ID"
    gcloud config set project ${PROJECT_ID}
    
  2. יצירת אשכולות GKE באזורים שונים.

    בדוגמה הזו יש שני אשכולות, gke-west-1 ב-us-west1 ו-gke-east-1 ב-us-east1. מוודאים שממשק Gateway API מופעל (--gateway-api=standard) ושהאשכולות רשומים בצי.

    gcloud container clusters create gke-west-1 \
        --location=us-west1-a \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    
    gcloud container clusters create gke-east-1 \
        --location=us-east1-c \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    

    שינוי השם של ההקשרים כדי לגשת אליהם בקלות רבה יותר:

    gcloud container clusters get-credentials gke-west-1 \
      --location=us-west1-a \
      --project=${PROJECT_ID}
    
    gcloud container clusters get-credentials gke-east-1 \
      --location=us-east1-c \
      --project=${PROJECT_ID}
    kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1
    kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1
    
  3. הפעלת שירותים מרובי אשכולות (MCS) ותעבורת נתונים נכנסת (ingress) מרובת אשכולות (MCI/Gateway):

    gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID}
    
    # Set the config membership to one of your clusters (e.g., gke-west-1)
    # This cluster will be the source of truth for multi-cluster Gateway and Route resources.
    gcloud container fleet ingress enable \
        --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \
        --project=${PROJECT_ID}
    
  4. מגדירים רשתות משנה ל-proxy בלבד. נדרשת תת-רשת של שרת proxy בלבד בכל אזור שבו נמצאים אשכולות GKE ושבו יפעל מאזן העומסים. כדי להשתמש במאזני עומסים פנימיים של אפליקציות (ALB) בין אזורים, צריך להגדיר את הייעוד של תת-הרשת הזו ל-GLOBAL_MANAGED_PROXY.

    # Proxy-only subnet for us-west1
    gcloud compute networks subnets create us-west1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-west1 \
        --network=default \
        --range=10.129.0.0/23 # Choose an appropriate unused CIDR range
    
    # Proxy-only subnet for us-east1
    gcloud compute networks subnets create us-east1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-east1 \
        --network=default \
        --range=10.130.0.0/23 # Choose an appropriate unused CIDR range
    

    אם אתם לא משתמשים ברשת שמוגדרת כברירת מחדל, מחליפים את default בשם של רשת ה-VPC. מוודאים שטווחי ה-CIDR ייחודיים ולא חופפים.

  5. פורסים את אפליקציות ההדגמה, כמו store, בשני האשכולות. קובץ הדוגמה store.yaml מ-gke-networking-recipes יוצר מרחב שמות store ופריסה.

    kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    
  6. כדי לייצא שירותים מכל אשכול, צריך ליצור משאבי Kubernetes‏ Service ומשאבי ServiceExport בכל אשכול. כך השירותים יהיו זמינים לגילוי בכל צי המכונות. בדוגמה הבאה מיוצא שירות כללי store ושירותים ספציפיים לאזור (store-west-1, store-east-1) מכל אשכול, והכול במרחב השמות store.

    חל על gke-west1:

    cat << EOF | kubectl apply --context gke-west1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-west-1 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-west-1 # Exporting the region-specific service
      namespace: store
    EOF
    

    חל על gke-east1:

    cat << EOF | kubectl apply --context gke-east1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-east-1 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-east-1 # Exporting the region-specific service
      namespace: store
    EOF
    
  7. בודקים את ServiceImports: מוודאים שמשאבי ServiceImport נוצרים בכל אשכול במרחב השמות ServiceImport.store יכול להיות שיעברו כמה דקות עד שהם ייווצרו. bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n store צריכות להופיע הרשומות store, store-west-1 ו-store-east-1 (או רשומות רלוונטיות על סמך ההפצה).

הגדרת שער פנימי מרובה אזורים

הגדרה של Gateway משאב שמפנה אל gke-l7-cross-regional-internal-managed-mc GatewayClass. מחילים את המניפסט הזה על אשכול התצורה המיועד, כמו gke-west-1.

בשדה spec.addresses אפשר לבקש כתובות IP זמניות באזורים ספציפיים או להשתמש בכתובות IP סטטיות שהוקצו מראש.

  1. כדי להשתמש בכתובות IP זמניות, שומרים את קובץ המניפסט Gateway הבא בתור cross-regional-gateway.yaml:

    # cross-regional-gateway.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: internal-cross-region-gateway
      namespace: store # Namespace for the Gateway resource
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      # Addresses across regions. Address value is allowed to be empty or matching
      # the region name.
      - type: networking.gke.io/ephemeral-ipv4-address/us-west1
        value: "us-west1"
      - type: networking.gke.io/ephemeral-ipv4-address/us-east1
        value: "us-east1"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute # Only allow HTTPRoute to attach
    

    ברשימה הבאה מוגדרים חלק מהשדות בקובץ ה-YAML הקודם:

    • metadata.namespace: מרחב השמות שבו נוצר משאב ה-Gateway, לדוגמה, store.
    • spec.gatewayClassName: השם של GatewayClass. חייב להיות gke-l7-cross-regional-internal-managed-mc.
    • spec.listeners.allowedRoutes.kinds: סוגי אובייקטים של מסלולים שאפשר לצרף, לדוגמה, HTTPRoute.
    • spec.addresses:
      • type: networking.gke.io/ephemeral-ipv4-address/REGION: בקשה לכתובת IP זמנית.
      • value: מציין את האזור של הכתובת, לדוגמה, "us-west1" או "us-east1".
  2. מחילים את המניפסט על אשכול ההגדרות, לדוגמה, gke-west1:

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

צירוף של HTTPRoutes ל-Gateway

מגדירים משאבי HTTPRoute לניהול ניתוב התנועה ומחילים אותם על אשכול ההגדרות.

  1. שומרים את קובץ המניפסט HTTPRoute הבא בשם store-route.yaml:

    # store-route.yaml
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store-route
      namespace: store
      labels:
        gateway: cross-regional-internal
    spec:
      parentRefs:
      - name: internal-cross-region-gateway
        namespace: store # Namespace where the Gateway is deployed
      hostnames:
      - "store.example.internal" # Hostname clients will use
      rules:
      - matches: # Rule for traffic to /west
        - path:
            type: PathPrefix
            value: /west
        backendRefs:
        - group: net.gke.io # Indicates a multi-cluster ServiceImport
          kind: ServiceImport
          name: store-west-1 # Targets the ServiceImport for the west cluster
          port: 8080
      - matches: # Rule for traffic to /east
        - path:
            type: PathPrefix
            value: /east
        backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-east-1 # Targets the ServiceImport for the east cluster
          port: 8080
      - backendRefs: # Default rule for other paths (e.g., /)
        - group: net.gke.io
          kind: ServiceImport
          name: store # Targets the generic 'store' ServiceImport (any region)
          port: 8080
    

    ברשימה הבאה מוגדרים חלק מהשדות בקובץ ה-YAML הקודם:

    • spec.parentRefs: מצמיד את המסלול הזה ל-internal-cross-region-gateway במרחב השמות store.
    • spec.hostnames: מייצג את שם המארח שהלקוחות משתמשים בו כדי לגשת לשירות.
    • spec.rules: הגדרה של לוגיקת הניתוב. בדוגמה הזו נעשה שימוש בניתוב מבוסס-נתיב:
      • תנועת /west עוברת אל store-west-1 ServiceImport.
      • תנועת /east עוברת אל store-east-1 ServiceImport.
      • כל התנועה האחרת, כמו /, מועברת אל ServiceImport כללי.store
    • backendRefs:
      • group: net.gke.io ו-kind: ServiceImport שירותים מרובי אשכולות.
  2. מחילים את המניפסט HTTPRoute על אשכול ההגדרות:

    kubectl apply --context gke-west1 -f store-route.yaml
    

אימות הסטטוס של השער והמסלול

  1. בודקים את סטטוס השער:

    kubectl get gateway internal-cross-region-gateway -n store -o yaml --context gke-west1
    

    מחפשים תנאי עם הסטטוס type:Programmedand: True. You should see IP addresses assigned in thestatus.addressesfield, corresponding to the regions you specified (e.g., one forus-west1and one forus-east1`).

  2. בודקים את הסטטוס של HTTPRoute:

    kubectl get httproute store-route -n store -o yaml --context gke-west1
    

    מחפשים תנאי ב-status.parents[].conditions עם type: Accepted (או ResolvedRefs) ו-status: "True".

אישור התנועה

אחרי שמקצים את כתובות ה-IP לשער, אפשר לבדוק את התעבורה ממכונה וירטואלית של לקוח שנמצאת ברשת ה-VPC ובאחד מהאזורים, או באזור שאפשר להתחבר ממנו לכתובת ה-IP של השער.

  1. מאחזרים את כתובות ה-IP של השער.

    הפקודה הבאה מנסה לנתח את פלט ה-JSON. יכול להיות שתצטרכו לשנות את jsonpath בהתאם למבנה המדויק.

    kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".
    

    הפלט של הפקודה הזו צריך לכלול את כתובות ה-VIP, כמו VIP1_WEST, או VIP2_EAST.

  2. שליחת בקשות בדיקה: ממכונה וירטואלית של לקוח ב-VPC:

    # Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1
    # Traffic to /west should ideally be served by gke-west-1
    curl -H "host: store.example.internal" http://VIP_WEST/west
    curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path
    
    # Traffic to /east should ideally be served by gke-east-1
    curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path
    curl -H "host: store.example.internal" http://VIP_EAST/east
    
    # Traffic to / (default) could be served by either cluster
    curl -H "host: store.example.internal" http://VIP_WEST/
    curl -H "host: store.example.internal" http://VIP_EAST/
    

    התגובה צריכה לכלול פרטים מהאפליקציה store שמציינים איזה פוד בקצה העורפי הגיב לבקשה, כמו cluster_name או zone.

שימוש בכתובות IP סטטיות

במקום כתובות IP ארעיות, אפשר להשתמש בכתובות IP פנימיות סטטיות שהוקצו מראש.

  1. יוצרים כתובות IP סטטיות באזורים שבהם רוצים להשתמש:

    gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID}
    gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}
    

    אם אתם לא משתמשים ברשת המשנה שמוגדרת כברירת מחדל, מחליפים את default בשם של רשת המשנה שכוללת את כתובת ה-IP שרוצים להקצות. אלה רשתות משנה רגילות, לא רשתות משנה של שרת proxy בלבד.

  2. מעדכנים את קובץ המניפסט של שער התשלומים על ידי שינוי הקטע spec.addresses בקובץ cross-regional-gateway.yaml:

    # cross-regional-gateway-static-ip.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: internal-cross-region-gateway # Or a new name if deploying alongside
      namespace: store
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      - type: networking.gke.io/named-address-with-region # Use for named static IP
        value: "regions/us-west1/addresses/cross-region-gw-ip-west"
      - type: networking.gke.io/named-address-with-region
        value: "regions/us-east1/addresses/cross-region-gw-ip-east"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    
  3. החלת המניפסט המעודכן של שער.

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

שיקולים מיוחדים לגבי רשתות משנה שאינן ברירת המחדל

כשמשתמשים ברשתות משנה שאינן ברירת המחדל, חשוב לקחת בחשבון את הנקודות הבאות:

  • אותה רשת VPC: כל המשאבים שנוצרו על ידי המשתמשים – כמו כתובות IP סטטיות, רשתות משנה של פרוקסי בלבד ואשכולות GKE – חייבים להיות באותה רשת VPC.

  • רשת משנה של כתובות: כשיוצרים כתובות IP סטטיות לשער, הן מוקצות מרשתות משנה רגילות באזורים שצוינו.

  • שמות של רשתות משנה באשכול: לכל אזור צריכה להיות רשת משנה עם אותו שם כמו רשת המשנה שבה נמצא אשכול התצורה של MCG.

    • לדוגמה, אם אשכול ההגדרות gke-west-1 נמצא ב-projects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet, אז גם לאזורים שאתם מבקשים כתובות עבורם צריך להיות רשת משנה my-custom-subnet. אם מבקשים כתובות באזורים us-east1 ו-us-centra1, צריך שיהיה גם רשת משנה בשם my-custom-subnet באזורים האלה.

הסרת המשאבים

אחרי שתסיימו את התרגילים במסמך הזה, תצטרכו לפעול לפי השלבים הבאים כדי להסיר משאבים ולמנוע חיובים לא רצויים בחשבון:

  1. מחיקת האשכולות.

  2. ביטול הרישום של האשכולות ב-Fleet אם אין צורך לרשום אותם למטרה אחרת.

  3. השבתת התכונה multiclusterservicediscovery:

    gcloud container fleet multi-cluster-services disable
    
  4. השבתת Multi Cluster Ingress:

    gcloud container fleet ingress disable
    
  5. משביתים את ממשקי ה-API:

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

פתרון בעיות

לא קיימת תת-רשת לשרת proxy בלבד עבור שער פנימי

אם האירוע הבא מופיע בשער הפנימי, סימן שלא קיימת רשת משנה של פרוקסי בלבד באזור הזה. כדי לפתור את הבעיה, פורסים רשת משנה (subnet) של שרת proxy בלבד.

generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.

אין מקור תקין

התסמין:

יכולה להתרחש הבעיה הבאה כשיוצרים Gateway אבל אין גישה לשירותי ה-Backend (קוד תגובה 503):

no healthy upstream

הסיבה:

הודעת השגיאה הזו מציינת שכלי הבדיקה של בדיקת תקינות לא יכול למצוא שירותי קצה עורפיים תקינים. יכול להיות שהשירותים שלכם ב-Backend תקינים, אבל תצטרכו להתאים אישית את בדיקות התקינות.

פתרון עקיף:

כדי לפתור את הבעיה, מתאימים אישית את בדיקת התקינות בהתאם לדרישות של האפליקציה (לדוגמה, /health) באמצעות HealthCheckPolicy.

המאמרים הבאים