פתרון בעיות שקשורות לאחסון ב-GKE

בעיות באחסון באשכולות Google Kubernetes Engine ‏ (GKE) יכולות להתבטא בדרכים שונות, החל מנקודות צוואר בקבוק בביצועים וכשלים בהרכבת נפחים, ועד לשגיאות בשימוש בסוגים ספציפיים של דיסקים עם סוגים מסוימים של מכונות. הבעיות האלה יכולות להשפיע על מצב האפליקציה, על שמירת הנתונים ועל תקינות העומס הכולל.

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

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

שגיאה 400: אי אפשר לצרף RePD למכונה וירטואלית שעברה אופטימיזציה

אי אפשר להשתמש בדיסקים לאחסון מתמיד אזורי עם מכונות מותאמות לצריכת זיכרון גבוהה (memory-optimized) או עם מכונות מותאמות לצריכת מעבד גבוהה (compute-optimized).

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

פתרון בעיות בביצועים של הדיסק

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

  • קובצי אימג' של Docker.
  • מערכת הקבצים של הקונטיינר עבור מה שלא מותקן כנפח (כלומר, מערכת הקבצים של שכבת העל), ולרוב כוללת ספריות כמו /tmp.
  • כרכים emptyDir שמגובים בדיסק, אלא אם הצומת משתמש ב-SSD מקומי.

ביצועי הדיסק משותפים לכל הדיסקים מאותו סוג דיסק בצומת. לדוגמה, אם יש לכם pd-standard דיסק אתחול בנפח 100GB ו-pd-standard PersistentVolume בנפח 100GB עם הרבה פעילות, הביצועים של דיסק האתחול יהיו כמו של דיסק בנפח 200GB. בנוסף, אם יש הרבה פעילות ב-PersistentVolume, זה משפיע גם על הביצועים של דיסק האתחול.

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

INFO: task dockerd:2314 blocked for more than 300 seconds.
fs: disk usage and inodes count on following dirs took 13.572074343s
PLEG is not healthy: pleg was last seen active 6m46.842473987s ago; threshold is 3m0s

כדי לפתור בעיות כאלה, כדאי לעיין במידע הבא:

  • חשוב לעיין בהשוואות בין סוגים של דיסקים לאחסון ולבחור סוג של דיסק מתמשך שמתאים לצרכים שלכם.
  • הבעיה הזו מתרחשת לעיתים קרובות בצמתים שמשתמשים בדיסקים קשיחים רגילים עם גודל של פחות מ-200 GB. כדאי להגדיל את גודל הדיסקים או לעבור ל-SSD, במיוחד עבור אשכולות שמשמשים לייצור.
  • מומלץ להפעיל SSD מקומי לאחסון זמני במאגרי הצמתים. האפשרות הזו יעילה במיוחד אם יש לכם קונטיינרים שמשתמשים לעיתים קרובות בנפחי emptyDir.

התקנת נפח אחסון מפסיקה להגיב בגלל ההגדרה fsGroup

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

Unable to attach or mount volumes for pod; skipping pod ... timed out waiting for the condition

כדי לוודא ששגיאת טעינה שנכשלה נובעת מההגדרה fsGroup, אפשר לבדוק את היומנים של ה-Pod. אם הבעיה קשורה להגדרה fsGroup, תראה את רשומת היומן הבאה:

Setting volume ownership for /var/lib/kubelet/pods/POD_UUID and fsGroup set. If the volume has a lot of files then setting volume ownership could be slow, see https://github.com/kubernetes/kubernetes/issues/69699

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

פעולות איטיות בדיסק גורמות לכשלים ביצירת Pod

מידע נוסף מופיע בבעיה מספר 4604 ב-containerd.

גרסאות הצמתים של GKE שהושפעו: 1.18, ‏ 1.19, ‏ 1.20.0 עד 1.20.15-gke.2100, ‏ 1.21.0 עד 1.21.9-gke.2000, ‏ 1.21.10 עד 1.21.10-gke.100, ‏ 1.22.0 עד 1.22.6-gke.2000, ‏ 1.22.7 עד 1.22.7-gke.100, ‏ 1.23.0 עד 1.23.3-gke.700, ‏ 1.23.4 עד 1.23.4-gke.100

דוגמאות לשגיאות שיוצגו ביומנים של k8s_node container-runtime:

Error: failed to reserve container name "container-name-abcd-ef12345678-91011_default_12131415-1234-5678-1234-12345789012_0": name "container-name-abcd-ef12345678-91011_default_12131415-1234-5678-1234-12345789012_0" is reserved for "1234567812345678123456781234567812345678123456781234567812345678"

צמצום הפגיעה

  1. אם יש כשלים ב-Pods, כדאי להשתמש ב-restartPolicy:Always או ב-restartPolicy:OnFailure ב-PodSpec.
  2. מגדילים את מספר פעולות הקלט/פלט בשנייה בדיסק האתחול (לדוגמה, משדרגים את סוג הדיסק או מגדילים את נפח הדיסק).

תיקון

הבעיה הזו תוקנה ב-containerd 1.6.0 ומעלה. גרסאות GKE עם התיקון הזה הן ‎1.20.15-gke.2100 ומעלה, ‎1.21.9-gke.2000 ומעלה, ‎1.21.10-gke.100 ומעלה, ‎1.22.6-gke.2000 ומעלה, ‎1.22.7-gke.100 ומעלה, ‎1.23.3-gke.1700 ומעלה ו-‎1.23.4-gke.100 ומעלה.

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

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

  • אם משנים אובייקט PersistentVolume ישירות, הערכים של PersistentVolume ו-PersistentVolumeClaim מתעדכנים לערך חדש, אבל גודל מערכת הקבצים לא משתקף בקונטיינר והוא עדיין משתמש בגודל הווליום הישן.

  • אם משנים ישירות אובייקט PersistentVolume, ואז מעדכנים את PersistentVolumeClaim כך שהשדה status.capacity מתעדכן לגודל חדש, יכול להיות שיהיו שינויים ב-PersistentVolume אבל לא ב-PersistentVolumeClaim או במערכת הקבצים של הקונטיינר.

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

  1. האובייקט PersistentVolume שהשתנה יישאר כמו שהוא.
  2. עורכים את האובייקט PersistentVolumeClaim ומגדירים את spec.resources.requests.storage לערך גבוה יותר מזה שהיה ב-PersistentVolume.
  3. מוודאים שהגודל של PersistentVolume השתנה לערך החדש.

אחרי השינויים האלה, kubelet אמור לשנות את הגודל של PersistentVolume, ‏ PersistentVolumeClaim ומערכת קבצים של קונטיינר באופן אוטומטי.

בודקים אם השינויים משתקפים ב-Pod.

kubectl exec POD_NAME  -- /bin/bash -c "df -h"

מחליפים את POD_NAME ב-Pod שמצורף ל-PersistentVolumeClaim.

סוג המכונה שנבחר צריך לכלול SSD מקומי

יכול להיות שתיתקלו בשגיאה הבאה כשתיצרו אשכול או מאגר צמתים שמשתמשים ב-SSD מקומי:

The selected machine type (c3-standard-22-lssd) has a fixed number of local SSD(s): 4. The EphemeralStorageLocalSsdConfig's count field should be left unset or set to 4, but was set to 1.

בהודעת השגיאה, יכול להיות שיוצג LocalNvmeSsdBlockConfig במקום EphemeralStorageLocalSsdConfig, בהתאם למה שציינתם.

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

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

Hyperdisk Storage Pools: Cluster or node pool creation fails

יכול להיות שתיתקלו בשגיאה ZONE_RESOURCE_POOL_EXHAUSTED או בשגיאות דומות במשאבי Compute Engine כשאתם מנסים להקצות דיסקים מסוג Hyperdisk Balanced כדיסקים לטעינת המערכת או כדיסקים מצורפים לצומת בHyperdisk Storage Pool.

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

  • יכול להיות שאין מספיק דיסקים מסוג Hyperdisk Balanced באזור.
  • יכול להיות שאין באזור מספיק קיבולת ליצירת הצמתים של סוג המכונה שציינתם, כמו c3-standard-4.

כדי לפתור את הבעיה:

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

זוהה לחץ גבוה על אחסון הצמתים

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

כשמתארים צומת באמצעות הפקודה kubectl describe node NODE_NAME, יכול להיות שיוצג אירוע דומה לזה:

Events:
  Type     Reason                      Age   From                     Message
  ----     ------                      ----  ----                     -------
  ...
  Warning  StoragePressureDetected     46m   device-capacity-monitor  Node condition StoragePressureRootFileSystem is now: True, reason: StoragePressureDetected, message: "Disk /dev/nvme0n1 usage 89% exceeds threshold 85%"

הסיבה:

הסיבה StoragePressureDetected מציינת שהשימוש בדיסק במערכת הקבצים הבסיסית של הצומת (לרוב mnt/stateful_partition או נקודות טעינה קשורות) חרג מסף מוגדר מראש (לדוגמה, 85%). הסיבות האפשריות לכך:

  • עומסי עבודה שכותבים נתונים בכמות מוגזמת לנפחי אחסון מסוג emptyDir שלא מגובים על ידי כונני SSD מקומיים.
  • תמונות גדולות של קונטיינרים נמשכות אל הצומת.
  • קבצים של יומן רישום מצטברים בצומת.
  • תהליכים אחרים שצורכים שטח דיסק.

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

ניפוי באגים ופתרון בעיות:

זיהוי השימוש בדיסק: משתמשים ב-SSH כדי להתחבר לצומת המושפע ומשתמשים בפקודות כמו df -h כדי לבדוק את השימוש בדיסק בנקודות טעינה שונות, תוך שימת לב ל-/mnt/stateful_partition ולכל נקודות הטעינה של אחסון זמני.

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

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

  • שימוש בדיסקים גדולים יותר לאתחול: כשיוצרים מאגרי צמתים, בוחרים גודל גדול יותר של דיסק לאתחול אם עומסי העבודה דורשים יותר אחסון זמני במערכת קבצים בסיסית.
  • שימוש בכונני SSD מקומיים גדולים יותר לאחסון זמני: כדי להריץ עומסי עבודה שדורשים אחסון זמני עם ביצועים גבוהים וזמן אחזור נמוך, צריך להגדיר את מאגרי הצמתים לשימוש בכונני SSD מקומיים. כך אפשר להשתמש בנפח גדול יותר של emptyDir.
  • התאמת הבקשות או המגבלות של עומס העבודה: מוודאים שמפרטי ה-Pod כוללים בקשות ומגבלות מתאימות של אחסון זמני, כדי לעזור למתזמן למקם את ה-Pods בצמתים עם מספיק מקום ולמנוע שימוש לא מבוקר בדיסק.
  • ניקוי משאבים שלא בשימוש: אם קבצים מיותרים, תמונות ישנות של קונטיינרים או יומנים תורמים לשימוש הגבוה בדיסק, צריך להסיר אותם מהצומת.

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

פתרון בעיות שקשורות לאירועי חוסר זיכרון (OOM) ב-Cloud Storage FUSE

אם יש לכם Pods עם ניצול גבוה של הזיכרון או אירועים של חוסר זיכרון (OOM) שקשורים למנהל התקן ה-CSI של Cloud Storage FUSE, אתם יכולים לאסוף ולנתח תמונות מצב של המעבד והזיכרון באמצעות Cloud Profiler. הגדרת האפשרויות האלה מוסברת במאמר הגדרת קונטיינר ה-sidecar של מנהל התקן ה-CSI של Cloud Storage FUSE.

כשמתרחש OOM kill ב-Pod, אפשר לבצע קורלציה בין האירוע לבין תמונת המצב הנכונה ב-Cloud Profiler באמצעות תהליך העבודה הבא:

  1. בדיקה ב-Cloud Logging: עוברים אל Cloud Logging כדי למצוא את אירוע ה-OOM של Kubernetes.
  2. סינון לפי שם ה-Pod: מריצים את השאילתה הבאה כדי לאתר את יומני האירועים של ה-Pod הספציפי, ומחליפים את POD_NAME בשם ה-Pod של עומס העבודה:

    jsonPayload.involvedObject.name="POD_NAME"
    jsonPayload.involvedObject.kind="Pod"
    OOMKilled
    
  3. שליפת ה-UID של ה-Pod: מרחיבים את יומן האירועים הרלוונטי של OOM ורושמים את חותמת הזמן ואת ה-UID המדויק של ה-Pod שנמצא ב-jsonPayload.involvedObject.uid.

  4. ניתוח ב-Cloud Profiler: עוברים אל Cloud Profiler, מסננים את גרסת השירות באמצעות הפורמט POD_NAME_POD_UID ומשנים את טווח הזמן כך שיתאים לחותמת הזמן של שגיאת ה-OOM. כך תוכלו לוודא שאתם בודקים את פרופיל הזיכרון המדויק של מופע הקונטיינר הספציפי ממש לפני שהוא הופסק.

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