שינוי גודל של עומסי עבודה ב-GKE לאפס ומאפס באמצעות HPA

במדריך הזה נסביר איך לבצע אופטימיזציה של ניצול המשאבים ב-Google Kubernetes Engine ‏(GKE) על ידי הגדרת עומסי עבודה (workload) כך שיתבצע שינוי אוטומטי של מספר הרפליקות לאפס כשהמערכת לא פעילה, ושינוי חזרה למספר הרפליקות המקורי כשהביקוש גדל. הגישה הזו משלבת את התאמה אופקית של קבוצות Pod לעומס (HPA) עם תשתית מנוהלת של התאמת גודל ב-GKE, כדי לנהל את שינוי הגודל על סמך מדדים חיצוניים.

מגדירים את הפריסה כך שתצטמצם לאפס על ידי הגדרת הערך של השדה minReplicas ל-0 והגדרת מדד עם הסוג External או Object במניפסט של HPA. ‫GKE עוקב אחרי המדדים האלה באמצעות המשאב המותאם אישית AutoscalingMetric, כדי לוודא שהמשאבים של האפליקציות מנוהלים בצורה יעילה.

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

במדריך הזה תפרסו אפליקציית worker אסינכרונית לדוגמה שמבצעת עיבוד של הודעות מתור Pub/Sub. מגדירים את הכלי Horizontal Pod Autoscaler (HPA) כדי לעקוב אחרי עומק התור (pubsub.googleapis.com:num_undelivered_messages) באמצעות משאב מותאם אישית AutoscalingMetric:

  • כשהודעות מגיעות למינוי:‏ GKE מגדיל את מספר ה-Pods של העובדים כדי לעבד את התור.
  • כשהתור ריק: מערכת GKE מצמצמת אוטומטית את פריסת העובדים לאפס רפליקות.

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

לתשומת ליבכם

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

  • כדי לשנות את קנה המידה של עומסי עבודה לאפס ומאפס באמצעות HPA, רמת הבקרה והצמתים של אשכול GKE צריכים להריץ גרסה 1.37 ואילך באשכולות חדשים ובאשכולות קיימים ששודרגו. אם משתמשים באשכול קיים, צריך לוודא שהגרסה שלו היא 1.37 או גרסה חדשה יותר, או לשדרג את האשכול או את הצמתים שלו לגרסה 1.37 או לגרסה חדשה יותר.
  • במניפסט של HPA צריך להשתמש בהגדרה apiVersion: autoscaling/v2 כדי לתמוך בהגדרה minReplicas: 0 ובמדדים חיצוניים.
  • לפני שדרוג לאחור של מאגרי צמתים לגרסה מוקדמת יותר מ-1.37, צריך לעדכן את כל מניפסטים של HPA שהוגדרו להגדלה מאפס ולהקטנה לאפס על ידי הגדרת השדה minReplicas לערך 1 או לערך גבוה יותר. גרסאות קודמות ל-1.37 לא תומכות בהגדרה minReplicas: 0, ולכן יכול להיות שעומסי עבודה יישארו תקועים עם אפס רפליקות.
  • צריך להגדיר לפחות מדד אחד של External או Object (כמו עומק התור) במנגנון האוטומטי לשינוי גודל של ה-Pod האופקי. ‫GKE לא יכול לאסוף מדדים של CPU או זיכרון (Resource) כשעומס עבודה כולל אפס Pods, ולכן מדדי משאבים בלבד לא יכולים להפעיל הגדלה מאפס.
  • האובייקטים AutoscalingMetric,‏ HorizontalPodAutoscaler ופריסת היעד חייבים להיות באותו מרחב שמות של Kubernetes.

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

  1. נכנסים לחשבון Google Cloud . אם אתם משתמשים חדשים ב- Google Cloud, צרו חשבון כדי שתוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
  2. התקינו את ה-CLI של Google Cloud.

  3. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  4. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  5. יוצרים או בוחרים Google Cloud פרויקט.

    תפקידים שנדרשים כדי לבחור או ליצור פרויקט

    • Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים
    • יוצרים Google Cloud פרויקט:

      gcloud projects create PROJECT_ID

      מחליפים את PROJECT_ID בשם של פרויקט Google Cloud שיוצרים.

    • בוחרים את הפרויקט שיצרתם: Google Cloud

      gcloud config set project PROJECT_ID

      מחליפים את PROJECT_ID בשם הפרויקט ב- Google Cloud .

  6. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

  7. מפעילים את ממשקי ה-API של GKE ו-Pub/Sub:

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, נדרשת ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד 'בעלים' (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין בממשק Service Usage' (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

    gcloud services enable container.googleapis.com pubsub.googleapis.com
  8. התקינו את ה-CLI של Google Cloud.

  9. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  10. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  11. יוצרים או בוחרים Google Cloud פרויקט.

    תפקידים שנדרשים כדי לבחור או ליצור פרויקט

    • Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
    • יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (יצירת פרויקטים) (roles/resourcemanager.projectCreator), שכולל את ההרשאה resourcemanager.projects.create. איך מקצים תפקידים
    • יוצרים Google Cloud פרויקט:

      gcloud projects create PROJECT_ID

      מחליפים את PROJECT_ID בשם של פרויקט Google Cloud שיוצרים.

    • בוחרים את הפרויקט שיצרתם: Google Cloud

      gcloud config set project PROJECT_ID

      מחליפים את PROJECT_ID בשם הפרויקט ב- Google Cloud .

  12. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

  13. מפעילים את ממשקי ה-API של GKE ו-Pub/Sub:

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, נדרשת ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד 'בעלים' (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין בממשק Service Usage' (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

    gcloud services enable container.googleapis.com pubsub.googleapis.com

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות להשלמת המדריך הזה, צריך לבקש מהאדמין להקצות לכם בפרויקט את תפקידי ה-IAM הבאים:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

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

מגדירים את הסביבה

כדי לפשט את התהליך, הפקודות במדריך הזה יוצרות את כל המשאבים (אשכול GKE, נושא Pub/Sub והמינוי) ב Google Cloud פרויקט אחד (PROJECT_ID).

כדי להגדיר את הסביבה, מבצעים את השלבים הבאים:

  1. הגדרת משתני סביבה:

    export PROJECT_ID=PROJECT_ID
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
    export LOCATION=LOCATION
    

    מחליפים את מה שכתוב בשדות הבאים:

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

    טייס אוטומטי

    יצירת אשכול Autopilot:

    gcloud container clusters create-auto scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    

    איחוד זהויות של עומסי עבודה ל-GKE מופעל כברירת מחדל באשכולות Autopilot.

    רגילה

    יוצרים אשכול Standard עם איחוד זהויות של עומסי עבודה ל-GKE:

    gcloud container clusters create scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION} \
        --workload-pool=${PROJECT_ID}.svc.id.goog
    
  3. מגדירים את kubectl כדי לתקשר עם האשכול:

    gcloud container clusters get-credentials scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    

יצירת משאבי Pub/Sub

במדריך הזה נעשה שימוש בעומק התור של Pub/Sub כדוגמה למקור חיצוני של מדדים.

כדי ליצור נושא ומינוי ב-Pub/Sub:

  1. יוצרים נושא Pub/Sub:

    gcloud pubsub topics create my-worker-topic \
        --project=${PROJECT_ID}
    
  2. יוצרים מינוי שמצורף לנושא:

    gcloud pubsub subscriptions create my-worker-subscription \
        --topic=my-worker-topic \
        --project=${PROJECT_ID}
    

הגדרת איחוד זהויות של עומסי עבודה ל-GKE

מגדירים איחוד זהויות של עומסי עבודה ל-GKE כדי לאפשר לאפליקציית העובד לבצע אימות באמצעות ממשקי API של Google Cloud ולצרוך הודעות מ-Pub/Sub.

‫GKE מטפל אוטומטית באימות באמצעות Cloud Monitoring עבור משאבי AutoscalingMetric באותו פרויקט. למידע נוסף על הגדרת מדדים לצורך שינוי גודל אוטומטי, אפשר לעיין במאמר בנושא אחזור מדדים מותאמים אישית או חיצוניים מ-Cloud Monitoring.

כדי להגדיר איחוד זהויות של עומסי עבודה ל-GKE עבור עומס העבודה של העובד, מבצעים את השלבים הבאים:

  1. יוצרים חשבון שירות של Kubernetes לאפליקציית העובד במרחב השמות default:

    kubectl create serviceaccount async-worker-sa \
        --namespace default
    
  2. מקצים את התפקיד roles/pubsub.subscriber לחשבון השירות של Kubernetes כדי שהאפליקציה תוכל לקבל הודעות מהמינוי שלכם ל-Pub/Sub:

    gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
        --role=roles/pubsub.subscriber \
        --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/default/sa/async-worker-sa
    

מידע נוסף זמין במאמר הגדרת אפליקציות לשימוש באיחוד שירותי אימות הזהות של עומסי עבודה ב-GKE.

יצירת פריסה לדוגמה

לפני שיוצרים אובייקט HPA, צריך ליצור את עומס העבודה שהוא יעקוב אחריו.

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

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

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: async-worker
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: async-worker
      template:
        metadata:
          labels:
            app: async-worker
        spec:
          containers:
          - name: async-worker
            image: nginx:latest
            ports:
            - containerPort: 80
            resources:
              limits:
                memory: 100Mi
              requests:
                cpu: 50m
                memory: 100Mi
    
  2. מחילים את הפריסה async-worker.yaml:

    kubectl apply -f async-worker.yaml
    

הגדרת עומס עבודה להרחבה לאפס ומאפס

בקטע הזה מגדירים את async-worker הפריסה כך שהיא תצטמצם לאפס כשהתור של Pub/Sub ריק, ותתרחב מחדש כשיגיעו הודעות חדשות.

יצירת משאב AutoscalingMetric

כדי להגדיר את האות החיצוני שמנוטר על ידי GKE, יוצרים את המשאב המותאם אישית AutoscalingMetric. במניפסט של הדוגמה הבאה, המדד שולח שאילתה ל-Cloud Monitoring כדי לקבל את מספר ההודעות ב-Pub/Sub שלא נמסרו במינוי my-worker-subscription.

כדי ליצור את משאב AutoscalingMetric:

  1. שומרים את המניפסט הבא כקובץ pubsub-metric.yaml:

    apiVersion: autoscaling.gke.io/v1beta1
    kind: AutoscalingMetric
    metadata:
      name: pubsub-queue-depth
      namespace: default
    spec:
      metrics:
      - promql:
          name: pubsub-undelivered
          query: >
              {
                "pubsub.googleapis.com/subscription/num_undelivered_messages",
                subscription_id="my-worker-subscription"
              }
    
  2. החלת המניפסט pubsub-metric.yaml:

    kubectl apply -f pubsub-metric.yaml
    
  3. בודקים את סטטוס המדד ומאחזרים את מזהה המדד:

    kubectl describe autoscalingmetric pubsub-queue-depth
    

    בקטע Status של הפלט, מוודאים שלא מופיעות שגיאות ורושמים את הערך Hpa Name שמופיע בפורמט autoscaling.gke.io|CUSTOM_RESOURCE_NAME|METRIC_NAME. תצטרכו להשתמש במזהה הזה של המדד החיצוני כשתיצרו את אובייקט HorizontalPodAutoscaler בקטע הבא. אם בקטע Status מדווח על שגיאות בהגדרות או שהמדדים לא מאוחזרים כמו שציפיתם, כדאי לעיין במאמר פתרון בעיות שקשורות למדדים שמאוחזרים לצורך שינוי גודל אוטומטי.

הגדרת Horizontal Pod Autoscaler

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

כדי להגדיר את הכלי האוטומטי לשינוי גודל של Pod אופקי:

  1. שומרים את המניפסט הבא כקובץ worker-hpa.yaml:

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: async-worker-hpa
      namespace: default
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: async-worker
      minReplicas: 0
      maxReplicas: 20
      metrics:
      - type: External
        external:
          metric:
            name: autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered
          target:
            type: AverageValue
            averageValue: "10"
    

    קובץ המניפסט הזה מגדיר את שדות המפתח הבאים:

    • minReplicas: 0: מאפשר צמצום הפעולה לאפס על ידי מתן אפשרות לבקר לצמצם את הפריסה ל-0 רפליקות כשהביקוש יורד לאפס.
    • type: External: מגדיר מקור חיצוני של מדדים כדי שה-HPA יוכל להפעיל הגדלה כשאין אף Pod בעומס העבודה.
    • name: autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered: ממפה את ה-HPA ישירות למשאב AutoscalingMetric שנוצר בשלב הקודם באמצעות פורמט המזהה autoscaling.gke.io|CUSTOM_RESOURCE_NAME|METRIC_NAME.
  2. החלת המניפסט worker-hpa.yaml:

    kubectl apply -f worker-hpa.yaml
    

אימות ההתנהגות והתנאים של קמפיינים ללא הגדרת משקל

כשכל ההודעות במינוי Pub/Sub מעובדות, ה-Horizontal Pod Autoscaler (HPA) מעריך את הביקוש לאפס ומקטין את הפריסה ל-0 רפליקות.

כדי לוודא שה-HPA הפעיל את מצב האפס, בודקים את תנאי הסטטוס של async-worker-hpa המשאב על ידי הרצת הפקודה הבאה:

kubectl describe hpa async-worker-hpa

הפלט אמור להיראות כך:

Name:             async-worker-hpa
Namespace:        default
Reference:        Deployment/async-worker
Metrics:          ( current / target )
  "autoscaling.gke.io|pubsub-queue-depth|pubsub-undelivered" (external metric):  0 / 10
Min replicas:     0
Max replicas:     20
Deployment pods:  0 current / 0 desired
Conditions:
  Type            Status  Reason               Message
  ----            ------  ------               -------
  AbleToScale     True    SucceededGetScale    the HPA controller was able to get the target's current scale
  ScalingActive   True    ValidMetricFound     the HPA was able to successfully calculate a replica count from external metric
  ScaledToZero    True    ScaledToZero         the HPA has scaled the target resource to 0 replicas due to zero metric demand

הסבר על התנאי ScaledToZero

תנאי ScaledToZero מציין אם המערכת Horizontal Pod Autoscaler (HPA) שינתה את קנה המידה של עומס העבודה לאפס רפליקות:

  • ScaledToZero: True (Reason: ScaledToZero): מציין שבקר ה-HPA שינה את קנה המידה של עומס העבודה ל-0 רפליקות כי הביקוש למדד חיצוני ירד לאפס. ה-HPA נשאר פעיל (ScalingActive: True) ומבצע סקרים רציפים ב-GKE כדי לזהות מתי הביקוש לעומס העבודה גדל.
  • ScaledToZero: False: מציין שעומס העבודה גדל עד לשימוש בעותק אחד או יותר.

אם משנים את קנה המידה של פריסה באופן ידני לאפס רפליקות, למשל באמצעות הפקודה kubectl scale --replicas=0, ה-HPA משהה את שינוי קנה המידה האוטומטי (ScalingActive: False) כדי למנוע שינויים סותרים. כדי להפעיל מחדש את ההתאמה האוטומטית לעומס, צריך לשנות את גודל הפריסה בחזרה ל-replica אחד או יותר (kubectl scale deployment async-worker --replicas=1).

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

הסרת המשאבים

כדי לא לצבור חיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם במדריך הזה, פועלים לפי השלבים הבאים:

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

    gcloud container clusters delete scale-to-zero \
        --project=${PROJECT_ID} \
        --location=${LOCATION}
    
  2. מחיקת המינוי והנושא ב-Pub/Sub:

    gcloud pubsub subscriptions delete my-worker-subscription \
        --project=${PROJECT_ID}
    gcloud pubsub topics delete my-worker-topic \
        --project=${PROJECT_ID}
    

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