תכנון התשתית ל-Agent Substrate ב-GKE

ב-Google Kubernetes Engine‏ (GKE) אתם יכולים לשנות את הגודל של אשכולות Agent Substrate ב-GKE כדי לתמוך בעומסי עבודה של סוכני AI עם בו-זמניות גבוהה, תוך צמצום עלויות המחשוב במצב חוסר פעילות. השילוב של מאגרי צמתים ייעודיים לתשתית המערכת עם ComputeClasses בהתאמה אישית ומאגרים זמניים למשאבי מחשוב מאפשר לכם לבודד רכיבי מערכת קריטיים, להפוך את החלופות של החומרה לאוטומטיות בסדרות מכונות של Compute Engine ולשמור על קיבולת זמינה של צומתי Worker.

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

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

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

  • מצב וגרסה של אשכול GKE: צריך להשתמש באשכול GKE Standard שבו גם מישור הבקרה וגם מאגרי הצמתים מריצים את גרסה 1.37 ואילך. אי אפשר להשתמש באשכולות GKE Autopilot עם Agent Substrate ב-GKE.
  • התקנה של Agent Substrate ב-GKE: צריך שתהיה לכם התקנה קיימת של Agent Substrate ב-GKE, או שאתם מתכננים להתקין את Agent Substrate ב-GKE עם בידוד צומת של תשתית המערכת. איך מתקינים את Agent Substrate ב-GKE

בחירת הגודל המתאים לאשכול Agent Substrate

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

הערכת שיאי עומס העבודה

אם אין לכם מדידות ייצור, אתם יכולים להעריך את מספר שיא של צופים בו זמנית ואת קצב החידוש לפי המספר הכולל של השחקנים הרשומים (total_actors), החלק הממוצע של השחקנים שפועלים בו-זמנית (average_active_fraction), מכפיל התנועה המתפרצת (burst_factor) ומשך הזמן הממוצע שבו שחקן נשאר פעיל בכל תור (average_seconds_active_per_resume):

peak_running_actors = total_actors × average_active_fraction × burst_factor
peak_resume_rate    = peak_running_actors / average_seconds_active_per_resume

לדוגמה, אם יש לכם 100,000 שחקנים בסך הכול, עם 10% פעילים בממוצע (10,000 שחקנים) ופקטור פרץ של 2, האשכול שלכם צריך לתמוך ב-20,000 שחקנים פעילים בשיא. אם כל Actor פועל במשך 100 שניות בממוצע לפני ההשעיה, כדי לשמור על השיא הזה נדרשים 200 חידושים בשנייה ו-200 השעיות בשנייה.

‫Agent Substrate ב-GKE לא משעה באופן אוטומטי שחקנים לא פעילים. האפליקציה או התזמורן צריכים להפעיל את ההשעיה.

הגדרת הגודל של מישור הנתונים

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

חישוב של פודים של Worker וצומתי GKE

כל Worker Pod ב-WorkerPool מארח כמה Actors. ‫Worker יכול לקבל Actor חדש כל עוד הוא מארח פחות Actors מהמגבלה שמוגדרת בדגל --max-actors בקונטיינר ateworker (ברירת המחדל היא 1000), ויש לו מספיק קיבולת מעבד וזיכרון כדי לעמוד במגבלות של ActorTemplate. במדריך הקוד הפתוח Right-sizing resources in the Agent Substrate API מוסבר איך המגבלות של Worker משפיעות על המגבלות של Actor.

מחשבים את מספר ה-Worker Pods הנדרש עם 20% קיבולת תזמון זמינה (הפקטור 0.8):

slots_per_worker = min(max_actors, worker_memory / actor_memory, worker_cpu / actor_cpu)
total_workers    = peak_running_actors / (slots_per_worker × 0.8)

בנוסחה הזו, ברירת המחדל של המשתנה max_actors היא 1000 (מוגדרת על ידי הדגל --max-actors). מפחיתים את הזיכרון שה-Worker שומר לתהליך שלו מהערך של worker_memory. במשאבים של WorkerPool מסוג microVM, צריך להוסיף לערך של actor_memory את התקורה של זיכרון ה-VMM (צג מכונה וירטואלית) לכל Actor, כפי שדווח על ידי ה-Worker, כי המיקום מחשיב את התקורה הזו כחלק מהקיבולת של ה-Worker.

עם Pod אחד של Worker לכל צומת, מספר ה-Workers שווה למספר צומתי העובדים ב-GKE. אל תקצו 100% מהמעבד (CPU) והזיכרון של הצומת שניתנים להקצאה ל-Worker Pod. השאירו קיבולת בכל צומת ל-atelet DaemonSet (במרחב השמות ate-system) ולתהליכי הרקע של מערכת GKE. ב-GKE Standard אפשר להשתמש בעד 65,000 צמתים לכל אשכול ועד 512 Pods לכל צומת. כברירת מחדל, המספר המקסימלי הוא 110 Pods לכל צומת (אפשר להגדיר את המספר באמצעות הדגל --max-pods-per-node), ולאשכולות גדולים יש דרישות נוספות.

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

כל השעיה של Actor כותבת קובץ snapshot לדיסק של הצומת המקומי בנתיב הספרייה /var/lib/ate. במצב SYNCHRONOUS, הסוכן atelet מעלה את קובץ ה-snapshot ל-Cloud Storage לפני שפעולת ההשעיה חוזרת. במצב ASYNCHRONOUS, הסוכן atelet מתזמן את ההעלאה ל-Cloud Storage אחרי עיכוב של בערך ערך הדגל --snapshot-upload-delay (ברירת המחדל היא 5m) מהרגע שבו נוצרת קובץ ה-snapshot. ‫Agent Substrate שומר במטמון את קובץ ה-snapshot האחרון בצומת למשך התקופה שהוגדרה בדגל --snapshot-detach-delay, שערך ברירת המחדל שלו הוא 30m. אם ה-Actor ממשיך לפעול בתוך החלון הזה, הוא מתוזמן לאותו צומת ומשוחזר מהדיסק המקומי במקום להוריד את קובץ ה-snapshot מ-Cloud Storage.

העריכו את גודל קובץ ה-snapshot הלא דחוס (snapshot_size) כמגבלת הזיכרון של ActorTemplate, בתוספת כל הנתונים שנכתבו למערכת הקבצים הבסיסית שניתנת לכתיבה או לספריות העמידות. טיפול בקבצים חסכוניים (sparse) ודחיסת zstd מקטינים את הגודל של קובץ ה-snapshot הדחוס (compressed_snapshot_size) שמועבר אל Cloud Storage וממנו, שבו Agent Substrate מאחסן עד שני קובצי snapshot לכל Actor (ה-snapshot הקודם וה-snapshot שנמצא בתהליך):

  • רוחב הפס המקסימלי של Cloud Storage (בכל כיוון): peak_resume_rate × compressed_snapshot_size
  • קצב העברת הנתונים המקסימלי של כתיבה לדיסק של צומת, לכל צומת: 2 × peak_resume_rate × snapshot_size / total_nodes (גם הורדות שחודשו וגם נקודות ביקורת מושהות כותבות לדיסק של הצומת).

דיסק האתחול של hyperdisk-balanced בנפח 100GiB‎ שמוגדר כברירת מחדל ב-GKE מספק ‎3,600 IOPS וקצב העברת נתונים של ‎290MiB/s (הביצועים שמוגדרים כברירת מחדל משתנים בהתאם לגודל הדיסק), מה שיכול להגביל את פעולות יצירת קובצי ה-snapshot במקרה של קלט/פלט כבד של אורחים. כשיוצרים מאגרים של צומתי עובדים, צריך לטעון דיסק ייעודי בנתיב הספרייה /var/lib/ate/snapshots או לשפר את הביצועים של דיסק האתחול באמצעות הדגלים --boot-disk-provisioned-iops ו---boot-disk-provisioned-throughput עם הפקודה gcloud container node-pools create.

בדיקת המכסה של Security Token Service

כל העברה של קובץ snapshot אל Cloud Storage או ממנו דורשת אסימון שמוגדר להיקף של ה-Actor, והרכיב ate-api-server מבקש אותו מ-Security Token Service (STS) API. הרכיב ate-api-server שולח בקשת STS אחת לכל Actor כל 20 עד 40 דקות (בדרך כלל בהפעלה מחדש הראשונה בחלון הזה) ומשתמש שוב באסימון עד 20 דקות לפני שהוא פג תוקף.

מכסת ברירת המחדל של STS Exchange token global requests היא 6,000 בקשות לדקה לכל פרויקט, והיא משותפת עם איחוד זהויות של עומסי עבודה ל-GKE:

  • מכסת STS נדרשת (בקשות לדקה): הערכה של עד פי 60 מהקצב המקסימלי של חידוש הפעולה של שחקנים שהעברת תמונת המצב האחרונה שלהם הייתה לפני יותר מ-20 דקות, בתוספת קיבולת לאיחוד זהויות של עומסי עבודה ל-GKE. אם אתם לא יודעים מהו השיעור הזה, השתמשו בנוסחה 60 × peak_resume_rate כחלופה. לדוגמה, כדי להמשיך 200 פעמים בשנייה, צריך עד 12,000 בקשות בדקה.
  • איך מגדילים את המכסה: מבקשים להגדיל את המכסה בדף Quotas & System Limits במסוף Google Cloud . העברות של תמונות מצב פועלות בלי להפעיל את Security Token Service API בפרויקט, אבל צריך להפעיל את ה-API כדי שהמכסה תופיע בדף Quotas & System Limits. מידע נוסף זמין במאמר מכסות ל-Exchange Token API ב-Security Token Service במסמכי התיעוד של איחוד זהויות של עומסי עבודה ל-GKE.

כוונון סוכן הצומת של atelet

‫atelet DaemonSet מריץ Pod אחד לכל צומת עובד כדי לשחזר את ה-Actors וליצור להם נקודות ביקורת. בכל Pod של atelet, הקונטיינר של objectstore-plugin דוחס ומעביר תמונות מצב אל Cloud Storage וממנו.

בטבלה הבאה מתוארות הגדרות הגודל העיקריות של מאגרי atelet ו-objectstore-plugin:

הגדרה ברירת מחדל הנחיות לגבי מידות
מעבד (CPU) וזיכרון של קונטיינר atelet ו-objectstore-plugin בקשות: ‎50 mCPU, זיכרון ‎128 MiB, ללא מגבלות מגדירים Burstable QoS בלי מגבלות זיכרון על ידי השמטת מגבלות הזיכרון בשני הקונטיינרים, כי הגעה למגבלת הזיכרון עוצרת את סוכן הצומת ומפסיקה את כל ההמשכים בצומת. מגדילים את הבקשות למעבד (CPU) ולזיכרון כך שיתאימו לשימוש המקסימלי שנמדד בצומת מלא בקצב החידוש המקסימלי, כדי ש-Worker Pods לא יצרכו משאבים שנדרשים לסוכן atelet.
הדגל --upload-memory-budget (מאגר objectstore-plugin) והדגל --snapshot-upload-workers (מאגר atelet) תקציב של 512 MiB; שני עובדי העלאה

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

  • מגדילים את הערך של הדגל --upload-memory-budget (ומגדירים את בקשת הזיכרון של מאגר objectstore-plugin כך שתהיה גבוהה מהתקציב הזה).
  • מגדילים את הערך של הדגל --snapshot-upload-workers.
הדגל --drain-timeout והשדה terminationGracePeriodSeconds ‫5 דקות (הדגל --drain-timeout); 330 שניות (השדה terminationGracePeriodSeconds) המדיניות קובעת כמה זמן הסוכן של atelet יסיים את השחזורים וההעלאות של תמונות המצב שמתבצעים כשה-Pod שלו נעצר במהלך ריקון או שדרוג של צומת. אם מגדילים את הערך של הדגל --drain-timeout בשביל קובצי snapshot גדולים, צריך להגדיל גם את הערך של השדה terminationGracePeriodSeconds ב-DaemonSet של atelet כדי שסוכן kubelet לא יעצור את סוכן atelet לפני שההעלאות יסתיימו.

הגדרת הגודל של רכיבי התשתית של המערכת ושל מסד הנתונים

לפריסות של רכיבי מערכת בלי שמירת מצב במרחב השמות ate-system שמתרחבות אופקית, מעריכים את מספר הרפליקות הנדרש עם קיבולת זמינה של 35% (הפקטור 0.65) בתוספת רפליקה אחת פנויה (+ 1) כדי להתמודד עם שיבושים בצומת:

replicas = ceil(peak_load / (capacity_per_replica × 0.65)) + 1

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

בטבלה הבאה מתוארים כללי המשאבים וההתאמה לעומס (scaling) של כל רכיב בתשתית המערכת:

רכיב כללי QoS ומשאבים שינוי קנה מידה וכוונון החיבור
נתב Ingress‏ (atenet-router) הגדרת Guaranteed QoS: מגדירים בקשות ומגבלות תואמות למעבד (CPU) ולזיכרון, כדי שזמן הריצה של Go יתאים את מספר ה-threads לתקציב המעבד של הקונטיינר. להגדיל את מספר הרפליקות באופן אופקי על סמך מספר הבקשות המקסימלי לשנייה של תעבורת נתונים נכנסת, התקורה של mTLS וגודל המטען הייעודי (payload) של הבקשות.
שרת API‏ (ate-api-server) הגדרת Guaranteed QoS: מגדירים בקשות ומגבלות תואמות למעבד (CPU) ולזיכרון, כדי שזמן הריצה של Go יתאים את מספר ה-threads לתקציב המעבד של הקונטיינר. משנים את קנה המידה של הרפליקות בהתאם לשיא של מחזורי ההשהיה וההמשך לשנייה (בערך 4 אלפיות השנייה של מעבד לכל מחזור השהיה והמשך) ולעומס החיפוש של בקשות Ingress. מגדירים במפורש את ההגדרה ateapi.postgres.poolMaxConns. כל רפליקה פותחת עד poolMaxConns + 6 חיבורים למסד הנתונים, והסכום של כל הרפליקות צריך להיות קטן מההגדרה max_connections של PostgreSQL.
מסד נתונים (PostgreSQL) הגדרת Burstable QoS עם זיכרון מובטח: מגדירים בקשות זיכרון ששוות למגבלות כדי לנעול את המטמון של shared_buffers בזיכרון ולמנוע פינוי בגלל חוסר בזיכרון (OOM). לא להגדיר מגבלות מעבד (CPU) כשמריצים בצומת ate-postgres ייעודי, כדי שהוויסות של מעבד הליבה לא יאט את פרצי ה-checkpoint וה-autovacuum. הגדלת קנה המידה של StatefulSet עם מופע יחיד באופן אנכי. מקצים מספיק מעבד (CPU) כדי להישאר מתחת ל-80% ניצול בעומס שיא, מספיק זיכרון RAM כדי לשמור במטמון את טבלת ה-Actor (כשהפרמטר shared_buffers מוגדר לכ-25% מהזיכרון), ו-StorageClass שמגובה ב-SSD שמוגדר בזמן ההתקנה עם ההגדרה ateapi.postgres.storageClass (לדוגמה, StorageClass של dynamic-rwo ב-C4 או ב-N4, או StorageClass של premium-rwo ב-C3 או ב-N2). מגדילים את הפרמטר max_connections ב-ConfigMap של postgres-config (הקובץ postgresql.conf) כך שיתאים לכל הרפליקות של ate-api-server.
שרת proxy לתעבורת נתונים יוצאת (atenet-egress) כללי משאבים: מגדירים בקשת מעבד (CPU) של 512mCPU (מגבלה של 8vCPU) ובקשת זיכרון של 512MiB (מגבלה של 1GiB). אם יש זמן אחזור ארוך יותר בתנועה יוצאת של Actor, צריך להגדיל את הבקשות והמגבלות. הגדלת מספר הרפליקות באופן אופקי על סמך תנועת הבקשות היוצאות של Actor.
בקר עובדים (ate-controller) כללי משאבים: שמירה על רפליקה אחת (ללא בחירת מנהיג). מגדירים בקשות למעבד (CPU) ולזיכרון על סמך שיא השימוש במהלך אירועים גדולים של הרחבה אופקית בהתאם לעומס (scale out) של WorkerPool. אם לוקח יותר מדי זמן לרשום פודים חדשים של Worker בציים גדולים, מגדילים את הערך של הדגל --worker-sync-concurrency (ברירת המחדל היא 2).
בקר אישורים (podcertificate-controller) כללי משאבים: פועל במרחב השמות podcertificate-controller-system כדי לחתום על אישורי mTLS של פודים חדשים של Worker לפני שהם יכולים לקבל שחקנים. אם יש לכם אלפי עובדים, הגדילו את הערכים של ההגדרה podcert.workersPerSigner (ברירת המחדל היא 0, ששומרת על ברירת המחדל של המניפסט של עובד אחד (1) לכל חותם), הדגל --kube-api-qps (ברירת המחדל היא 5) והדגל --kube-api-burst (ברירת המחדל היא 10).
ספק הזהויות (ate-idp-server) כללי משאבים: הצגת מסמך Discovery של OpenID Connect‏ (OIDC) ו-JSON Web Key Set‏ (JWKS) במרחב השמות ate-system כדי לאמת אסימוני JWT‏ (JSON Web Tokens) של Actor. מגדירים בקשות למעבד (CPU) ולזיכרון על סמך נפח השאילתות של JWKS בשיא. אם גורמים מסתמכים שולחים שאילתות לנקודת הקצה של JWKS בקצב בקשות גבוה בלי לשמור מפתחות במטמון, צריך להגדיל את מספר הרפליקות.
ספק פרטי הכניסה (k8s-credential-provider) כללי משאבים: פועלים במרחב השמות ate-system כשמופעלת הזרקת פרטי כניסה של Kubernetes Secret. הגדירו בקשות למעבד (CPU) ולזיכרון על סמך נפח הזרקת פרטי הכניסה היוצאת. הגדלת מספר הרפליקות באופן אופקי על סמך קצב הבקשות היוצאות של Actor שדורשות הזרקת פרטי כניסה של Kubernetes Secret בשרת ה-proxy של atenet-egress.

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

באשכולות בסביבת הייצור, תזמון של Actor עם שיעור נטישה גבוה ותנועת תמונות מצב בצומתי עובדים יכולים להתחרות ברכיבי תשתית המערכת על מעבד (CPU), זיכרון וקלט/פלט של דיסק. מפרידים את אשכול GKE לשלוש רמות נפרדות של מאגרי צמתים:

  • מאגר צמתים של מסד נתונים (תווית ate-postgres): מאגר צמתים ייעודי ל-StatefulSet של PostgreSQL, שבו מאוחסנים כל המטא-נתונים של Actor ו-Worker.
  • מאגר צמתים של תשתית המערכת (תווית ate-system-infra): מאגר צמתים ייעודי לשאר שירותי תשתית המערכת (הרכיבים atenet-router,‏ ate-api-server,‏ atenet-egress,‏ ate-controller,‏ ate-idp-server ו-k8s-credential-provider).
  • מאגרי צמתים של עובדים (WorkerPool): מאגרי צמתים עם התאמה דינמית של קנה המידה, שמנוהלים על ידי ComputeClasses בהתאמה אישית של GKE ומאגרים זמניים למשאבי מחשוב של GKE, כדי לארח ארגזי חול פעילים של Actor.

כשמתקינים את Agent Substrate ב-GKE, אפשר לבודד את רכיבי התשתית של מסד הנתונים והמערכת לצמתים ייעודיים באמצעות ההגדרה cordonSystemInfraComponents (או הדגל --cordon-system-infra-components). לפני ההתקנה, צריך ליצור את שני מאגרי הצמתים עם התוויות הנדרשות ועם NoSchedule taints:

# 1. Create the dedicated PostgreSQL node pool
gcloud container node-pools create ate-postgres-pool \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --node-locations=POSTGRES_ZONE \
    --machine-type=POSTGRES_MACHINE_TYPE \
    --num-nodes=1 \
    --node-labels=ate.dev/workloadType=ate-postgres \
    --node-taints=ate.dev/workloadType=ate-postgres:NoSchedule

# 2. Create the dedicated system infrastructure node pool
gcloud container node-pools create ate-system-infra-pool \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --machine-type=SYSTEM_INFRA_MACHINE_TYPE \
    --num-nodes=2 \
    --node-labels=ate.dev/workloadType=ate-system-infra \
    --node-taints=ate.dev/workloadType=ate-system-infra:NoSchedule

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

  • ‫CLUSTER_NAME: השם של אשכול GKE Standard.
  • ‫LOCATION: האזור או התחום של מישור הבקרה של האשכול ב-Compute Engine.
  • ‫POSTGRES_ZONE: אזור אחד של Compute Engine בשביל ה-StatefulSet של PostgreSQL עם רפליקה אחת. באשכול אזורי, מציינים אזור אחד בתוך האזור של האשכול, כדי שמאגר הצמתים יקצה צומת אחד באזור שבו ייווצר הדיסק הקבוע של ה-StatefulSet. באשכול אזורי, מציינים את האזור של האשכול.
  • ‫POSTGRES_MACHINE_TYPE: סוג המכונה של Compute Engine שמתאים לגודל של מכונת PostgreSQL.
  • ‫SYSTEM_INFRA_MACHINE_TYPE: סוג המכונה של Compute Engine שמתאים לרכיבי התשתית של המערכת (לדוגמה, סוג המכונה c3-standard-8).

באשכול אזורי, הדגל --num-nodes חל על כל אזור (לדוגמה, הגדרת הדגל --num-nodes=2 בשלושה אזורים יוצרת שישה צמתים בסך הכול). כדי למקם את מאגר הצמתים ate-system-infra-pool באזורים ספציפיים, מוסיפים את הדגל --node-locations.

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

טירגוט אוטומטי של חומרה באמצעות ComputeClasses בהתאמה אישית

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

בחירת סדרת מכונות של Compute Engine לפי זמן ריצה

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

  • סביבת זמן ריצה של MicroVM‏ (Cloud Hypervisor): מגדירים את השדה enableNestedVirtualization: true בעדיפויות של ComputeClass ומטרגטים סדרות מכונות של Compute Engine x86 שתומכות בווירטואליזציה מקוננת (כמו N4,‏ C3,‏ C4 או N2), או משתמשים בסוגי מכונות x86 ללא מערכת הפעלה, שמריצות KVM באופן מקורי ולא דורשות את השדה enableNestedVirtualization. אין תמיכה במכונות וירטואליות מבוססות-ARM ובסדרות מכונות שמפורטות בקטע מגבלות על וירטואליזציה בתצורה משולבת.
  • סביבת זמן הריצה gVisor: מתאימה לסדרות של מכונות x86 ב-Compute Engine למטרות כלליות או עם אופטימיזציה לצריכת מעבד (כמו N4,‏ C3,‏ C4 או N2) בלי וירטואליזציה בתצורה מקוננת. אי אפשר להשתמש ב-Agent Substrate ב-GKE בסדרות מכונות שפועלות על מיקרו-ארכיטקטורות מעורבות של מעבדים (כמו E2) ובמכונות וירטואליות שמבוססות על Arm. כל המשאבים מסוג WorkerPool שנבחרים על ידי ActorTemplate צריכים להיות עם אותה ארכיטקטורת מעבד (CPU).

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

כללי ComputeClass שנדרשים ל-Agent Substrate

כשיוצרים ComputeClass ל-Agent Substrate בצומתי עובדים ב-GKE, צריך לפעול לפי הכללים הבאים:

  • שימוש ב-ComputeClasses שמבוססים על צמתים: אל תשתמשו בחיוב שמבוסס על Pod (השדה podFamily), שלא תומך בווירטואליזציה בתצורה מקוננת.
  • אל תגדירו את השדה nodePoolConfig.sandbox.type: microvm: ההגדרה הזו מפעילה את סביבת זמן הריצה של Kata ל-GKE Sandbox בעומסי עבודה שמבוססים על Pod, ומחילה את ה-taint‏ sandbox.gke.io/runtime=microvm שמונע תזמון של Agent Substrate ב-GKE Workers. ‫Agent Substrate ב-GKE מנהל את זמן הריצה של ה-microVM שלו, ודורש רק וירטואליזציה בתצורה משולבת של Compute Engine בצמתים סטנדרטיים של מערכת הפעלה שמותאמת לקונטיינרים (סוג קובץ אימג' cos_containerd).
  • הגדרת Linux kernel sysctl לצפיפות גבוהה של ארגזי חול: אם צומת עובד מריץ יותר מ-800 ארגזי חול בו-זמנית, צריך להגדיל את מגבלות ה-Linux kernel למעקב אחר מערכת הקבצים (פרמטרים של fs.inotify.*) ולטבלת השכנים של Address Resolution Protocol (ARP) (פרמטרים של net.ipv4.neigh.default.gc_thresh*). ההגדרות האלה חלות רק על אשכולות שנוצרו על ידי תוכנת ההתקנה. כשמגדירים ComputeClasses בהתאמה אישית (באמצעות השדה priorityDefaults.nodeSystemConfig.linuxNodeConfig.sysctls) או יוצרים מראש מאגרי צמתים של עובדים (באמצעות הדגל --system-config-from-file), צריך להחיל את הערכים הבאים של sysctl:

    • fs.inotify.max_user_instances: 65536
    • fs.inotify.max_user_watches: ‏1048576
    • net.ipv4.neigh.default.gc_thresh1: ‏4096
    • net.ipv4.neigh.default.gc_thresh2: ‏16384
    • net.ipv4.neigh.default.gc_thresh3: 32768

    מידע נוסף על הגדרת הפרמטרים של הצומת sysctl זמין במאמר אפשרויות הגדרה של Sysctl.

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

פודים של MicroVM Worker מבקשים את המשאב המורחב ate.dev/kvm: 1, שמתפרסם על ידי הפלאגין של המכשיר atelet רק אחרי שהצומת מופעל והסוכן atelet מתחיל לפעול. בגלל שהקצאת הצמתים האוטומטית של GKE לא רואה את המשאב המורחב ate.dev/kvm בתבניות של צמתים שלא הוקצו, פוד של MicroVM Worker שנמצא בהמתנה לא יכול לגרום ל-GKE ליצור באופן אוטומטי מאגר צמתים חדש מאפס רפליקות בעצמו. עם זאת, אם במאגר הצמתים כבר יש לפחות צומת אחד פועל, GKE יכול להגדיל את מאגר הצמתים הזה.

בטבלה הבאה מוצגת השוואה בין הדפוסים הנתמכים לשינוי קנה המידה של משאבי WorkerPool של microVM ב-GKE:

דוגמת קוד איך זה עובד האם אפשר להקטין את קנה המידה ל-0 צמתים? האם יש חלופה עם כמה רמות עדיפות למקרים שבהם המשאב לא זמין? מתי כדאי להשתמש?
מאגרים שנוצרו באופן אוטומטי עם השדה minimumCapacity מגדיר את השדות nodePoolAutoCreation.enabled: true ו-minimumCapacity.targetNodeCount: 1 עם עדיפויות machineType מפורשות. לא (צומת חם אחד ממשיך לפעול) רק בהקצאה הראשונית של השדה minimumCapacity ברמת המחלקה. כדי להגדיר חלופה באמצע פרץ, צריך להגדיר את השדה minimumCapacity.targetNodeCount: 1 בכל רשומת חלופה בשדה spec.priorities[] (תוך שמירה על צומת חם אחד לכל עדיפות) אתם רוצים ליצור מאגר צמתים באופן אוטומטי, ולוודא שתמיד פועל לפחות צומת עובד אחד.
מאגרים שנוצרו באופן אוטומטי עם מאגרים זמניים למשאבי מחשוב משלב את השדה nodePoolAutoCreation.enabled: true עם CapacityBuffer פעיל או במצב המתנה, ש-PodTemplate שלו משמיט את המשאב המורחב ate.dev/kvm. השהיה למצב המתנה (לדוגמה, כ-8% מעלות המחשוב של צומת c3-standard-4 פועל עם דיסק אתחול של 100GiB כברירת מחדל) כן (פלייסהולדרים של מאגרים מפעילים חלופות של הקצאת צמתים אוטומטית (NAP) ברמות עדיפות שונות) אתם רוצים התאמה מהירה לעומס (פעיל למשך שנייה עד 4 שניות, או 20 עד 35 שניות כדי להמשיך את צומתי ההמתנה ו-50 עד 85 שניות עד שה-Workers החדשים יהיו מוכנים) עם עלות נמוכה במצב חוסר פעילות.
מאגרי צמתים שנוצרו מראש עם 0 צמתים ותוויות של תבניות צמתים יוצר מראש מאגרי צמתים עם התאמה אוטומטית לעומס (autoscaling) עם התווית clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 ומפנה אליהם בשדה spec.priorities[].nodepools של ComputeClass. כן (0 צמתים אמיתיים, ללא עלות מחשוב במצב חוסר פעילות) כן, במאגרי הצמתים שנוצרו מראש אתם רוצים צמצום הפעולה לאפס אמיתי בלי לשמור מאגרים זמניים למשאבי מחשוב.

דוגמה: ComputeClass עם השדה minimumCapacity

כשמשתמשים בשדה minimumCapacity, כל רשומה בשדה spec.priorities צריכה לציין שדה machineType מפורש במקום לציין רק את השדה machineFamily:

apiVersion: cloud.google.com/v1
kind: ComputeClass
metadata:
  name: substrate-microvm
spec:
  priorityDefaults:
    enableNestedVirtualization: true
    nodeSystemConfig:
      linuxNodeConfig:
        sysctls:
          fs.inotify.max_user_instances: 65536
          fs.inotify.max_user_watches: 1048576
          net.ipv4.neigh.default.gc_thresh1: 4096
          net.ipv4.neigh.default.gc_thresh2: 16384
          net.ipv4.neigh.default.gc_thresh3: 32768
  priorities:
  - machineType: n4-standard-4
  - machineType: c3-standard-4
  - machineType: n2-standard-4
  nodePoolAutoCreation:
    enabled: true
  minimumCapacity:
    targetNodeCount: 1
  nodePoolConfig:
    imageType: cos_containerd
  whenUnsatisfiable: DoNotScaleUp

כדי לטרגט WorkerPool ל-ComputeClass הזה, מוסיפים את השדה nodeSelector: {cloud.google.com/compute-class: substrate-microvm} לתבנית ה-Pod של WorkerPool.

כש-ComputeClass עובר בין סדרות שונות של מכונות x86 (למשל מ-N4 ל-C3 או ל-N2), כדי לשחזר תמונת מצב עמידה בנאמנות לזיכרון (מצב SNAPSHOT_FIDELITY_MEMORY) נדרש Worker שתכונות המעבד שלו הן קבוצת-על של תכונות המעבד של תמונת המצב. אם אין Worker תואם עם קיבולת, Agent Substrate משנמך את השחזור לרמת הדיוק של מערכת הקבצים ברמה הבסיסית (מצב SNAPSHOT_FIDELITY_ROOTFS), ששומרת על מערכת הקבצים ברמה הבסיסית ועל נתוני הנפח העמידים בזמן הפעלה מחדש של תהליכי ה-Actor.

דוגמה: התאמה מאפס עם מאגרי צמתים שנוצרו מראש עם 0 צמתים

  1. שומרים את ההגדרות של ליבת Linux בצפיפות גבוהה sysctl כקובץ system-config.yaml:

    linuxConfig:
      sysctl:
        fs.inotify.max_user_instances: '65536'
        fs.inotify.max_user_watches: '1048576'
        net.ipv4.neigh.default.gc_thresh1: '4096'
        net.ipv4.neigh.default.gc_thresh2: '16384'
        net.ipv4.neigh.default.gc_thresh3: '32768'
    
  2. יוצרים מראש את מאגרי הצמתים הראשיים והחלופיים של הווירטואליזציה בתצורה מקוננת ב-0 צמתים, עם הדגל --system-config-from-file=system-config.yaml והתווית clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096, כדי שהמידרוג האוטומטי של אשכולות GKE ידע שהמאגר הריק מספק את המשאב המורחב ate.dev/kvm:

    # Primary N4 pool (0 nodes)
    gcloud container node-pools create microvm-n4-pool \
        --cluster=CLUSTER_NAME \
        --location=LOCATION \
        --machine-type=n4-standard-4 \
        --enable-nested-virtualization \
        --system-config-from-file=system-config.yaml \
        --num-nodes=0 \
        --enable-autoscaling --total-min-nodes=0 --total-max-nodes=10 \
        --node-labels=cloud.google.com/compute-class=substrate-microvm-zero,clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 \
        --node-taints=cloud.google.com/compute-class=substrate-microvm-zero:NoSchedule
    
    # Fallback C3 pool (0 nodes)
    gcloud container node-pools create microvm-c3-pool \
        --cluster=CLUSTER_NAME \
        --location=LOCATION \
        --machine-type=c3-standard-4 \
        --enable-nested-virtualization \
        --system-config-from-file=system-config.yaml \
        --num-nodes=0 \
        --enable-autoscaling --total-min-nodes=0 --total-max-nodes=10 \
        --node-labels=cloud.google.com/compute-class=substrate-microvm-zero,clusterautoscaler-nodetemplate-resources.ate.dev/kvm=4096 \
        --node-taints=cloud.google.com/compute-class=substrate-microvm-zero:NoSchedule
    

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

    • ‫CLUSTER_NAME: השם של אשכול GKE Standard.
    • ‫LOCATION: האזור או התחום של האשכול ב-Compute Engine. הדגלים --total-min-nodes ו---total-max-nodes מגדירים את גבולות ההתאמה האוטומטית לעומס בכל מאגר הצמתים, ולא לכל אזור.
  3. מפנים למאגרים שנוצרו מראש לפי סדר העדיפויות ב-ComputeClass:

    apiVersion: cloud.google.com/v1
    kind: ComputeClass
    metadata:
      name: substrate-microvm-zero
    spec:
      nodePoolAutoCreation:
        enabled: false
      priorities:
      - nodepools:
        - microvm-n4-pool
      - nodepools:
        - microvm-c3-pool
      whenUnsatisfiable: DoNotScaleUp
    

    השדה priorityDefaults לא רלוונטי לעדיפויות שמשתמשות בשדה nodepools, כי הגדרות הצומת מגיעות ממאגרי הצמתים שנוצרו מראש. כמו בעדיפויות חלופיות שנוצרות באופן אוטומטי, אם מפעילים מחדש Actor בסדרת מכונות חלופית שתכונות המעבד שלה לא כוללות את כל תכונות המעבד של קובץ ה-snapshot, השחזור משתנמך למצב SNAPSHOT_FIDELITY_ROOTFS והתהליכים של ה-Actor מופעלים מחדש.

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

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

כשיש עלייה חדה בתנועה של Actor שחורגת מהקיבולת של ה-WorkerPool Pods שפועלים, ה-Worker Pods החדשים צריכים להמתין להקצאת צומת ב-Compute Engine, לאתחול הסוכן של atelet ולחימום מראש של נכסי ארגז החול לפני שהם יכולים לשרת את ה-Actors. מאגרים זמניים למשאבי מחשוב ב-GKE מעבירים את הקצאת הצמתים ואת החימום מראש של נכסי atelet מהנתיב הקריטי:

  • ‫מאגרים זמניים פעילים למשאבי מחשוב (אסטרטגיית buffer.x-k8s.io/active-capacity): צמתים שהוקצו מראש ממשיכים לפעול ולהיות מוכנים, כך שפודים חדשים של Worker מתוזמנים תוך שנייה עד ארבע שניות, בעלות ההפעלה המלאה של ה-VM ב-Compute Engine.
  • מאגרים זמניים למשאבי מחשוב במצב המתנה (אסטרטגיית buffer.gke.io/standby-capacity): הקצאת צמתים ומתן אפשרות לסוכן atelet לאתחל ולחמם מראש נכסי ארגז חול (הקובץ הבינארי runsc או תמונות Cloud Hypervisor ו-Kata) בדיסק במהלך חלון האתחול במצב המתנה לפני ש-GKE משעה את המכונות הווירטואליות של Compute Engine. חלון ברירת המחדל הוא חמש דקות (5m) והוא מוגדר על ידי ההערה buffer.gke.io/standby-capacity-init-time ב-CapacityBuffer. אם החימום המקדים של הנכס נמשך יותר מ-5 דקות, צריך להגדיל את הערך של ההערה הזו. כשיש עלייה חדה, GKE מפעיל מחדש את הצמתים שהושעו תוך 20 עד 35 שניות, והמוכנות מקצה לקצה של WorkerPool (תזמון פודים של Worker, הנפקת אישורי פודים ורישום קיבולת באמצעות הרכיב ate-api-server) מסתיימת תוך 50 עד 85 שניות. בזמן ההשעיה, משלמים רק על הזיכרון של המכונה הווירטואלית המושעית ועל האחסון של דיסק האתחול. לדוגמה, עלויות האחסון של צומת c3-standard-4 מושהה עם דיסק אתחול hyperdisk-balanced בנפח ברירת מחדל של 100GiB הן כ-8% מעלות המחשוב של צומת פעיל. האחוז המדויק משתנה בהתאם לצורת המכונה, לגודל דיסק האתחול ול-IOPS או לנפח הקלט/פלט שהוקצו.

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

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

כשמגדירים מאגרים זמניים למשאבי מחשוב ב-Agent Substrate ב-GKE, צריך לפעול לפי הכללים הבאים:

  • הגבלות על תצורת המכונה ב-Compute Engine למאגרי המתנה: אי אפשר להשהות מכונות של Compute Engine במכונות וירטואליות עם כונני SSD מקומיים, או בתצורות מכונה עם יותר מ-208GB זיכרון (כמו סוג המכונה c3-highmem-88 או תצורות Bare Metal). בצורות גדולות של צומתי עובדים או בצמתים עם כונני SSD מקומיים, השתמשו במאגרים זמניים פעילים למשאבי מחשוב במקום במאגרים זמניים במצב המתנה.
  • אל תפנו את השדה scalableRef ל-WorkerPool או לפריסת microVM עם 0 רפליקות:
    • הבקר GKE CapacityBuffer לא יכול לפתור משאב בהתאמה אישית (kind: WorkerPool) כשמאגר המשאבים מוגדל ל-0 רפליקות.
    • במשאבי WorkerPool של microVM, אל תפנו את השדה scalableRef לפריסה הבסיסית, כי תבנית ה-Pod של הפריסה כוללת את המשאב המורחב ate.dev/kvm: 1 (שמונע מהקצאת צמתים אוטומטית להרחיב אופקית מאגר ריק). במקום זאת, מגדירים מאגרים על ידי הפניה ל-PodTemplate (בשדה podTemplateRef) שבוחר את ה-ComputeClass בלי לבקש את המשאב המורחב ate.dev/kvm.
    • במשאבי gVisor WorkerPool (שלא מבקשים את המשאב המורחב ate.dev/kvm), אפשר להפנות את השדה scalableRef ישירות לפריסה הבסיסית של WorkerPool או להשתמש ב-PodTemplate.

דוגמה: Standby CapacityBuffer באמצעות PodTemplate

המניפסט הבא מגדיר PodTemplate ו-CapacityBuffer במצב המתנה, שפועלים במשאבים של מאגר WorkerPool ב-microVM או ב-gVisor:

apiVersion: v1
kind: PodTemplate
metadata:
  name: substrate-worker-buffer-template
  namespace: WORKERPOOL_NAMESPACE
template:
  spec:
    nodeSelector:
      cloud.google.com/compute-class: COMPUTE_CLASS_NAME
    containers:
    - name: buffer-placeholder
      image: registry.k8s.io/pause:3.9
      resources:
        requests:
          cpu: "WORKER_CPU_REQUEST"
          memory: "WORKER_MEMORY_REQUEST"
---
apiVersion: autoscaling.x-k8s.io/v1beta1
kind: CapacityBuffer
metadata:
  name: substrate-standby-buffer
  namespace: WORKERPOOL_NAMESPACE
spec:
  podTemplateRef:
    name: substrate-worker-buffer-template
  replicas: BUFFER_REPLICAS
  provisioningStrategy: buffer.gke.io/standby-capacity

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

  • ‫WORKERPOOL_NAMESPACE: מרחב השמות של Kubernetes של WorkerPool (לדוגמה, my-workerpool).
  • ‫COMPUTE_CLASS_NAME: השם של ה-ComputeClass המותאם אישית שאליו מטרגט ה-WorkerPool (לדוגמה, substrate-microvm).
  • ‫WORKER_CPU_REQUEST ו-WORKER_MEMORY_REQUEST: בקשות ה-CPU והזיכרון של Worker Pod יחיד ב-WorkerPool (לדוגמה, 2 מעבדי CPU ו-4Gi זיכרון בצומת עם 4 מעבדי vCPU), שמשאירות קיבולת בצומת לסוכן atelet ולתהליכי הרקע של מערכת GKE. התאמת הערכים האלה לבקשות של פוד עובד אחד עוזרת לוודא שכל רפליקה של מאגר זמני מקצה צומת עובד אחד במצב המתנה, במקום לארוז כמה פלייסהולדרים של מאגר זמני בצומת אחד.
  • ‫BUFFER_REPLICAS: מספר צומתי העובדים במצב המתנה שצריך להשאיר במצב של חימום מראש (לדוגמה, 4 צמתים).

כשמשתמשים במאגרים זמניים למשאבי מחשוב במצב המתנה, צריך להוסיף ל-DaemonSet של atelet טולרנטיות לטיינט buffer.gke.io/standby-capacity-node-suspended (באמצעות השדה operator: "Exists"), כדי שפודים חלופיים של atelet יוכלו להישאר מתוזמנים בצמתים מושהים במצב המתנה (לדוגמה, במהלך עדכון בהדרגה של DaemonSet). דוגמה להגדרת DaemonSet מופיעה במאמר טעינה מראש של תמונות במאגרי המתנה.

אם לכמה עומסי עבודה יש את אותו ComputeClass, צריך להוסיף טולרציות תואמות להפרדת עומסי עבודה ותוויות nodeSelector גם לתבנית WorkerPool Pod וגם ל-buffer PodTemplate, כדי ש-GKE יקצה צמתים ייעודיים עם טיינטים שעומסי עבודה אחרים לא תובעים. צריך גם להוסיף toleration תואם ל-DaemonSet של atelet כדי שסוכן atelet יוכל לתזמן בצמתים הייעודיים האלה. הוראות מפורטות להגדרה של מאגרים זמניים למשאבי מחשוב

ניהול אינטראקציות של שדרוגים ושל כלי התאמה אוטומטית לעומס (autoscaler)

בקטע הזה מוסבר איך לנהל עדכונים של atelet DaemonSet, אירועי צמצום אנכי בהתאם לעומס (scale down) של מידרוג אוטומטי באשכול ושדרוגים של צמתים בלי לשבש את הפעילות של Actors פעילים.

עדכון ה-DaemonSet של atelet עם מאגרי המתנה

צומתי מאגר הנתונים להחלפה במצב השעיה כוללים את הכתם buffer.gke.io/standby-capacity-node-suspended וכתם של חוסר נגישות בזמן ההשעיה, ולכן הסוכן kubelet בצומת מושעה לא יכול לאשר מחיקות של Pod. מוודאים שה-DaemonSet של atelet מאפשר את ה-taint של buffer.gke.io/standby-capacity-node-suspended (באמצעות השדה operator: "Exists"). גם עם הסבילות הזו, במהלך עדכון רגיל בהדרגה (rolling) של DaemonSet של atelet (עם השדה maxUnavailable: 1), פודים בצמתים מושהים נכנסים למצב Terminating ויכולים לחסום את התקדמות העדכון בצמתים פועלים.

לפני שמעדכנים את ה-DaemonSet של atelet באשכול עם צומתי המתנה מושהים, צריך לבצע אחת מהפעולות הבאות:

  • כדי שצומתי המתנה שלא ניתן להגיע אליהם לא ינצלו את תקציב העדכון, צריך להגדיר את השדה spec.updateStrategy.rollingUpdate.maxUnavailable ב-DaemonSet של atelet לערך שגדול מהמספר המקסימלי של צומתי המתנה מושהים.
  • לפני שמעדכנים את ה-DaemonSet של atelet, משנים באופן זמני את קנה המידה של הרפליקות של CapacityBuffer במצב המתנה ל-0 וממתינים עד שה-autoscaler של האשכול מסיר את כל הצמתים של מאגר הנתונים במצב המתנה שהושעו (בדרך כלל 10 עד 15 דקות). כדי לבדוק אם יש צמתים שעדיין מדווחים על סטטוס תנאי Suspended של True, מריצים את הפקודה הבאה:

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

הגנה על שחקנים פעילים במהלך צמצום אנכי בהתאם לעומס (scale down) ושדרוגים

מכיוון ש-Actors פעילים פועלים בתוך ארגזי חול שמנוהלים על ידי הסוכן atelet ולא כ-Pods נפרדים של Kubernetes, בקשות המעבד (CPU) והזיכרון של צומת עשויות להיראות נמוכות למגדיל קנה המידה האוטומטי של אשכול GKE, גם כש-Worker Pod באותו צומת מארח Actors פעילים. כשצומת מרוקן, הסוכן של kubelet שולח אות SIGTERM ל-Worker Pod, וה-Worker מעביר את האות SIGTERM לתהליך הראשי של כל מאגר של כל Actor שהוא מארח. לכל Actor פעיל יש עד 30 דקות להשעיה לפני שה-Worker מפסיק. נותנים לכל Actor עם שמירת מצב handler של SIGTERM שלא יוצא מהאות וקורא ל-method‏ SuspendActor עם המצב DURABILITY_MODE_SYNCHRONOUS. אם התהליך הראשי של Actor מסתיים בגלל האות SIGTERM, המצב שלא נשמר אובד באופן מיידי. אם ה-Worker Pod מפסיק לפעול בזמן שהוא עדיין מארח Actor פעיל, ה-Actor נכנס למצב ACTOR_STATE_CRASHED.

כדי לצמצם את ההפרעות במהלך אירועים של צמצום אנכי בהתאם לעומס (scale down) ושדרוגים של אשכולות GKE, כדאי ליישם את השיטות הבאות:

  • אל תשתמשו ב-VM במודל Spot לצומתי WorkerPool עם שמירת מצב, כי ההפקעה של VM במודל Spot מספקת רק 15 שניות עד 2 דקות של הודעת סיום לפני עצירת הצומת.
  • לתאם את הניקוז במתזמר כדי ש-Actors פעילים יסומנו בנקודות ביקורת ויושעו לפני ש-Worker Pods ייעצרו, או למנוע מה-autoscaler של האשכול לפנות Worker Pods פעילים (לדוגמה, באמצעות ההערה cluster-autoscaler.kubernetes.io/safe-to-evict: "false" Pod). אם מגדירים את ההערה safe-to-evict: "false" באופן סטטי בתבנית WorkerPool Pod, המידרוג האוטומטי של האשכול לא יצמצם את הצומת בזמן ש-Worker Pod מתוזמן בו – גם אם ה-Worker הזה מארח אפס שחקנים פעילים. כדי לשחרר צמתים לא פעילים, צריך לצמצם אנכית בהתאם לעומס (scale down) את הרפליקות של WorkerPool או לנהל את ההערה באופן דינמי. למידע נוסף על מחזור החיים של פינוי ה-Worker ועל שחזור של Actors שקרסו באמצעות השיטה RevertActor, קראו את הקטע בנושא פינוי במדריך של Agent Substrate API.
  • מגדירים שדרוגי מתח ב-GKE ובודקים את השדרוג בסביבה עם מגבלת משאבים, כדי שצומתי העובדים החדשים יוקצו לפני שצומתי העובדים הקיימים יבודדו וירוקנו.

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