paint-brush
כיצד לייעל את Kubernetes עבור תמונות Docker גדולותעל ידי@kksudo
היסטוריה חדשה

כיצד לייעל את Kubernetes עבור תמונות Docker גדולות

על ידי Kazakov Kirill10m2024/09/30
Read on Terminal Reader

יותר מדי זמן; לקרוא

🚀 אשפי Kubernetes, נמאס לכם לחכות שעות עד שהצמתים שלכם יתחממו? תאר לעצמך לקצץ את הזמן הזה לשניות בלבד! מאמר זה משנה את המשחק חושף כיצד להטעין טורבו את תהליך הפריסה של Kubernetes, אפילו עם תמונות מאסיביות של 3GB ו-1000 פודים. גלה את הרוטב הסודי שהופך את הביצועים של האשכול שלך מאיטיים לעל קוליים. אל תיתן לחימום איטי לעכב אותך - למד כיצד לחולל מהפכה בזרימת העבודה שלך ב-Kubernetes היום!
featured image - כיצד לייעל את Kubernetes עבור תמונות Docker גדולות
Kazakov Kirill HackerNoon profile picture
0-item

סקירה קצרה של הבעיה

יום אחד, במהלך עדכון מתוכנן של cluster k8s, גילינו שכמעט כל ה-POD שלנו (כ-500 מתוך 1,000) בצמתים חדשים לא הצליחו להתחיל, והדקות הפכו במהירות לשעות. מחפשים אותנו באופן פעיל אחר הסיבה לשורש, אך לאחר שלוש שעות, ה-PODS עדיין היו בסטטוס ContainerCreating .


Kubernetes תקוע ב-ContainerCreating

למרבה המזל, זו לא הייתה סביבת הפרוד וחלון התחזוקה נקבע לסוף השבוע. היה לנו זמן לחקור את הנושא ללא כל לחץ.

היכן כדאי להתחיל את החיפוש אחר סיבת השורש? האם תרצה ללמוד עוד על הפתרון שמצאנו? התחברו ותהנו!

פרטים נוספים על הבעיה

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


מעת לעת, תהליך התקליטור לוקח עד 3 שעות כדי למשוך את התמונות. עם זאת, הפעם זה היה תקוע לחלוטין, כי כמות ה-PODS במהלך שדרוג ה-EKS (משולב, כאשר אנו מחליפים את כל הצמתים באשכול) הייתה גבוהה מדי.


  • כל האפליקציות שלנו חיות ב-k8s (מבוסס EKS ). כדי לחסוך בעלויות שלנו עבור DEV env, אנו משתמשים במופעים נקודתיים.

  • אנו משתמשים בתמונת AmazonLinux2 עבור הצמתים.

  • יש לנו מספר רב של ענפי תכונה (FBs) בסביבת הפיתוח שנפרסים ברציפות באשכול Kubernetes שלנו. לכל FB יש סט יישומים משלו, ולכל אפליקציה יש סט תלות משלו (בתוך תמונה).

  • בפרויקט שלנו, כמעט 200 אפליקציות והמספר הזה הולך וגדל. כל אפליקציה משתמשת באחת מ-7 תמונות העגינה הבסיסיות בגודל של ~2 GB. הגודל המקסימלי הכולל של התמונה המאוחסנת בארכיון (ב- ECR ) הוא כ-3 GB.

  • כל התמונות מאוחסנות ב- Amazon Elastic Container Registry (ECR).

  • אנו משתמשים בסוג ברירת המחדל של gp3 EBS עבור הצמתים.


בעיות שהתמודדו

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

  • שגיאות ErrImagePull: ErrImagePull תכופות או נתקעות במצבי ContainerCreating , מה שמצביע על בעיות עם משיכת תמונה.

  • ניצול דיסק גבוה: ניצול הדיסק נשאר קרוב ל-100% במהלך תהליך משיכת התמונה, בעיקר בשל הקלט/פלט הדיסק האינטנסיבי הנדרש לביטול הדחיסה (למשל, "unpigz").

  • בעיות במערכת DaemonSet: חלק מה-DaemonSets של המערכת (כמו aws-node או ebs-csi-node ) עברו למצב "לא מוכן" עקב לחץ בדיסק, והשפיע על מוכנות הצומת.

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


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

לאחר חקירה מהירה, מצאנו שהבעיה העיקרית הייתה לחץ הדיסק על הצמתים על ידי תהליך unpigz . תהליך זה אחראי לביטול הדחיסה של תמונות ה-docker. לא שינינו את הגדרות ברירת המחדל עבור סוג עוצמת הקול gp3 EBS, כי לא מתאים למקרה שלנו.


תיקון חם לשחזור האשכול

כצעד ראשון, החלטנו לצמצם את מספר ה-PODs על הצמתים.

  1. אנו מעבירים את הצמתים החדשים למצב "קורדון".
  2. הסר את כל ה-PODS התקועות כדי להפחית את לחץ הדיסק
  3. הפעל אחד אחד את ה-PODs כדי לחמם את הצמתים
  4. לאחר מכן, אנו מעבירים צמתים מחוממים למצב רגיל ("unCordon")
  5. הסירו את כל הצמתים במצב תקוע
  6. כל ה-PODS התחילו להשתמש בהצלחה במטמון התמונות של Docker


עיצוב CI/CD מקורי

הרעיון המרכזי של הפתרון הוא לחמם את הצמתים לפני שתהליך התקליטור מתחיל על ידי החלק הגדול ביותר של תמונת ה-docker (שכבת התלות של JS), המשמשת כתמונת השורש של כל האפליקציות שלנו. יש לנו לפחות 7 סוגים של תמונות השורש עם התלות ב-JS, שקשורים לסוג האפליקציה. אז בואו ננתח את עיצוב ה-CI/CD המקורי.


בצינור ה-CI/CD שלנו, יש לנו 3 עמודים: צינור CI/CD מקורי

צינור CI/CD מקורי:

  1. בשלב Init it: אנחנו מכינים את הסביבה/משתנים, מגדירים את סט התמונות לבנייה מחדש וכו'...

  2. בשלב Build : אנו בונים את התמונות ודוחפים אותן ל-ECR

  3. בשלב Deploy : אנו פורסים את התמונות ל-k8s (פריסות עדכון וכו'...)


פרטים נוספים על עיצוב ה-CICD המקורי:

  • הסניפים המאפיינים שלנו (FB) התפצלו מהסניף main . בתהליך ה-CI, אנו תמיד מנתחים את סט התמונות ששונו ב-FB ובונים אותם מחדש. הענף main תמיד יציב, כהגדרה, צריכה להיות תמיד הגרסה העדכנית ביותר של תמונות הבסיס.
  • אנו בנפרד בונים את ה-JS dependencies docker images (עבור כל סביבה) ודוחפים אותם ל-ECR כדי לעשות בו שימוש חוזר בתור תמונת השורש (בסיס) ב- Dockerfile. יש לנו בערך 5-10 סוגים של תמונת ה-JS dependencies docker.
  • ה-FB נפרס לאשכול k8s למרחב השמות הנפרד, אבל לצמתים המשותפים ל-FB. ה-FB יכול לכלול ~200 אפליקציות, עם גודל התמונה של עד 3 GB.
  • יש לנו את מערכת ה-Cluster Autoscaling, אשר מדרגת את הצמתים באשכול בהתבסס על העומס או ה-PODS הממתינים עם ה-nodeSelector והסבילות בהתאם.
  • אנו משתמשים במופעי הנקודה עבור הצמתים.

יישום תהליך החימום

יש דרישות לתהליך החימום.

הֶכְרֵחִי:

  1. פתרון בעיה : מטפל ופותר בעיות ContainerCreating .
  2. ביצועים משופרים : מפחית באופן משמעותי את זמן האתחול על ידי שימוש בתמונות בסיס מחוממות מראש (תלות ב-JS).

נחמד שיש שיפורים:

  1. גמישות : מאפשרת שינויים קלים בסוג הצומת ובתוחלת החיים שלו (למשל, SLA גבוה או זמן חיים ממושך).
  2. שקיפות : מספק מדדים ברורים על שימוש וביצועים.
  3. יעילות עלות : חוסך בעלויות על ידי מחיקת ה-VNG מיד לאחר מחיקת ענף התכונה המשויך.
  4. בידוד : גישה זו מבטיחה שסביבות אחרות לא יושפעו.

פִּתָרוֹן

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


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

  1. צור את קבוצת הצמתים (Virtual Node Group) לכל FB

  2. הוסף תמונות בסיס לסקריפט של Cloud-init עבור הצמתים החדשים

  3. הוסף שלב של פריסה מוקדמת להפעלת ה-DaemonSet עם הקטע initContainers כדי להוריד את תמונות ה-docker הדרושות לצמתים לפני תחילת תהליך התקליטור.


צינור CI/CD מעודכן ייראה כך: צינור CI/CD מעודכן


צינור CI/CD מעודכן:

  1. התחל בשלב
    1.1.(שלב חדש) Init deploy : אם זו התחלה ראשונה של ה-FB, אז צור סט אישי חדש של מופעי הצומת (במונחים שלנו זה Virtual Node Group או VNG) והורד את כל תמונות הבסיס של JS (5–10 תמונות ) מהסניף הראשי. זה מספיק הוגן לעשות את זה, כי חילקנו את ה-FB מהסניף הראשי. נקודה חשובה, לא מדובר בפעולת חסימה.
  2. שלב לבנות
  3. שלב הפריסה מראש הורד תמונות בסיס JS אפויות טריות עם תג FB הספציפי מה-ECR.
    3.1.(שלב חדש) נקודות חשובות : זוהי פעולת חסימה, כי עלינו להפחית את לחץ הדיסק. בזה אחר זה, אנו מורידים את תמונות הבסיס עבור כל צומת קשור.
    אגב, תודה על שלב ה- init deploy , כבר יש לנו את תמונות ה-docker הבסיסיות מהסניף הראשי, כלומר נותנים לנו הזדמנות גדולה להיכנס למטמון בהתחלה הראשונה.
  4. **לִפְרוֹס
    **אין שינויים בשלב זה. אבל הודות לשלב הקודם, כבר יש לנו את כל שכבות התמונה הכבדות של docker על הצמתים הדרושים.

התחל את שלב הפריסה

צור קבוצה חדשה של צמתים עבור כל FB באמצעות קריאת API (למערכת קנה המידה האוטומטי של צד שלישי) מצינור ה-CI שלנו.


בעיות שנפתרו:

  1. בידוד : לכל FB יש קבוצה משלו של צמתים, מה שמבטיח שהסביבה לא מושפעת מ-FBs אחרים.

  2. גמישות : אנו יכולים לשנות בקלות את סוג הצומת ואת תוחלת החיים שלו.

  3. יעילות עלות : אנו יכולים למחוק את הצמתים מיד לאחר מחיקת ה-FB.

  4. שקיפות : אנו יכולים לעקוב בקלות אחר השימוש והביצועים של הצמתים (לכל צומת יש תג הקשור ל-FB).

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


הורד את כל תמונות הבסיס של JS מהסניף הראשי לצמתים החדשים באמצעות סקריפט cloud-init .


בזמן הורדת התמונות ברקע, תהליך התקליטור יכול להמשיך לבנות תמונות חדשות ללא בעיות. יתרה מכך, הצמתים הבאים (שייווצרו על ידי מערכת קנה מידה אוטומטי) מקבוצה זו ייווצרו עם הנתונים המעודכנים cloud-init , שכבר יש להם הוראות להורדת תמונות לפני ההתחלה.


בעיות שנפתרו:

  1. פתרון הבעיה : לחץ הדיסק נעלם, מכיוון שעדכנו את הסקריפט של cloud-init על ידי הוספת ההורדה של תמונות הבסיס מהסניף הראשי. זה מאפשר לנו להיכנס למטמון בהתחלה הראשונה של ה-FB.

  2. שימוש יעיל במופעי הנקודה : מופע הנקודה מתחיל בנתונים מעודכנים cloud-init . זה אומר שאחרי שהצומת הנקודתי מתחיל, יש כבר תמונות הבסיס על הצומת (מהענף הראשי).

  3. ביצועים משופרים : תהליך התקליטור יכול להמשיך לבנות תמונות חדשות ללא בעיות.


פעולה זו הוסיפה ~17 שניות (קריאת API) לצינור ה-CI/CD שלנו.

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

שלב פריסה מראש

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


המטרות של שלב הטרום-פריסה

  1. מניעת לחץ בדיסק : הורד ברצף את רוב התמונות הכבדות של Docker. לאחר שלב ה-init-deploy, כבר יש לנו את תמונות הבסיס על הצמתים, מה שאומר שיש לנו סיכוי גדול למטמון ההיט.

  2. שפר את יעילות הפריסה : ודא שהצמתים מחוממים מראש עם תמונות דוקר חיוניות, מה שמוביל לזמני הפעלה מהירים יותר (כמעט מיידי) של POD.

  3. שפר את היציבות : צמצם למינימום את הסיכוי להיתקל בשגיאות ErrImagePull / ContainerCreating והבטח שקבוצות הדמונים של המערכת נשארות במצב "מוכן".


בשלב זה, אנו מוסיפים 10-15 דקות לתהליך התקליטור.

פרטי שלב טרום הפריסה:

  • בתקליטור אנו יוצרים DaemonSet עם הקטע initContainers .
  • הקטע initContainers מבוצע לפני שהמכל הראשי מתחיל, ומבטיח שהתמונות הדרושות יורדו לפני שהמכולה הראשית מתחילה.
  • בתקליטור אנו בודקים ללא הרף את המצב של daemonSet. אם daemonSet נמצא במצב "מוכן", אנו ממשיכים בפריסה. אחרת, אנחנו מחכים שה-demonSet יהיה מוכן.

השוואה

השוואה בין השלבים המקוריים והמעודכנים לתהליך החימום מראש.

שָׁלָב

התחל את שלב הפריסה

שלב פריסה מראש

לִפְרוֹס

זמן כולל

הבדל

ללא חימום מוקדם

0

0

11 מ' 21 שניות

11 מ' 21 שניות

0

עם חימום מוקדם

8 שניות

58 שניות

25 שניות

1 מ' 31 שניות

-9 מ' 50


העיקר, זמן "הפריסה" השתנה (מהפקודה הראשונה להחלה למצב ריצה של התרמילים) מ-11 מ' 21 שניות ל-25 שניות. הזמן הכולל השתנה מ-11 מ' 21 שניות ל-1 מ' 31 שניות.

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


מַסְקָנָה זמן המשיכה

הבעיה העיקרית ContainerCreating נפתרה בתהליך החימום. כהטבה, הפחתנו משמעותית את זמן ההתחלה הקרה של ה-POD.
לחץ הדיסק נעלם, כי כבר יש לנו את תמונות הבסיס על הצמתים. מערכת daemonSets נמצאים במצב "מוכן" ו"בריא" (מכיוון שאין לחץ בדיסק), ולא נתקלנו בשגיאות ErrImagePull הקשורות לבעיה זו.


פתרונות אפשריים וקישורים


נ.ב.: ברצוני להודות לצוות הטכני הנהדר ב- Just ( https://www.linkedin.com/company/justt-ai ) על העבודה הבלתי נלאית והגישה היצירתית באמת לכל נושא שהם מתמודדים איתם. עִם. במיוחד, צעקה לרוני שרעבי, המוביל המעולה שאחראי על העבודה הנהדרת שהצוות עושה. אני מצפה לראות עוד ועוד דוגמאות נהדרות לאופן שבו היצירתיות שלך משפיעה על המוצר Justt.