שימוש במכונות 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

מכונות וירטואליות (VM) זמניות דומות למכונות וירטואליות (VM) במודל Spot בהרבה מובנים, כולל:

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

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

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

כש-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 שנסגרו.

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

כשמספר ה-Pods שהופסקו מגיע לסף של 1,000 באשכולות עם פחות מ-100 צמתים או 5,000 באשכולות עם 100 צמתים או יותר, מתבצע איסוף אשפה כדי לנקות את ה-Pods.

אפשר גם למחוק ידנית Pods שהופסקו באמצעות הפקודות הבאות:

  kubectl get pods --all-namespaces | grep -i NodeShutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n
  kubectl get pods --all-namespaces | grep -i Terminated | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

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

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

מגבלות

  • התכונה של כיבוי צומת חלק ב-kubelet מופעלת רק באשכולות שמריצים את GKE בגרסה 1.20 ואילך. בגרסאות GKE שקודמות לגרסה 1.20, אפשר להשתמש בKubernetes on GCP Node Termination Event Handler כדי להפסיק את ה-Pod-ים בצורה מסודרת כשמכונות וירטואליות זמניות מופסקות.
  • מכונות וירטואליות שניתן לקטוע את הפעולה שלהן לא תומכות במאגרי צמתים של 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 של צמתים למכונות וירטואליות (VM) זמניות

אפשר להוסיף כתם לצמתים שמשתמשים במכונות וירטואליות שניתנות להפסקת פעולה, כדי ש-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 לא מוסיף באופן אוטומטי את ה-taint‏ nvidia.com/gpu=present:NoSchedule לצמתים. יכול להיות ש-GKE יתזמן קבוצות Pod של המערכת במכונות וירטואליות זמניות, מה שעלול לגרום לשיבושים. ההתנהגות הזו גם מגדילה את צריכת המשאבים, כי צמתים של GPU יקרים יותר מצמתים ללא GPU.

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