הגדרת מאגרי קיבולת

מאגרי קיבולת משפרים את מהירות התגובה והאמינות של עומסי עבודה קריטיים. הם עושים זאת באמצעות ניהול פרואקטיבי של קיבולת עודפת של אשכולות ומצבים מושהים של קיבולת שהוקצתה מראש והוגדרה מראש, באמצעות CapacityBuffer CustomResourceDefinition ‏ (CRD) של Kubernetes. שימוש במאגרי קיבולת מאפשר לכם להגדיר במפורש כמות מסוימת של קיבולת צומת לא בשימוש באשכול. הקיבולת השמורה הזו עוזרת לקצר את זמן התזמון של ה-Pod.

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

בדף הזה מוסברות שיטות להגדרת מאגרי קיבולת: מאגר קבוע של רפליקות, מאגר של מגבלות משאבים ומאגר שמבוסס על אחוזים.

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

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

  • מפעילים את ממשק Google Kubernetes Engine API.
  • הפעלת Google Kubernetes Engine API
  • כדי להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את gcloud CLI. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.
  • צריך ליצור אשכול GKE בגרסה ‎1.35.2-gke.1842000 עבור מאגרי נתונים פעילים, או בגרסה ‎1.36.0-gke.2253000 ואילך עבור מאגרי נתונים במצב המתנה, או לקבל גישה לאשכול כזה.
  • מפעילים הקצאת משאבים אוטומטית של צמתים באשכולות רגילים. בקטגוריות של Autopilot, ניהול ההקצאות האוטומטי של הצמתים כבר מופעל. הקצאת משאבים אוטומטית לצמתים היא אופציונלית אבל מומלצת למאגרי זיכרון פעילים, ונדרשת למאגרי זיכרון במצב המתנה.

יצירת אובייקטים של Kubernetes שנדרשים מראש

כדי להגדיר CapacityBuffer, צריך מרחב שמות שמכיל את כל האובייקטים הנדרשים (ה-CapacityBuffer עצמו ומשאבים נוספים כמו PodTemplate או עומס עבודה). ה-PodTemplate וה-CapacityBuffer צריכים להיות באותו מרחב שמות. אתם יכולים ליצור מרחב שמות או להשתמש במרחב שמות קיים, כולל מרחב השמות default.

בהתאם לסוג ה-CapacityBuffer שאתם מגדירים, תצטרכו גם אחת מהאפשרויות הבאות:

  • PodTemplate: מגדיר את דרישות המשאבים ליחידה אחת של קיבולת מאגר. ההגדרה שצוינה באובייקט CapacityBuffer מפנה לתבנית ה-Pod.
  • עומס עבודה: עומס עבודה קיים שמופיע בהפניה באובייקט CapacityBuffer. במדריך הזה נעשה שימוש באובייקט Deployment כדוגמה לעומס עבודה, אבל מאגרי קיבולת תומכים בכל אחד מסוגי המשאבים הבאים:

    • פריסה
    • ReplicaSet
    • StatefulSet
    • ReplicationController
    • משימה
    • ‫CustomResourceDefinitions (CRDs) שמטמיעים את משאב המשנה scale.

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

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

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

    apiVersion: v1
    kind: Namespace
    metadata:
      name: capacity-buffer-example
      labels:
        name: capacity-buffer-example
    

    המניפסט הזה יוצר מרחב שמות בשם capacity-buffer-example.

  2. אופציונלי: כדי להשתמש במאגרי קיבולת עם ComputeClass מותאם אישית, שומרים את המניפסט הבא בתור custom-compute-class.yaml:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: ccc-example
      namespace: capacity-buffer-example
    spec:
      # Buffers are also created according to these priorities
      priorities:
      - machineFamily: n4
      - machineFamily: n4d
      - machineFamily: c4
      - machineFamily: c4d
      nodePoolAutoCreation:
        enabled: true
    

    קובץ המניפסט הזה יוצר ComputeClass מותאם אישית שמגדיר את סדרי העדיפויות של המחשוב עבור הצמתים שמוקצים על ידי GKE. מידע נוסף זמין במאמר בנושא custom ComputeClasses.

  3. שומרים את קובץ המניפסט הבא בשם buffer-pod-template.yaml:

    apiVersion: v1
    kind: PodTemplate
    metadata:
      name: buffer-unit-template
      namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer
    template:
      spec:
        terminationGracePeriodSeconds: 0
        containers:
        - name: buffer-container
          image: registry.k8s.io/pause:3.9
          resources:
            requests:
              cpu: "1"
              memory: "1Gi"
            limits:
              cpu: "1"
              memory: "1Gi"
        # Optional: Using buffers with a custom ComputeClass /
        # controls the properties of the provisioned nodes.
        nodeSelector:
          cloud.google.com/compute-class: ccc-example
    

    קובץ המניפסט הזה יוצר PodTemplate שמגדיר את דרישות המשאבים של יחידה אחת של קיבולת מאגר (1 CPU ו-1Gi זיכרון). ההגדרה הזו מציינת את הגודל של יחידות הקיבולת ש-GKE מקצה למאגר הנתונים הזמני. לדוגמה, אם משתמשים ב-PodTemplate הזה, מערכת GKE לא תכלול בצבירה צמתים עם פחות ממעבד אחד ו-‎1Gi של משאבים זמינים, אם מתבצעת הרחבה של האשכול.

  4. שומרים את קובץ המניפסט הבא בשם sample-workload-deployment.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: critical-workload-ref
      namespace: capacity-buffer-example # the namespace must be the same namespace as the CapacityBuffer
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: critical-workload
      template:
        metadata:
          labels:
            app: critical-workload
        spec:
          containers:
          - name: busybox
            image: busybox
            command: ["sleep", "3600"]
            resources:
              requests:
                cpu: 100m
          # Optional: Using buffers with a custom ComputeClass /
          # controls the properties of the provisioned nodes.
          nodeSelector:
            cloud.google.com/compute-class: ccc-example
    

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

  5. מחילים את קובצי המניפסט על האשכול:

    kubectl apply -f namespace.yaml -f custom-compute-class.yaml -f buffer-pod-template.yaml -f sample-workload-deployment.yaml
    
  6. מוודאים שאובייקטים נוצרו ב-GKE:

    kubectl get podtemplate -n capacity-buffer-example
    kubectl get deployment critical-workload-ref -n capacity-buffer-example
    

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

    NAME                   AGE
    buffer-unit-template   1m
    
    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    critical-workload-ref   10/10   10           10          1m
    

הוספת מאגר קיבולת

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

הגדרת מאגר של רפליקות קבועות

הגדרת CapacityBuffer עם רפליקות קבועות מציינת את המספר המדויק של יחידות המאגר שרוצים על סמך PodTemplate.

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

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

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: fixed-replica-buffer
      namespace: NAMESPACE
    spec:
      podTemplateRef:
        name: POD_TEMPLATE
      replicas: 3
      provisioningStrategy: "STRATEGY"
    

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

    • NAMESPACE: השם של מרחב השמות, לדוגמה capacity-buffer-example.
    • POD_TEMPLATE: PodTemplate שמגדיר את דרישות המשאבים, לדוגמה buffer-unit-template.
    • STRATEGY: שיטת ההקצאה, "buffer.x-k8s.io/active-capacity" (ברירת מחדל) או "buffer.gke.io/standby-capacity".

    קובץ המניפסט הזה יוצר משאב CapacityBuffer שמפנה אל PodTemplate כדי לבקש מספר ספציפי של יחידות מאגר.

  2. החלת המניפסט:

    kubectl apply -f cb-fixed-replicas.yaml
    
  3. מוודאים ש-GKE החיל את מאגר הקיבולת:

    kubectl get capacitybuffer fixed-replica-buffer -n NAMESPACE
    

    בשדה replicas בסטטוס צריך להופיע 3, שמשקף את מספר הרפליקות שהגדרתם במניפסט. בשדה STATUS צריך להופיע ReadyForProvisioning.

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

אפשר להשתמש בשדה limits כדי להגדיר את הכמות המקסימלית של משאבים שהמאגר צריך לצרוך, על סמך הגודל של PodTemplate.

כדי ליצור מאגר לניצול משאבים:

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

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: resource-limit-buffer
      namespace: NAMESPACE
    spec:
      podTemplateRef:
        name: POD_TEMPLATE
      limits:
        cpu: "5"
        memory: "5Gi"
      provisioningStrategy: "STRATEGY"
    

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

    • NAMESPACE: השם של מרחב השמות, לדוגמה capacity-buffer-example.
    • POD_TEMPLATE: PodTemplate שמגדיר את דרישות המשאבים, לדוגמה buffer-unit-template.
    • STRATEGY: שיטת ההקצאה, "buffer.x-k8s.io/active-capacity" (ברירת מחדל) או "buffer.gke.io/standby-capacity".

    קובץ המניפסט הזה יוצר משאב CapacityBuffer עם מגבלה כוללת של 5 יחידות עיבוד מרכזיות (CPU) ו-5 ‎GiB זיכרון. אם משתמשים בדוגמה של PodTemplate מהשלב הקודם, מגדירים כל יחידה כ-1 CPU ו-1Gi Memory, וכך אמורות להתקבל 5 יחידות של מאגר.

  2. החלת המניפסט:

    kubectl apply -f cb-resource-limits.yaml
    
  3. מוודאים ש-GKE החיל את מאגר הקיבולת:

    kubectl get capacitybuffer resource-limit-buffer -n NAMESPACE
    

    בודקים את הסטטוס של CapacityBuffer. בשדה replicas צריך להופיע ערך שנגזר מהמגבלות שהגדרתם. אם משתמשים בדוגמה של PodTemplate מהקטע הקודם, אמורות להופיע 5 יחידות של מאגר, כי זה המספר המקסימלי של יחידות שמתאים למגבלות שהוגדרו.

הגדרת מאגר נתונים זמני מבוסס-אחוזים

הגדרת מאגר זמני שמבוסס על אחוז מאפשרת לשנות את גודל המאגר באופן דינמי על סמך אחוז מעומס עבודה קיים שניתן להרחבה. אפשר להשתמש במרווחי ביטחון של קיבולת שמבוססים על אחוזים רק באובייקטים ניתנים להרחבה של Kubernetes שמטמיעים את משאב המשנה scale, כמו Deployments,‏ StatefulSets,‏ ReplicaSets או Jobs. אי אפשר להגדיר מאגר מבוסס-אחוזים לתבניות של פודים כי אין להן שדה replicas.

בדרך כלל מומלץ להתחיל עם שכפול קבוע או עם אסטרטגיות של הגבלת משאבים, ולא עם מאגרי זיכרון מבוססי-אחוזים. מאגרי זיכרון מבוססי-אחוזים פחות רגישים להגדלות פתאומיות אם עומס העבודה גדל למספרים נמוכים או לאפס, כי מרווח הביטחון גדל באופן יחסי ל-Pods פעילים. הן שימושיות בעיקר לפריסות גדולות שבהן מספר העותקים אף פעם לא יורד לרמה נמוכה מאוד.

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

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

    apiVersion: autoscaling.x-k8s.io/v1beta1
    kind: CapacityBuffer
    metadata:
      name: percentage-buffer
      namespace: NAMESPACE
    spec:
      scalableRef:
        apiGroup: apps
        kind: Deployment
        name: SCALABLE_RESOURCE_NAME
      percentage: 20
      provisioningStrategy: "STRATEGY"
    

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

    • NAMESPACE: השם של מרחב השמות.
    • SCALABLE_RESOURCE_NAME: השם של המשאב שניתן להרחבה, לדוגמה critical-workload-ref.
    • STRATEGY: שיטת ההקצאה, "buffer.x-k8s.io/active-capacity" (ברירת מחדל) או "buffer.gke.io/standby-capacity".

    קובץ המניפסט הזה יוצר משאב CapacityBuffer שמבקש גודל מאגר ששווה ל-20% מהרפליקות של המשאב שאליו מתייחסים. אם משתמשים בדוגמה לפריסה מהקטע הקודם, ערך הרפליקה מוגדר כ-10.

  2. החלת המניפסט:

    kubectl apply -f cb-percentage-based.yaml
    
  3. מוודאים ש-GKE החיל את מאגר הקיבולת:

    kubectl get capacitybuffer percentage-buffer -n NAMESPACE
    

    בודקים את הסטטוס של CapacityBuffer. בשדה replicas צריך להזין ערך שמתקבל מחישוב האחוז. אם אתם משתמשים בדוגמה לפריסה מהקטע הקודם, אמורות להופיע 2 יחידות של מאגר, שהן 20% מ-10 העותקים שהוגדרו בפריסה.

  4. כדי לבדוק את ההתאמה הדינמית של גודל הפריסה, מגדילים את הפריסה באופן ידני ל-20 רפליקות:

    kubectl scale deployment critical-workload-ref -n NAMESPACE --replicas=20
    

    הבקרה CapacityBuffer מגיבה ומבצעת התאמה אוטומטית של המאגר ל-4 רפליקות.

התאמה אישית של התנהגות מאגר ההמתנה

אפשר להשתמש בהערות כדי להתאים אישית את האופן שבו מאגרי ההמתנה מתחילים ומתרעננים. מוסיפים את ההערות האלה לשדה metadata.annotations של משאב CapacityBuffer:

  • buffer.gke.io/standby-capacity-init-time: משך הזמן שבו צומת נשאר פעיל אחרי שהוא נוצר, לפני שהוא מושעה. הפורמט הוא מחרוזת של משך זמן (לדוגמה, 5m או 1h). ערך ברירת המחדל הוא 5m.
  • buffer.gke.io/standby-capacity-refresh-frequency: באיזו תדירות מתבצע רענון של צמתים מושעים. ערך ברירת המחדל הוא 24h.

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

apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
  name: customized-standby-buffer
  namespace: my-namespace
  annotations:
    buffer.gke.io/standby-capacity-init-time: "15m"
    buffer.gke.io/standby-capacity-refresh-frequency: "12h"
spec:
  podTemplateRef:
    name: buffer-unit-template
  replicas: 3
  provisioningStrategy: "buffer.gke.io/standby-capacity"

טעינה מראש של תמונות במאגרי המתנה

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

כדי לטעון מראש תמונות באמצעות DaemonSet, מבצעים את השלבים הבאים:

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

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: image-prefetch-daemonset
      namespace: NAMESPACE
    spec:
      selector:
        matchLabels:
          name: image-prefetch
      template:
        metadata:
          labels:
            name: image-prefetch
        spec:
          tolerations:
          - key: "buffer.gke.io/standby-node-suspended"
            operator: "Exists"
          initContainers:
          - name: image-puller
            image: IMAGE_NAME
            command: ["sh", "-c", "true"]
          containers:
          - name: pause
            image: registry.k8s.io/pause:3.9
    

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

    • NAMESPACE: מרחב השמות של DaemonSet, לדוגמה capacity-buffer-example.
    • IMAGE_NAME: שם התמונה לטעינה מראש, לדוגמה your-app-image:latest.
  2. מחילים את מניפסט ה-DaemonSet על האשכול:

    kubectl apply -f image-puller-daemonset.yaml
    
  3. מוודאים ש-DaemonSet נוצר:

    kubectl get daemonset image-prefetch-daemonset -n NAMESPACE
    
  4. מוודאים שמאגר הקיבולת נוצר ומוכן להקצאת משאבים:

    kubectl get capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

    בודקים את הסטטוס. בשדה STATUS צריך להופיע ReadyForProvisioning.

מעקב אחרי הסטטוס והביצועים של מאגר הקיבולת

אפשר לעקוב אחרי הסטטוס והתקינות של מאגרי הקיבולת באמצעות פקודות kubectl ומדדים של Cloud Monitoring.

אימות הסטטוס של משאב CapacityBuffer

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

  1. כדי לראות את הסטטוס של כל מאגרי הקיבולת באשכול:

    kubectl get capacitybuffer -A
    
  2. כדי לבדוק את הסטטוס המפורט, התנאים ויומני האירועים של מאגר נתונים זמני ספציפי:

    kubectl describe capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE
    

זיהוי של צמתי מאגר בהמתנה מושעים

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

kubectl get nodes -o custom-columns='NAME:.metadata.name,SUSPENDED:.status.conditions[?(@.type=="Suspended")].status'

הסטטוס True מציין שמכונה וירטואלית במצב המתנה מושעית. הסטטוס False או <none> מציין שהצומת פעיל ופועל.

מעקב אחר הביצועים באמצעות Cloud Monitoring

כדי לעקוב אחרי הביצועים של מאגרי הקיבולת, כדאי לעקוב אחרי המשאבים הבאים ב-Cloud Monitoring:

  • זמן האחזור של התגובה (cluster_autoscaler/reaction_time_milliseconds): המדד הזה עוקב אחרי משך הזמן שנדרש ל-Cluster Autoscaler כדי לקבל החלטה לגבי שינוי גודל, על סמך הביקוש בהמתנה של CapacityBuffer.
  • יומנים של Cluster Autoscaler: מחפשים רשומות ביומן כמו "Capacity pod processor injecting ..." כדי לראות אירועים פעילים של החלפת Pod מאגר.

הסרת מאגרי קיבולת

אם אתם לא צריכים יותר מאגר קיבולת לעומסי העבודה, אתם יכולים למחוק את האובייקט CapacityBuffer. הפעולה הזו מסירה את ה-Pods של ה-placeholder ומאפשרת ל-autoscaler של האשכול להקטין את קנה המידה של הצמתים.

kubectl delete capacitybuffer CAPACITY_BUFFER_NAME -n NAMESPACE

מחליפים את CAPACITY_BUFFER_NAME בשם של CapacityBuffer שרוצים למחוק.

פתרון בעיות

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

מאגר הקיבולת לא מוכן בגלל מודל החיוב

אם יוצרים CapacityBuffer לעומס עבודה שמשתמש במודל החיוב מבוסס-Pod (תשלום לפי Pod), מאגר הקיבולת לא יהיה מוכן להקצאת משאבים.

כדי לזהות את הבעיה הזו, בודקים את הסטטוס של CapacityBuffer:

kubectl describe capacitybuffer BUFFER_NAME -n NAMESPACE

מחפשים תנאי מהסוג ReadyForProvisioning עם סטטוס False.

כדי לפתור את הבעיה, צריך לוודא ש-CapacityBuffer מפנה לעומס עבודה או ל-PodTemplate שתואמים לחיוב מבוסס-צומת.

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

אם מגדירים את CapacityBuffer לעבודה עם אובייקטים מותאמים אישית שניתנים להרחבה (באמצעות השדה scalableRef), יכול להיות שהכלי לאוטוסקיילינג של האשכול לא יצליח לשנות את גודל המאגר אם אין לו את ההרשאות הנדרשות.

כדי לפתור את הבעיה, צריך להעניק ידנית את ההרשאות הנדרשות על ידי יצירת ClusterRole ו-ClusterRoleBinding, כמו בדוגמה הבאה:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: custom-scale-getter
rules:
- apiGroups: ["api.example.com"]
  resources: ["customreplicatedresources/scale"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ca-custom-scale-getter
subjects:
- kind: User
  name: "system:cluster-autoscaler"
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: custom-scale-getter

מידע נוסף על הגדרת RBAC זמין במאמרי העזרה של Kubernetes בנושא RBAC.

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