הגדרת מגבלות משאבים מפורטות

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

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

הסבר על מגבלות המשאבים של CapacityQuota

‫CapacityQuota הוא משאב בהתאמה אישית של Kubernetes בהיקף אשכול, שאתם מגדירים במניפסט ומחילים על האשכול. כדי לבחור צמתים ולציין מגבלות על משאבים, משתמשים בשדות הבאים במפרט של CapacityQuota:

  • ‫selector: סינון של צמתים ספציפיים באמצעות בורר תוויות אחד או יותר. לדוגמה, אפשר לבחור את כל הצמתים של ComputeClass ספציפי או צמתים עם שתי תוויות ספציפיות.
  • ‫limits: מציינים את מגבלות המשאבים המקסימליות לצמתים שתואמים לסלקטורים. לדוגמה, אתם יכולים להגביל את כמות ה-CPU שאפשר להשתמש בה במחלקה ספציפית של מחשוב בהתאמה אישית, או להגביל את מספר ה-GPU מסוג מסוים.

כשהפעולה של הרחבה אנכית מתחילה, המידרוג האוטומטי של האשכול בודק את הצומת המוצע מול כל CapacityQuotas שתואמים לתוויות הצומת, ומול כל מגבלות המשאבים שהוגדרו ברמת האשכול. ‫GKE יוצר את הצומת רק אם הוא לא חורג ממגבלות המשאבים שהוגדרו.

מגבלות

  • ‫GKE דוחה מכסות קיבולת שמציינות את בוררי התוויות node.kubernetes.io/instance-type ו-beta.kubernetes.io/instance-type. כדי להגביל את הצמתים שמשתמשים בסוג מכונה ספציפי, יוצרים ComputeClass בהתאמה אישית עם כללי עדיפות machineType ובוחרים את ה-ComputeClass הזה ב-CapacityQuota.
  • בדומה למגבלות ברמת האשכול, יכול להיות שמכסות קיבולת ימנעו העברה פעילה של ComputeClass. העברה פעילה היא פעולה של הרחבה אנכית בהתאם לעומס (scale up), ולכן המידרוג האוטומטי של האשכול בודק את הצומת החדש הפוטנציאלי בהשוואה לכל מכסות הקיבולת (CapacityQuotas) הרלוונטיות ולמגבלות המשאבים ברמת האשכול. אם הצומת החדש חורג מאחת מהמגבלות האלה, GKE לא יוצר את הצומת וההעברה הפעילה לא מתבצעת. המצב הזה קורה רק אם הערך של CapacityQuota כבר הגיע למגבלות שהוגדרו או קרוב אליהן.
  • מגבלות מכסת הקיבולת הן לא מגבלות מחמירות. בתרחישים נדירים, יכול להיות שתבחינו ש-GKE חורג מהמגבלות שהוגדרו בשיעור קטן.
  • ההגבלות של CapacityQuota נאכפות רק על ידי המידרוג האוטומטי של האשכול. אפשר לחרוג מהמגבלות על ידי הרחבה ידנית של האשכול, או על ידי שינוי המגבלות כך שיהיו נמוכות מהשימוש הנוכחי.
  • אם הצמתים באשכול חורגים מהמגבלות שהוגדרו ב-CapacityQuota, אז המידרוג האוטומטי חוסם את היצירה של צמתים חדשים שתואמים ל-CapacityQuota שחרגו ממנו. המידרוג האוטומטי של האשכול לא מקטין את מספר הצמתים הקיימים שתואמים ל-CapacityQuota.

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

לפני שמתחילים, חשוב לוודא שביצעתם את המשימות הבאות:

  • מפעילים את Google Kubernetes Engine API.
  • הפעלת Google Kubernetes Engine API
  • כדי להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז לאתחל את ה-CLI של gcloud. אם כבר התקנתם את ה-CLI של gcloud, הריצו את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.
  • מוודאים שיש לכם אשכול קיים במצב Autopilot או Standard שפועל בגרסה 1.36.2-gke.2064000 ואילך. כדי ליצור אשכול חדש, אפשר לעיין במאמר בנושא יצירת אשכול Autopilot.

הגדרת מגבלות משאבים ב-CapacityQuota

כדי לבחור את הצמתים ש-CapacityQuota חלה עליהם, אפשר להשתמש באחת מהשיטות הבאות או בשתיהן:

  • בחירת צמתים באמצעות תוויות צומת מדויקות: מציינים צמד אחד או יותר של מפתח/ערך של תווית צומת בשדה matchLabels. ‫GKE מוצא צמתים שיש להם את כל התוויות שציינתם. השיטה הזו דומה לשימוש בשדה nodeSelector במפרט של Pod.

  • בחירת צמתים באמצעות ביטויים: מציינים ביטוי אחד או יותר של סלקטור תוויות על ידי ציון מפתח התווית, אופרטורים וערכים. השיטה הזו דומה לשימוש בשדה nodeAffinity במפרט של Pod.

בחירת צמתים באמצעות תוויות צמתים

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

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

    • כדי להגדיר מגבלות משאבים לכל ComputeClass מותאם אישית, מציינים את התווית cloud.google.com/compute-class:

      apiVersion: autoscaling.x-k8s.io/v1beta1
      kind: CapacityQuota
      metadata:
        name: capacity-quota-compute-class
      spec:
        selector:
          matchLabels:
            cloud.google.com/compute-class: my-class
        limits:
          resources:
            cpu: 12
      

      ה-CapacityQuota הזה מגביל את ה-Cluster Autoscaler למקסימום של 12 מעבדים בכל הצמתים ש-GKE יוצר עבור my-class ComputeClass.

    • כדי להגדיר מגבלות על מספר ה-GPU מסוג מסוים, משתמשים בתווית cloud.google.com/gke-accelerator ובשם המשאב nvidia.com/gpu:

      apiVersion: autoscaling.x-k8s.io/v1beta1
      kind: CapacityQuota
      metadata:
        name: capacity-quota-gpu
      spec:
        selector:
          matchLabels:
            cloud.google.com/compute-class: my-gpu-class
            cloud.google.com/gke-accelerator: nvidia-tesla-t4
        limits:
          resources:
            nvidia.com/gpu: 16
      

      ה-CapacityQuota הזה מגביל את המידרוג האוטומטי של האשכול ל-16 מעבדי GPU מסוג NVIDIA Tesla T4 לכל היותר ב-ComputeClass‏ my-gpu-class. אם לא מציינים את בורר ComputeClass, המגבלה חלה על כל הצמתים של NVIDIA Tesla T4 GPU באשכול.

    • כדי להגדיר מגבלות על מספר הצמתים ש-GKE יוצר באזור מסוים, משתמשים בתווית topology.kubernetes.io/zone ובשם המשאב nodes:

      apiVersion: autoscaling.x-k8s.io/v1beta1
      kind: CapacityQuota
      metadata:
        name: capacity-quota-zone
      spec:
        selector:
          matchLabels:
            topology.kubernetes.io/zone: us-central1-b
        limits:
          resources:
            nodes: 64
      

      ההגבלה הזו מגבילה את המידרוג האוטומטי באשכול ל-64 צמתים באזור us-central1-b.

  2. יוצרים את מכסת הקיבולת:

    kubectl apply -f PATH_TO_MANIFEST_FILE
    

    מחליפים את PATH_TO_MANIFEST_FILE בנתיב לקובץ המניפסט CapacityQuota שיצרתם.

בחירת צמתים באמצעות ביטויים

לטירגוט מורכב יותר, אפשר להגדיר ב-CapacityQuota את השדה matchExpressions בנוסף לשדה matchLabels. האופרטור matchExpressions מאפשר שימוש באופרטורים כמו In,‏ NotIn,‏ Exists ו-DoesNotExist.

  1. יוצרים מניפסט CapacityQuota שמשתמש בשדה matchExpressions. בדוגמה הבאה של CapacityQuota מוגדרים מגבלות על מעבד וזיכרון לצמתים שפועלים במשפחות ספציפיות של מכונות עם ביצועים גבוהים, על ידי קיבוץ שלהם באמצעות האופרטור In:

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityQuota
    metadata:
      name: capacity-quota-high-perf-machines
    spec:
      selector:
        matchExpressions:
          - key: cloud.google.com/machine-family
            operator: In
            values:
              - c2
              - c3
              - c3d
      limits:
        resources:
          cpu: 64
          memory: 128Gi
    
  2. מחילים את המניפסט על האשכול:

    kubectl apply -f PATH_TO_MANIFEST_FILE
    

    מחליפים את PATH_TO_MANIFEST_FILE בנתיב לקובץ המניפסט CapacityQuota שיצרתם.

אימות ההגדרה של CapacityQuota

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

  1. שומרים את הדוגמה הבאה של ComputeClass בתור test-capacityquota-class.yaml:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: test-capacityquota-class
    spec:
      priorities:
      - machineFamily: n2
      nodePoolAutoCreation:
        enabled: true
    

    ה-ComputeClass הזה יכול ליצור אוטומטית צמתים שמשתמשים בסדרת המכונות N2.

  2. יוצרים את ComputeClass:

    kubectl apply -f test-capacityquota-class.yaml
    
  3. שומרים את הדוגמה הבאה של CapacityQuota כ-test-capacityquota.yaml:

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityQuota
    metadata:
      name: test-capacityquota
    spec:
      selector:
        matchLabels:
          cloud.google.com/compute-class: test-capacityquota-class
      limits:
        resources:
          cpu: 8
    

    ההגדרה CapacityQuota מגבילה את קנה המידה האוטומטי למקסימום של 8 משאבי CPU עבור test-capacityquota-class ComputeClass.

  4. יוצרים את מכסת הקיבולת:

    kubectl apply -f test-capacityquota.yaml
    
  5. שומרים את הפריסה הבאה בשם test-capacityquota-workload.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: test-capacityquota-workload
    spec:
      replicas: 16
      selector:
        matchLabels:
          app: test-capacityquota-workload
      template:
        metadata:
          labels:
            app: test-capacityquota-workload
        spec:
          containers:
          - name: test
            image: gcr.io/google_containers/pause
            resources:
              limits:
                cpu: 500m
          nodeSelector:
            cloud.google.com/compute-class: test-capacityquota-class
    

    הפריסה הזו יוצרת 16 פודים, שכל אחד מהם מבקש 500 mCPU. מכיוון שהצמתים שומרים חלק מהמעבד לרכיבי המערכת, סכום משאבי המעבד בכל הצמתים ש-GKE צריך ליצור כדי להפעיל את 16 ה-Pods גדול מ-8.

  6. יוצרים את הפריסה:

    kubectl apply -f test-capacityquota-workload.yaml
    
  7. ממתינים כשתי דקות ואז מאמתים את סטטוס התזמון של ה-Pod:

    kubectl get pods -l app=test-capacityquota-workload
    

    המידרוג האוטומטי באשכול מרחיב את הצמתים עד למגבלת CapacityQuota של 8 מעבדים. אחרי שמגיעים למגבלה הזו, המידרוג האוטומטי לא יוצר צמתים. כתוצאה מכך, חלק מה-Pods בפריסה נשארים במצב Pending.

  8. כדי לוודא שהסטטוס Pending נגרם בגלל CapacityQuota, מתארים אחד מה-Pods בהמתנה:

    kubectl describe pod PENDING_POD_NAME
    

    מחליפים את PENDING_POD_NAME בשם של Pod שנתקע במצב Pending.

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

    Pod didn't trigger scale-up: 1 exceeded quota: "CapacityQuota/test-capacityquota", resources: cpu
    

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

    {
      "jsonPayload": {
        "noDecisionStatus": {
          "noScaleUp": {
            "skippedMigs": [
              {
                "reason": {
                  "parameters": [
                    "exceeded quota: \"CapacityQuota/test-capacityquota\", resources: cpu"
                  ],
                  "messageId": "no.scale.up.mig.skipped"
                },
                "mig": {
                  "name": "gke-test-grp",
                  "zone": "us-central1-f",
                  "nodepool": "nap-n2-highcpu-2-test"
                }
              }
            ]
          }
        }
      }
    }
    

בדיקת השימוש והתוקף של CapacityQuotas

השדה status במשאב CapacityQuota API מספק מידע על השימוש במשאבים של צמתים שתואמים ל-CapacityQuota, ועל התוקף של מפרט CapacityQuota.

כדי לבדוק את הסטטוס של CapacityQuota, מריצים את הפקודה הבאה:

kubectl describe capacityquota CAPACITY_QUOTA_NAME

מחליפים את CAPACITY_QUOTA_NAME בשם של מכסת הקיבולת שרוצים לבדוק.

בודקים את השדות הבאים בפלט:

  • כדי לבדוק את השימוש במשאבים של הצמתים התואמים, משתמשים בשדה status.used:

    status:
      conditions:
      - lastTransitionTime: "2026-07-27T10:00:00Z"
        message: "CapacityQuota is valid"
        reason: "Valid"
        status: "True"
        type: "cluster-autoscaler.kubernetes.io/valid"
      used:
        resources:
          cpu: 32
          memory: 128Gi
    

    השדה status.used מיועד לניראות (observability), והמידרוג האוטומטי של האשכול לא משתמש בו כדי לאכוף מגבלות. השדה הזה מציג את השימוש רק אחרי פעולת הרחבה מוצלחת. המידרוג האוטומטי של האשכול עוקב גם אחרי צמתים בהמתנה באופן פנימי, ומשקלל את הצמתים האלה בהמתנה בהערכות הבאות של הגדלת הקיבולת. המעקב הפנימי הזה עוזר למנוע חריגה מהמגבלות.

  • כדי לבדוק את התוקף של CapacityQuota, משתמשים בשדה status.conditions:

    status:
      conditions:
      - lastTransitionTime: "2026-07-27T10:00:00Z"
        message: "CapacityQuota is valid"
        reason: "Valid"
        status: "True"
        type: "cluster-autoscaler.kubernetes.io/valid"
      used:
        resources:
          cpu: 32
          memory: 128Gi
    

    התנאי cluster-autoscaler.kubernetes.io/valid בודק אם מכסת הקיבולת משתמשת בהגדרה תקינה, כמו סלקטור בפורמט הנכון. אם הערך בשדה status של התנאי הזה הוא True, מכסת הקיבולת תקפה והמגבלות שלכם נאכפות. עם זאת, אם הערך בשדה status הוא False, או אם התנאי עדיין לא קיים, המגבלות לא נאכפות. בשדה message מפורטות הסיבות לכך שהערך של CapacityQuota לא תקין.

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