שימוש במכונות preemptible VM להרצת עומסי עבודה (workloads) עמידים בכשלים

בדף הזה מוסבר איך להשתמש במכונות וירטואליות שניתנות להפסקת פעולה ב-Google Kubernetes Engine ‏ (GKE).

סקירה כללית

מכונות Preemptible VM הן מכונות וירטואליות של Compute Engine שמחירן נמוך ממכונות וירטואליות רגילות, ואין עליהן הבטחה לזמינות. מכונות VM שניתן לקטוע מציעות פונקציונליות דומה לזו של מכונות VM זמניות, אבל הן זמינות למשך עד 24 שעות אחרי היצירה.

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

השוואה ל-VMs במודל Spot

מכונות וירטואליות זמניות דומות למכונות וירטואליות מסוג Spot במובנים רבים, כולל:

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

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

סיום וכיבוי מבוקר של מכונות וירטואליות זמניות

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

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

במקרה הטוב, kubelet מעניק תקופת סיום תקינה של 15 שניות ל-Pods שאינם מערכתיים, ולאחר מכן ל-Pods מערכתיים (עם priorityClasses‏ system-cluster-critical או system-node-critical) יש 15 שניות לסיום תקין. במהלך סגירה מסודרת של צומת, ה-kubelet מעדכן את הסטטוס של ה-Pods ומקצה להם שלב Failed וסיבה Terminated לסגירה.

תקופת ההמתנה לסיום תקין של Pods שאינם מערכתיים היא עד 15 שניות. אין השפעה להגדרה של ערך גדול מ-15 שניות בשדה terminationGracePeriodSeconds במניפסט של הפוד. המכונה הווירטואלית כולה מושבתת 30 שניות אחרי ההודעה על ההפקעה.

שינויים בהתנהגות של Kubernetes

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

מגבלות

  • התכונה של כיבוי צומת חלק ב-kubelet מופעלת רק באשכולות שמריצים GKE בגרסה 1.20 ואילך. בגרסאות GKE שקודמות לגרסה 1.20, אפשר להשתמש בKubernetes on GCP Node Termination Event Handler כדי להפסיק את הפודים בצורה מסודרת כשמכונות וירטואליות שניתנות להפסקת פעולה מופסקות.
  • מכונות וירטואליות שניתן לקטוע את הפעולה שלהן לא תומכות במאגרי צמתים של Windows Server.
  • ב-GKE, תקופת החסד של 15 שניות עבור פודים שאינם פודים של המערכת, והתקופה הבאה של 15 שניות עבור פודים של המערכת, הן קבועות ואי אפשר לשנות אותן. אי אפשר לשנות את שדות ההגדרה הבסיסיים של shutdownGracePeriod ו-kubelet shutdownGracePeriodCriticalPods.

יצירת אשכול או מאגר צמתים עם מכונות וירטואליות זמניות

אתם יכולים להשתמש ב-Google Cloud CLI כדי ליצור אשכול או מאגר צמתים עם מכונות וירטואליות שניתנות להפסקת פעולה.

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

gcloud container clusters create CLUSTER_NAME \
    --preemptible

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

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

gcloud container node-pools create POOL_NAME \
    --cluster=CLUSTER_NAME \
    --preemptible

מחליפים את POOL_NAME בשם של מאגר הצמתים החדש.

שימוש ב-nodeSelector לתזמון של Pod במכונות וירטואליות (VM) זמניות

‫GKE מוסיף את התוויות cloud.google.com/gke-preemptible=true ו-cloud.google.com/gke-provisioning=preemptible (לצמתים שפועלת בהם GKE בגרסה ‎1.25.5-gke.2500 ואילך) לצמתים שמשתמשים במכונות וירטואליות שניתנות להפסקת פעולה. אתם יכולים להשתמש ב-nodeSelector בפריסות כדי להנחות את GKE לתזמן Pods במכונות preemptible VM.

לדוגמה, הפריסה הבאה מסננת מכונות וירטואליות שניתנות להפסקת פעולה באמצעות התווית cloud.google.com/gke-preemptible:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-app
  template:
    metadata:
      labels:
        app: hello-app
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        resources:
          requests:
            cpu: 200m
      nodeSelector:
        cloud.google.com/gke-preemptible: "true"

שימוש ב-taints של צמתים למכונות וירטואליות זמניות

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

כדי להוסיף taint לצומת למאגר צמתים שמשתמש במכונות וירטואליות זמניות, משתמשים בדגל --node-taints כשיוצרים את מאגר הצמתים, בדומה לפקודה הבאה:

gcloud container node-pools create POOL2_NAME \
    --cluster=CLUSTER_NAME \
    --node-taints=cloud.google.com/gke-preemptible="true":NoSchedule

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

כדי להוסיף את ה-toleration הרלוונטי ל-Pods, משנים את הפריסות ומוסיפים את השורה הבאה למפרט ה-Pod:

tolerations:
- key: cloud.google.com/gke-preemptible
  operator: Equal
  value: "true"
  effect: NoSchedule

Node taints for GPU preemptible VMs

מכונות וירטואליות שניתן להפסיק את פעולתן תומכות בשימוש במעבדי GPU. לפני שמוסיפים מאגר צמתים של GPU שמשתמש במכונות preemptible VM, כדאי ליצור לפחות עוד מאגר צמתים באשכול שלא משתמש במכונות preemptible VM. מאגר צמתים רגיל עוזר לוודא ש-GKE יכול למקם בבטחה רכיבי מערכת כמו DNS.

אם יוצרים אשכול חדש עם מאגרי צמתים של GPU שמשתמשים במכונות וירטואליות שניתנות להפסקת פעולה, או אם מוסיפים מאגר צמתים חדש של GPU שמשתמש במכונות וירטואליות שניתנות להפסקת פעולה לאשכול שעדיין אין לו מאגר צמתים רגיל, GKE לא מוסיף באופן אוטומטי את ההגדרה nvidia.com/gpu=present:NoSchedule לצמתים. יכול להיות ש-GKE יתזמן Pods של המערכת במכונות וירטואליות זמניות, מה שעלול לגרום לשיבושים. ההתנהגות הזו גם מגדילה את צריכת המשאבים, כי צמתים של GPU יקרים יותר מצמתים ללא GPU.

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