הקצאת קיבולת מחשוב נוספת להתאמה מהירה של Pod לעומס

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

למה כדאי להקצות קיבולת עודפת

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

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

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

איך פועל הקצאת קיבולת עודפת ב-GKE

כדי להקצות קיבולת עודפת, אפשר להשתמש ב-PriorityClasses של Kubernetes וב-Pods של placeholder. בעזרת PriorityClass אפשר לציין ל-GKE שעומסי עבודה מסוימים הם בעדיפות נמוכה יותר מעומסי עבודה אחרים. אפשר לפרוס תרמילי placeholder שמשתמשים ב-PriorityClass עם עדיפות נמוכה ולבקש את קיבולת המחשוב שצריך לשריין. ‫GKE מוסיף קיבולת לאשכול על ידי יצירת צמתים חדשים כדי להכיל את ה-Pods של ה-placeholder.

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

כשמפנים מקום ל-Pod של placeholder, הוא חוזר למצב בהמתנה. אם משתמשים בפריסה לאספקת משאבים עקבית, בקר הפריסה מנסה ליצור מחדש את ה-Pod באופן מיידי. אם ל-Pod של placeholder יש עדיפות של ‎-10, הוא יפעיל את שינוי הגודל האוטומטי של האשכול כדי ליצור צומת חדש (אם צריך) במקום הקיבולת השמורה שבה השתמשתם. המחזור הזה עוזר לוודא שתמיד יש באשכול את כמות הקיבולת הפנויה שצוינה.

שיטות הקצאת קיבולת

בהתאם לתרחיש השימוש, אתם יכולים להקצות קיבולת נוספת באשכולות GKE באחת מהדרכים הבאות:

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

תמחור

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

ב-GKE Standard, אתם מחויבים על המכונות הווירטואליות הבסיסיות של Compute Engine שמוקצות על ידי GKE, בלי קשר לשאלה אם ה-Pods משתמשים בקיבולת הזו. פרטים נוספים מופיעים במאמר בנושא תמחור רגיל.

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

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

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

יצירת PriorityClass

כדי להשתמש באחת מהשיטות שמתוארות במאמר בנושא שיטות הקצאת קיבולת, צריך קודם ליצור את PriorityClasses הבאים:

  • Default PriorityClass: PriorityClass גלובלי שמוגדר כברירת מחדל ומוקצה לכל Pod שלא מוגדר בו במפורש PriorityClass אחר במפרט של ה-Pod. ל-Pods עם PriorityClass שמוגדר כברירת מחדל יש אפשרות להוציא משימוש Pods שמשתמשים ב-PriorityClass נמוך יותר.
  • Low PriorityClass: PriorityClass שאינו ברירת מחדל ומוגדר לעדיפות הנמוכה ביותר האפשרית ב-GKE. אפשר להוציא משימוש Pods עם PriorityClass כזה כדי להריץ Pods עם PriorityClass גבוה יותר.
  1. שומרים את קובץ המניפסט הבא בשם priorityclasses.yaml:

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: low-priority
    value: -10
    preemptionPolicy: Never
    globalDefault: false
    description: "Low priority workloads"
    ---
    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: default-priority
    value: 0
    preemptionPolicy: PreemptLowerPriority
    globalDefault: true
    description: "The global default priority."
    

    המניפסט הזה כולל את השדות הבאים:

    • preemptionPolicy: מציין אם אפשר להוציא מ-Pods שמשתמשים ב-PriorityClass,‏ Pods עם עדיפות נמוכה יותר. ‫low-priority PriorityClass משתמש ב-Never, ו-default PriorityClass משתמש ב-PreemptLowerPriority.
    • value: העדיפות של ה-Pods שמשתמשים ב-PriorityClass. באשכולות GKE, שינוי הגודל האוטומטי של האשכול משתמש בערך ברירת מחדל של סף עדיפות להוצאה של ‎-10. אם העדיפות היא ‎-10 או יותר, אפשר להפעיל את יצירת הצמתים החדשים ב-Pods אם אין קיבולת זמינה. אם העדיפות נמוכה מ-10-,‏ Pods לא מפעילים את שינוי הגודל האוטומטי של האשכול, ולכן לא מוקצים צמתים חדשים. אם אין קיבולת, ה-Pods נשארים במצב Pending.

      במאמר בחירת עדיפות מוסבר איך בוחרים ערכים מתאימים לעדיפות.

    • globalDefault: מציין אם GKE מקצה את PriorityClass ל-Pods שלא הוגדר להם PriorityClass באופן מפורש במפרט ה-Pod. ‫low-priority PriorityClass משתמש ב-false, ו-default PriorityClass משתמש ב-true.

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

    kubectl apply -f priorityclasses.yaml
    

הקצאת קיבולת מחשוב נוספת

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

שימוש בפריסה להקצאת קיבולת עקבית

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

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: capacity-res-deploy
    spec:
      replicas: 10
      selector:
        matchLabels:
          app: reservation
      template:
        metadata:
          labels:
            app: reservation
        spec:
          priorityClassName: low-priority
          terminationGracePeriodSeconds: 0
          containers:
          - name: ubuntu
            image: ubuntu
            command: ["sleep"]
            args: ["infinity"]
            resources:
              requests:
                cpu: 500m
                memory: 500Mi
    

    המניפסט הזה כולל את השדות הבאים:

    • spec.replicas: משנים את הערך הזה בהתאם לדרישות.
    • spec.resources.requests: משנים את בקשות ה-CPU והזיכרון בהתאם לדרישות. כדי להחליט על ערכי בקשות מתאימים, אפשר להיעזר בהנחיות שבקטע בחירת גודל הקיבולת.
    • spec.containers.command ו-spec.containers.args: הגדרת ה-Pods כך שיישארו פעילים עד ש-GKE יוציא אותם.
  2. החלת המניפסט:

    kubectl apply -f capacity-res-deployment.yaml
    
  3. קבלת הסטטוס של ה-Pod:

    kubectl get pods -l app=reservation
    

    מחכים עד שכל העותקים יהיו בסטטוס Running.

שימוש במשימה להקצאת קיבולת לאירוע יחיד

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

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: capacity-res-job
    spec:
      parallelism: 4
      backoffLimit: 0
      template:
        spec:
          priorityClassName: low-priority
          terminationGracePeriodSeconds: 0
          containers:
          - name: ubuntu-container
            image: ubuntu
            command: ["sleep"]
            args: ["36000"]
            resources:
              requests:
                cpu: "16"
          restartPolicy: Never
    

    המניפסט הזה כולל את השדות הבאים:

    • spec.parallelism: משנים את מספר העבודות שרוצים להריץ במקביל כדי לשריין קיבולת.
    • spec.backoffLimit: 0: מניעה של יצירה מחדש של משימות שהוצאו על ידי בקר המשימות.
    • template.spec.resources.requests: משנים את בקשות ה-CPU והזיכרון בהתאם לדרישות. כדי להחליט אילו ערכים מתאימים, אפשר להיעזר בהנחיות שבקטע שיקולים.
    • template.spec.containers.command ו-template.spec.containers.args: מציינים את משך הזמן בשניות שבו העבודות צריכות להישאר פעילות, כלומר משך הזמן שבו נדרש קיבולת נוספת.
  2. החלת המניפסט:

    kubectl apply -f capacity-res-job.yaml
    
  3. קבלת סטטוס המשימה:

    kubectl get jobs
    

    מחכים עד שכל המשימות יהיו בסטטוס Running.

בדיקת הקצאת הקיבולת וההוצאה מהזיכרון

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

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

    1. כדי להפעיל את הפקודה Deployments, מריצים את הפקודה הבאה:

      kubectl get pods --label=app=reservation -w
      
    2. כדי להריץ את הפקודה Jobs:

      kubectl get Jobs -w
      
  2. פותחים חלון טרמינל חדש ומבצעים את הפעולות הבאות:

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

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: helloweb
        labels:
          app: hello
      spec:
        replicas: 5
        selector:
          matchLabels:
            app: hello
            tier: web
        template:
          metadata:
            labels:
              app: hello
              tier: web
          spec:
            containers:
            - name: hello-app
              image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
              ports:
              - containerPort: 8080
              resources:
                requests:
                  cpu: 400m
                  memory: 400Mi
      
    2. החלת המניפסט:

      kubectl apply -f test-deployment.yaml
      
  3. בחלון הטרמינל המקורי, אפשר לראות ש-GKE מסיים כמה מעומסי העבודה של הקצאת הקיבולת כדי לתזמן את הרפליקות החדשות, כמו בדוגמה הבאה:

    NAME                                         READY   STATUS    RESTARTS   AGE
    capacity-res-deploy-6bd9b54ffc-5p6wc         1/1     Running   0          7m25s
    capacity-res-deploy-6bd9b54ffc-9tjbt         1/1     Running   0          7m26s
    capacity-res-deploy-6bd9b54ffc-kvqr8         1/1     Running   0          2m32s
    capacity-res-deploy-6bd9b54ffc-n7zn4         1/1     Running   0          2m33s
    capacity-res-deploy-6bd9b54ffc-pgw2n         1/1     Running   0          2m32s
    capacity-res-deploy-6bd9b54ffc-t5t57         1/1     Running   0          2m32s
    capacity-res-deploy-6bd9b54ffc-v4f5f         1/1     Running   0          7m24s
    helloweb-85df88c986-zmk4f                    0/1     Pending   0          0s
    helloweb-85df88c986-lllbd                    0/1     Pending   0          0s
    helloweb-85df88c986-bw7x4                    0/1     Pending   0          0s
    helloweb-85df88c986-gh8q8                    0/1     Pending   0          0s
    helloweb-85df88c986-74jrl                    0/1     Pending   0          0s
    capacity-res-deploy-6bd9b54ffc-v6dtk   1/1     Terminating   0          2m47s
    capacity-res-deploy-6bd9b54ffc-kvqr8   1/1     Terminating   0          2m47s
    capacity-res-deploy-6bd9b54ffc-pgw2n   1/1     Terminating   0          2m47s
    capacity-res-deploy-6bd9b54ffc-n7zn4   1/1     Terminating   0          2m48s
    capacity-res-deploy-6bd9b54ffc-2f8kx   1/1     Terminating   0          2m48s
    ...
    helloweb-85df88c986-lllbd              0/1     Pending       0          1s
    helloweb-85df88c986-gh8q8              0/1     Pending       0          1s
    helloweb-85df88c986-74jrl              0/1     Pending       0          1s
    helloweb-85df88c986-zmk4f              0/1     Pending       0          1s
    helloweb-85df88c986-bw7x4              0/1     Pending       0          1s
    helloweb-85df88c986-gh8q8              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-zmk4f              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-bw7x4              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-lllbd              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-74jrl              0/1     ContainerCreating   0          1s
    helloweb-85df88c986-zmk4f              1/1     Running             0          4s
    helloweb-85df88c986-lllbd              1/1     Running             0          4s
    helloweb-85df88c986-74jrl              1/1     Running             0          5s
    helloweb-85df88c986-gh8q8              1/1     Running             0          5s
    helloweb-85df88c986-bw7x4              1/1     Running             0          5s
    

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

שיקולים בהקצאת קיבולת

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

הקצאת קיבולת עקבית

  • צריך להעריך כמה עותקים משוכפלים של Pod של placeholder נדרשים ומה הגודל של הבקשות בכל עותק משוכפל. ההעתקים המשוכפלים בעדיפות נמוכה צריכים לבקש לפחות את אותה קיבולת כמו עומס העבודה הגדול ביותר בסביבת הייצור, כדי שעומסי העבודה האלה יוכלו להיכנס לקיבולת שהוקצתה לעומס העבודה בעדיפות נמוכה.
  • אם אתם מפעילים מספר גדול של עומסי עבודה של ייצור בקנה מידה גדול, כדאי להגדיר את בקשות המשאבים של ה-Pods של ה-placeholder לערכים שמספקים מספיק קיבולת להפעלת כמה עומסי עבודה של ייצור במקום רק אחד.

הקצאת קיבולת לשימוש חד-פעמי

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

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

בחירת עדיפות

אפשר להגדיר כמה PriorityClass באשכול כדי להשתמש בהם עם עומסי עבודה שיש להם דרישות שונות. לדוגמה, אפשר ליצור PriorityClass עם עדיפות של ‎-10 להקצאת קיבולת לשימוש חד-פעמי, ו-PriorityClass עם עדיפות של ‎-9 להקצאת קיבולת עקבית. לאחר מכן תוכלו להקצות קיבולת עקבית באמצעות PriorityClass עם עדיפות ‎-9, וכשאתם רוצים קיבולת גדולה יותר לאירוע מיוחד, תוכלו לפרוס משימות חדשות שמשתמשות ב-PriorityClass עם עדיפות ‎-10. מערכת GKE מפנה קודם את עומסי העבודה עם העדיפות הכי נמוכה.

אפשר גם להשתמש ב-PriorityClass אחרים כדי להריץ עומסי עבודה לא ייצוריים בעדיפות נמוכה שמבצעים משימות בפועל, כמו עומסי עבודה באצווה שהם עמידים בפני כשלים, בעדיפות נמוכה יותר מעומסי העבודה הייצוריים אבל גבוהה יותר מ-Pods של placeholder. לדוגמה, ‎-5.

בחירת גודל הקיבולת

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

הקיבולת הכוללת שהוקצתה מבוססת על מספר ה-Pods של placeholder שפרסתם ועל בקשות המשאבים של כל רפליקה. אם ההרחבה שלכם דורשת יותר קיבולת ממה שהוקצה ב-GKE לתאי ה-Pod של ה-placeholder, חלק מעומסי העבודה שלכם בסביבת הייצור יישארו במצב Pending עד ש-GKE יוכל להקצות יותר קיבולת.

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