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

במהלך מחזור החיים של אשכול GKE שפועל לאורך זמן, מתרחשות הפרעות תקופתיות בעומסי העבודה בגלל שיבושים בתשתית שגורמים לCloud de Confiance by S3NS בעיות. האירועים האוטומטיים האלה יכולים להתרחש בתגובה להחלטות תזמון (אירועי הפסקה זמנית), או לעדכוני צמתים, כולל שדרוגים אוטומטיים של צמתים ב-GKE (אירועי תחזוקה), או לתיקון בעיות שזוהו (אירועי סיום).

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

המסמך הזה רלוונטי לסוגי המכונות הבאים:

המאמר הזה מיועד לאדמינים ולמפעילים של פלטפורמות שמנהלים את מחזור החיים של התשתית הטכנולוגית הבסיסית. מידע נוסף על תפקידים נפוצים ועל משימות לדוגמה שאנחנו מתייחסים אליהן ב Cloud de Confiance by S3NS תוכן, זמין במאמר תפקידים נפוצים של משתמשים ומשימות ב-GKE.

מהי הפרעה בתשתית ב-GKE?

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

  • תיקון בעיות שזוהו (TerminationEvent): האירועים האלה מתרחשים כי Cloud de Confiance by S3NS מזהה בעיה ומשבש את תשתית האשכול. אירועי TerminationEvent לא תומכים בכיבוי מסודר. אירועי TerminationEvent מופעלים בגלל הבעיות הבאות:

    • תיקון אוטומטי מתרחש כש-GKE מתקן צומת אחרי בדיקות תקינות חוזרות שנכשלו.
    • השגיאה HostError מתרחשת כשתקלה בחומרה או בתוכנה במכונה הפיזית גורמת לעצירה של המכונה הווירטואלית.
  • אירועי תחזוקה או שדרוג (MaintenanceEvent): האירועים האלה מתרחשים כש- Cloud de Confiance by S3NS צריך להפריע למכונה וירטואלית כדי לבצע תחזוקה. אירועי MaintenanceEvent מופעלים על ידי משימות התחזוקה הבאות:

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

  • תגובה להחלטות תזמון (PreemptionEvent): מתרחשת כש-Cloud de Confiance by S3NS צריך להקצות מראש מכונות וירטואליות כדי לפנות קיבולת למשאבים עם עדיפות גבוהה יותר. הערך PreemptionEvent יכול להיות כל אחת מהאפשרויות הבאות:

    • הוצאה: מתרחשת כשמכונה וירטואלית (VM) זמנית או מכונת Spot מוצאת לפני הזמן כדי לפנות מקום למכונה וירטואלית (VM) בעדיפות גבוהה יותר.
    • ביטול פרגמנטציה: מתרחש כש-GKE מבצע הקצאה מראש של פרוסת TPU קטנה יותר כדי לפנות מקום לפרוסת TPU גדולה יותר. ביצוע דה-פרגמנטציה מתרחש רק בפרוסות TPU.

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

למה צמתים ללא העברה פעילה דורשים ניהול הפרעות

ברוב המכונות הווירטואליות של Compute Engine, עם כמה יוצאים מן הכלל, מדיניות התחזוקה של המארח מוגדרת למיגרציה פעילה, כלומר בדרך כלל יש שיבושים קלים מאוד או שאין שיבושים בכלל בעומסי העבודה הפעילים. עם זאת, סוגים מסוימים של מכונות וירטואליות לא תומכים במיגרציה פעילה, כולל מכונות וירטואליות עם מעבדי GPU ומעבדי TPU מצורפים, סוגי מכונות Z3 עם יותר מ-18 TiB של SSD, סוגי מכונות H4D וסוג המכונה c4a-highmem-96-metal (בגרסת Preview). לדוגמה, כשאירוע של המארח מתרחש במכונה וירטואלית בתוך פרוסת TPU, הפרוסה כולה מופרעת ואז מתוזמנת מחדש, כי כל אירועי התחזוקה מתואמים ברמת הפרוסה. לכן, אם תיצרו פלח TPU עם מאות מכונות וירטואליות, כל המכונות הווירטואליות האלה יקבלו את אותו לוח זמנים של אירוע תחזוקה.

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

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

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

מעקב אחרי הפרעות בצומת

מדד המערכת הבא של GKE מדווח על מספר ההפרעות בצומת GKE מאז הדגימה האחרונה (המדד נדגם כל 60 שניות):

  • kubernetes.io/node/interruption_count

השדות interruption_type (למשל TerminationEvent, ‏MaintenanceEvent או PreemptionEvent) ו-interruption_reason (למשל HostError, ‏Eviction או AutoRepair) יכולים לעזור להבין למה הייתה הפרעה בצומת.

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

  sum by (interruption_type,interruption_reason)(
    sum_over_time(
      kubernetes_io:node_interruption_count{monitored_resource="k8s_node"}[${__interval}]))

כדי לראות רק את אירועי התחזוקה של המארח, צריך לעדכן את השאילתה כדי לסנן את הערך HW/SW Maintenance בשדה interruption_reason. משתמשים בשאילתת PromQL הבאה:

  sum by (interruption_type,interruption_reason)(
    sum_over_time(
      kubernetes_io:node_interruption_count{monitored_resource="k8s_node", interruption_reason="HW/SW Maintenance"}[${__interval}]))

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

  sum by (node_pool_name,interruption_type,interruption_reason)(
    sum_over_time(
      kubernetes_io:node_pool_interruption_count{monitored_resource="k8s_node_pool", interruption_reason="HW/SW Maintenance", node_pool_name=NODE_POOL_NAME }[${__interval}]))

מעקב אחרי התראות לגבי פעולות תחזוקה

‫Compute Engine שולח התראות כשמתוכננים אירועים במארח שעלולים לשבש את הפעילות של הצמתים והמכונות הווירטואליות שמתחתיהם, וכשהאירועים האלה מתחילים. ההתראות כוללות מידע על שעת ההתחלה המתוכננת, סוג האירוע ופרטים נוספים.

ב-GKE בגרסה 1.31.1-gke.2008000 ואילך, אפשר לעקוב אחרי אירועי תחזוקה עתידיים, כולל האירועים שמתוארים בקטע הזה.

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

  • לסוגי מכונות עם מעבדי GPU או TPU מצורפים, גרסה 1.31.1-gke.2008000 ואילך
  • לסוגי מכונות Z3 עם יותר מ-18 TiB של SSD, ‫1.32.4-gke.1376000 ואילך
  • לסוגי מכונות H4D, גרסה 1.32.6-gke.1060000 ואילך
  • c4a-highmem-96-metal (תצוגה מקדימה), ‫1.35.0-gke.2232000 ואילך

תחזוקה עתידית מתוזמנת אבל לא פעילה

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

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

kubectl get nodes -l cloud.google.com/scheduled-maintenance-time \
    -L cloud.google.com/scheduled-maintenance-time

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

NAME                         STATUS    SCHEDULED-MAINTENANCE-TIME
<gke-accelerator-node-name>  Ready     1733083200
<gke-accelerator-node-name>  Ready     1733083200
[...]

העמודה SCHEDULED-MAINTENANCE-TIME מייצגת שניות, שמוצגות בפורמט של זמן ראשית יוניקס.

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

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

צמצום ההשפעה של שיבושים

מערכת Compute Engine שולחת התראות על אירועי תחזוקה קרובים וקובעת חלון זמן לתחזוקה. בין מועד ההתראה לבין מועד תחילת חלון זמן לתחזוקה, אתם יכולים להחליט אם:

  • הפעלה ידנית של אירוע תחזוקה של מארח.
  • מאפשרים ל-Compute Engine להתחיל את אירוע התחזוקה לפי התזמון.

הפעלה ידנית של אירוע תחזוקה של מארח

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

בצומת במאגר הצמתים, מגדירים את תווית הצומת cloud.google.com/perform-maintenance ל-true. לדוגמה:

kubectl label nodes <node-name> cloud.google.com/perform-maintenance=true

אם אתם מתחילים אירוע תחזוקה, GKE מבצע את הפעולות הבאות:

  1. הצומת מוכתם.
  2. מפנה Pods בצורה מסודרת.
  3. בקשות מ-Compute Engine להתחיל את אירוע התחזוקה באופן מיידי, במקום להמתין לשעה המתוכננת.

מערכת Compute Engine מתחילה את אירוע התחזוקה לפי לוח הזמנים

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

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

התחילה תחזוקה מתוזמנת

כשמתחילה תחזוקה מתוזמנת, מערכת Compute Engine מעדכנת את המטא-נתונים בספרייה http://metadata.google.internal/computeMetadata/v1/instance/attributes/. המערכת של Compute Engine מעדכנת את תוויות המטא-נתונים באופן הבא:

  • ההגדרה של maintenance-event היא TERMINATE_ON_HOST_MAINTENANCE.
  • ב-upcoming-maintenance, הערך של maintenance_status מוגדר ל-ONGOING.

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

הפעלת טיפול בשיבושים

apiVersion: v1
kind: ConfigMap
metadata:
  name: gke-disruption-handling
  namespace: kube-system
data:
  maintenance-experience.yaml: |
    gracefulTermination: true

כדי להפעיל את הטיפול בשיבושים, יוצרים קובץ בשם maintenance-config.yaml עם ה-ConfigMap הזה. מחילים את ה-ConfigMap על האשכול באמצעות הפקודה הבאה:

kubectl apply -f my-configmap.yaml

הגדרה של GKE להפסקת עומסי העבודה בצורה מסודרת

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

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

כדי להגדיר את תקופת ההמתנה לסיום התקין, מגדירים את תקופת ההמתנה לסיום (בשניות) בשדה spec.terminationGracePeriodSeconds במניפסט של ה-Pod. לדוגמה, כדי לקבל התראה אחרי 10 דקות, צריך להגדיר את השדה spec.terminationGracePeriodSeconds במניפסט של ה-Pod ל-600 שניות, באופן הבא:

    spec:
      terminationGracePeriodSeconds: 600

מומלץ להגדיר תקופת חסד לסיום המינוי שתהיה ארוכה מספיק כדי שכל המשימות הפעילות יסתיימו במסגרת הזמן של ההתראה. אם עומס העבודה שלכם משתמש במסגרת ML כמו MaxText,‏ Pax או JAX עם Orbax, עומסי העבודה יכולים לתעד את אות הכיבוי SIGTERM ולהפעיל תהליך של יצירת נקודת ביקורת. מידע נוסף זמין במאמר TPU Autocheckpoint.

תהליך סיום מבוקר

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

בתרשים זרימת העבודה הבא מוצג איך GKE מבצע סיום תקין של צומת כשיש השבתה צפויה של צומת:

  1. תוך 60 שניות, יקרו הדברים הבאים:
    1. רכיבי המערכת מחילים את תווית הצומת cloud.google.com/active-node-maintenance node label set to ONGOING כדי לציין שעומסי העבודה מופסקים.
    2. ‫GKE מחיל את ה-taint של הצומת כדי למנוע תזמון של Pods חדשים בצומת. הדחייה כוללת את המפתח cloud.google.com/impending-node-termination:NoSchedule. אנחנו ממליצים לא לשנות את עומסי העבודה כדי שיוכלו להתמודד עם ההרעלה הזו, כי ידוע על סיום שמתרחש.
  2. רכיב ה-maintenance-handler מתחיל להוציא את ה-Pods, קודם את ה-Pods של עומסי העבודה ואז את ה-Pods של המערכת (לדוגמה, kube-system).
  3. ‫GKE שולח אות כיבוי SIGTERM ל-Pods של עומסי עבודה שפועלים בצומת, כדי להודיע להם על כיבוי קרוב. אפשר להשתמש בהתראה הזו כדי לסיים משימות שמתבצעות כרגע. ‫GKE עושה כמיטב יכולתו כדי לסיים את הפעולה של ה-Pods האלה בצורה תקינה.
  4. אחרי שההוצאה מסתיימת, GKE מעדכן את הערך של התווית cloud.google.com/active-node-maintenance ל-terminating כדי לציין שהצומת מוכן לסיום.

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

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

אפשר לסנן את היומנים של GKE לפי האירועים הבאים של סיום תקין:

  • כשהמכונה הווירטואלית מזהה שיבוש בגלל סגירה קרובה של הצומת, כמו אירוע תחזוקה של מארח Compute Engine,‏ GKE מגדיר את הערך של cloud.google.com/active-node-maintenance ל-ONGOING כשעומדים להפסיק את עומסי העבודה, ול-terminating כשעומסי העבודה מסתיימים והצומת מוכן לסגירה.
  • כשמגבילים את התזמון של עומסי עבודה חדשים, GKE מחיל את cloud.google.com/impending-node-termination:NoScheduleההכתמה.

צמצום ההפרעות לעומסי עבודה פעילים באמצעות תחזוקה אופציונלית

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

יצירת מאגר צמתים חדש עם תחזוקה אופציונלית

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

gcloud beta container node-pools create NODE_POOL_NAME \
    --cluster CLUSTER_NAME \
    --accelerator ACCELERATOR_ARG \
    --machine-type MACHINE_TYPE \
    --num-nodes NODE_COUNT \
    --zone ZONE \
    --project=PROJECT_ID \
    --opportunistic-maintenance=node-idle-time=NODE_IDLE_TIME,min-nodes=MIN_NODES,window=WINDOW

מחליפים את הערכים הבאים:

  • NODE_POOL_NAME: שם מאגר הצמתים של GKE.
  • CLUSTER_NAME : השם של אשכול GKE.
  • NODE_IDLE_TIME : משך הזמן שבו צומת יכול להישאר במצב לא פעיל (כלומר, לא מופעלים עומסי עבודה שצורכים מאיץ) לפני שתופעל תחזוקה. הערך מייצג משך בשניות, עם עד תשע ספרות אחרי הנקודה העשרונית, ומסתיים בתו s, לדוגמה: 80000s.
  • MIN_NODES : מספר הצמתים המינימלי שצריך להיות זמין במאגר הצמתים. האפשרות הזו חוסמת את התחזוקה אם היא גורמת למספר הצמתים הפעילים להיות נמוך מהערך הזה, לדוגמה: 10.
  • WINDOW : חלון הזמן, בשניות, שבו אפשר להריץ תחזוקה אופציונלית. הערך מסתיים בתו s. לדוגמה, ערך של 14 ימים, או 1209600s, מציין שאפשר להפעיל תחזוקה אופציונלית רק בשבועיים שלפני תאריך התחזוקה המתוזמן. ערך של 28 ימים, או 2419200s, מאפשר להפעיל תחזוקה אופורטוניסטית בכל שלב במהלך חלון זמן לתחזוקה. חלון הזמן הזה לתחזוקת מארח ב-Compute Engine שונה מחלונות הזמן לתחזוקה ב-GKE, שקובעים מתי אפשר לבצע תחזוקה באשכול GKE ומוגדרים בנפרד.

דוגמה להגדרה של תחזוקה אופציונלית

לדוגמה: יש לכם מאגר צמתים עם ארבעה צמתים, וההגדרה של תחזוקה אופורטוניסטית מוגדרת לערך --opportunistic-maintenance=node-idle-time=600s,window=2419200s,min-nodes=3. במקרה כזה, יקרו הדברים הבאים:

  • node1 מריץ עליו עומס עבודה של GPU. הצומת הזה לא במצב סרק, ולכן הוא נדלג.
  • node2 לא פעיל במשך 60 שניות. הצומת הזה לא היה במצב סרק מספיק זמן, ולכן הוא נדלג.
  • node3 לא פעיל במשך 600 שניות. הצומת הזה עומד בדרישה של מצב בלי פעילות.
  • node4 לא פעיל במשך 600 שניות. הצומת הזה עומד בדרישה של מצב בלי פעילות.

גם node3 וגם node4 עומדים בדרישה של חוסר פעילות. עם זאת, רק אחד מהצמתים האלה יפעיל תחזוקה אופורטוניסטית כי הערך של האפשרות min-nodes מוגדר ל-3.

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

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

kubectl describe node NODE_NAME | grep node.gke.io/opportunistic-config

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

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

kubectl describe node NODE_NAME | grep node.gke.io/maintenance-state

אם הצומת מופעל על ידי תחזוקה אופורטוניסטית, ההערה maintenance-state תופיע כ-opportunistic-triggered true.

מגבלות

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

  • אפשר להשתמש בתכונה הזו רק עם מאגרי צמתים של GPU ו-TPU.
  • תחזוקה אופורטוניסטית לא תואמת להתאמה אוטומטית לעומס של אשכולות, כי ההתאמה האוטומטית לעומס כבר מצמצמת את מספר הצמתים בלי פעילות.
  • במאגרי צמתים של TPU עם כמה מארחים, הערך של ההגדרה min-nodes-per-pool צריך להיות 0 כי מאגרי הצמתים האלה הם אטומיים.
  • הגרסה המינימלית של GKE שנתמכת היא ‎1.33.3-gke.1118000.
  • יש תמיכה רק בתחזוקה מתוכננת שכוללת את can_reschedule=TRUE ההתראה.
  • כדי להשבית את התכונה הזו, צריך ליצור מחדש את מאגר הצמתים בלי הדגלים המתאימים. אפשר גם להשבית את התכונה באופן ידני בצמתים ספציפיים באמצעות cloud.google.com/opportunistic-disable=true.
  • במקרים נדירים, יכול להיות שהתחזוקה של צומת מסוים תימשך זמן רב יותר. לקוחות שמשתמשים בתכונה הזו עשויים לראות מספר קטן יותר של צמתים זמינים, עד לערך של ההגדרה min-nodes-per-pool, למשך תקופה מסוימת.

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