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

בדיקה צעד אחר צעד לשרת Docker שנגמר לו הדיסק: מוצאים אם לוגים, images, ‏build cache, ‏volumes או ה-journal של המערכת תופסים את המקום, ומפנים אותו בפקודות שאומרות מה הן מוחקות לפני שמריצים אותן.

פורסם ב-16 באוקטובר 2026

כשהדיסק של שרת Docker מתמלא, קונטיינרים נכשלים עם "no space left on device" ומסדי נתונים מפסיקים לכתוב, והרפלקס הרגיל, ‏docker system prune, מוחק דברים בלי לומר אם הם בכלל הסיבה. האשף הזה מוצא קודם מה מחזיק את המקום: לוגים של קונטיינרים, ‏images, ‏build cache, ‏volumes, מערכת הקבצים של קונטיינר עצמו, ה-journal של המערכת, קבצים שנמחקו ועדיין פתוחים, או inodes.

ענו על שאלה אחת בכל פעם. כל שלב מציג פקודה להרצה בשרת שלכם ומה הפלט שלה אומר; כל פקודה שמוחקת משהו אומרת מה היא מוחקת ומסומנת לפני שמריצים אותה. החליפו את <container>, ‏<service>, ‏<volume> ו-<mount> בשמות שלכם. העמוד לא מריץ שום דבר ולא שולח דבר לשום מקום; התשובות נשמרות בקישור של העמוד, אף פעם לא הפלט שלכם.

מוצאים את הסיבה, צעד אחר צעד

בפקודות, החליפו את ה-placeholders בסוגריים משולשים (<container>, <service>, <volume>, <mount>) בשמות שלכם. שום דבר לא רץ מהעמוד הזה.

שלב 1

איזו מערכת קבצים מלאה?

מתחילים מהמספרים שהקרנל מדווח לכל מערכת קבצים מחוברת. דיסק מלא מציג Use% של 100% או קרוב לזה, וכמעט כלום תחת Avail; אז קונטיינרים נכשלים עם no space left on device, מסדי נתונים מפסיקים לכתוב, ו-Docker עצמו עלול לסרב להפעיל קונטיינרים.

‏Docker שומר את הנתונים שלו תחת /var/lib/docker, אלא אם ה-data-root שלו הועבר; ברוב השרתים זו מערכת הקבצים הראשית /. אם לא בטוחים איפה זה, ‏docker info --format "{{.DockerRootDir}}" מדפיס את הנתיב, ובכל פקודה בהמשך מחליפים את /var/lib/docker בנתיב הזה.

הפקודה הזו רק קוראת.

להרצה בשרת שלכם
df -h
מה הפלט מראה?

כל השלבים כטקסט

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

הצגת כל השאלות, הבדיקות והפתרונות של האשף

איזו מערכת קבצים מלאה?

מתחילים מהמספרים שהקרנל מדווח לכל מערכת קבצים מחוברת. דיסק מלא מציג Use% של 100% או קרוב לזה, וכמעט כלום תחת Avail; אז קונטיינרים נכשלים עם no space left on device, מסדי נתונים מפסיקים לכתוב, ו-Docker עצמו עלול לסרב להפעיל קונטיינרים.

‏Docker שומר את הנתונים שלו תחת /var/lib/docker, אלא אם ה-data-root שלו הועבר; ברוב השרתים זו מערכת הקבצים הראשית /. אם לא בטוחים איפה זה, ‏docker info --format "{{.DockerRootDir}}" מדפיס את הנתיב, ובכל פקודה בהמשך מחליפים את /var/lib/docker בנתיב הזה.

פקודה

df -h

תשובות

  • מערכת הקבצים שמחזיקה את הנתונים של Docker (לרוב /) ב-100% או קרוב לזה: עוברים אל “המקום אצל Docker, בלוגים, או במקום אחר?”
  • רק מערכת קבצים אחרת מלאה (למשל /boot או /home): עוברים אל “המקום נמצא מחוץ ל-Docker”
  • אף אחת לא קרובה ל-100%, ובכל זאת כתיבה נכשלת עם "no space left on device": עוברים אל “האם נגמרו ה-inodes?”

האם נגמרו ה-inodes?

למערכת קבצים יש שתי מגבלות: בתים ו-inodes. כל קובץ וכל תיקייה תופסים inode אחד, וכשהם נגמרים אי אפשר ליצור קובץ חדש, גם כשיש גיגה-בתים פנויים. מיליוני קבצים קטנים (שכבות של images, ‏build cache, תיקיית cache של אפליקציה, קובצי session) גומרים את ה-inodes הרבה לפני שהם ממלאים את הבתים.

‏df -i מציג את אותן מערכות קבצים בספירת inodes; הסתכלו על IUse% במערכת הקבצים שבה הכתיבה נכשלת.

פקודה

df -i

תשובות

  • ‏IUse% ב-100% או קרוב לזה: עוברים אל “במערכת הקבצים נגמרו ה-inodes”
  • ‏IUse% רחוק מ-100%: עוברים אל “אף ענף לא התאים: אוספים את מה שצריך כדי להמשיך לחפור”

המקום אצל Docker, בלוגים, או במקום אחר?

לפני שמוחקים משהו, מוצאים מי מחזיק את המקום. הפקודה סוכמת את שלושת החשודים הרגילים: תיקיית הנתונים של Docker, זו של containerd (שבה ה-image store של containerd שומר את נתוני ה-images), ולוגי המערכת תחת /var/log. תיקייה שלא קיימת בשרת שלכם מדולגת בשקט.

השוו את הגדלים לעמודת Used ש-df -h הציג לאותה מערכת קבצים. ‏du קורא כל קובץ, ולכן בתיקייה גדולה זה יכול לקחת דקה.

פקודה

sudo du -sh /var/lib/docker /var/lib/containerd /var/log 2>/dev/null

תשובות

  • ‏/var/lib/docker (או /var/lib/containerd) מחזיק את רוב המקום התפוס: עוברים אל “איפה בתוך הנתונים של Docker?”
  • ‏/var/log מחזיק את רובו: עוברים אל “האם זה ה-journal של המערכת?”
  • ביחד הם מחזיקים הרבה פחות ממה ש-df מציג כתפוס: עוברים אל “מוצאים את התיקיות הגדולות ביותר”

מוצאים את התיקיות הגדולות ביותר

המקום נמצא מחוץ ל-Docker ומחוץ ללוגים. הציגו את התיקיות הגדולות ביותר במערכת הקבצים המלאה, שתי רמות לעומק; ‏-x משאיר את du באותה מערכת קבצים ולא סופר מערכות קבצים אחרות שמחוברות מתחתיה.

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

פקודה

sudo du -xh --max-depth=2 / 2>/dev/null | sort -h | tail -n 15

תשובות

  • תיקייה מחוץ ל-Docker ומחוץ ללוגים גדולה: עוברים אל “המקום נמצא מחוץ ל-Docker”
  • התיקיות מסתכמות בהרבה פחות מה-Used של df: עוברים אל “קבצים שנמחקו עדיין פתוחים”

איפה בתוך הנתונים של Docker?

תיקיית הנתונים של Docker מתחלקת לפי סוג: ‏containers מחזיקה את ההגדרות של כל קונטיינר ואת קובץ הלוג שלו, ‏overlay2 מחזיקה שכבות של images, את השכבות הניתנות לכתיבה של הקונטיינרים ואת ה-build cache, ו-volumes מחזיקה את הנתונים של volumes עם שם ובלי שם. הגדולה מביניהן מצביעה על הסיבה.

הפקודה מציגה את הרמה הראשונה של /var/lib/docker, מהקטנה לגדולה. אם המקום נמצא דווקא תחת /var/lib/containerd, נתוני ה-images וה-build cache נמצאים שם.

פקודה

sudo du -h --max-depth=1 /var/lib/docker | sort -h

תשובות

  • ‏containers הכי גדולה: עוברים אל “האם הלוגים של הקונטיינרים הם הסיבה?”
  • ‏overlay2 הכי גדולה, או שהמקום נמצא תחת /var/lib/containerd: עוברים אל “מה Docker עצמו סופר?”
  • ‏volumes הכי גדולה: עוברים אל “אילו volumes, והאם משתמשים בהם?”

האם הלוגים של הקונטיינרים הם הסיבה?

עם ה-logging driver ברירת המחדל json-file, ‏Docker כותב כל מה שקונטיינר מדפיס לקובץ ליד ההגדרות שלו, וכברירת מחדל הוא אף פעם לא מגלגל ולא מגביל את הקובץ הזה. קונטיינר פטפטן אחד יכול לכתוב גיגה-בתים ביום. ‏docker system df לא סופר את הקבצים האלה, ולכן קל לפספס אותם.

הפקודה רצה כ-root בתוך shell כי רק root יכול לקרוא את תיקיית הקונטיינרים; היא מציגה את חמשת קובצי הלוג הגדולים ביותר. שם התיקייה בכל נתיב הוא ה-ID המלא של הקונטיינר.

פקודה

sudo sh -c 'du -h /var/lib/docker/containers/*/*-json.log' | sort -h | tail -n 5

תשובות

  • קובץ *-json.log אחד או יותר גדולים: עוברים אל “הלוגים של הקונטיינרים לא עוברים רוטציה”
  • קובצי הלוג קטנים, או שאין כאלה (logging driver אחר): עוברים אל “מה Docker עצמו סופר?”

מה Docker עצמו סופר?

‏docker system df סוכם את האובייקטים של Docker עצמו בארבע שורות: ‏images, קונטיינרים (השכבות הניתנות לכתיבה שלהם), ‏volumes מקומיים וה-build cache. ‏RECLAIMABLE הוא מה שאף קונטיינר לא משתמש בו כרגע ואפשר להסיר.

בחרו את השורה שמחזיקה הכי הרבה. ‏RECLAIMABLE גדול ב-images או ב-build cache הוא המקרה הקל; שורת Containers גדולה אומרת שקונטיינר כותב למערכת הקבצים של עצמו במקום ל-volume.

פקודה

docker system df

תשובות

  • ‏Images, עם RECLAIMABLE גדול: עוברים אל “‏images ישנים ושלא בשימוש ממלאים את הדיסק”
  • ‏Build Cache: עוברים אל “ה-build cache ממשיך לגדול”
  • ‏Containers: עוברים אל “קונטיינר כותב למערכת הקבצים של עצמו”
  • ‏Local Volumes: עוברים אל “אילו volumes, והאם משתמשים בהם?”
  • אף שורה לא גדולה, או שה-images גדולים אבל שום דבר לא ניתן לפינוי: עוברים אל “אף ענף לא התאים: אוספים את מה שצריך כדי להמשיך לחפור”

אילו volumes, והאם משתמשים בהם?

‏volume חי יותר מהקונטיינר שיצר אותו: הסרת קונטיינר, או docker compose down בלי -v, משאירה את ה-volumes שלו במקום. לאורך חודשים, stacks של בדיקות וגרסאות ישנות משאירים volumes שאף קונטיינר לא משתמש בהם, וחלק מהם מחזיקים נתונים אמיתיים.

הצורה המפורטת מציגה כל volume עם הגודל שלו ועם LINKS, מספר הקונטיינרים שמשתמשים בו. ‏LINKS שהוא 0 אומר שאף קונטיינר, רץ או עצור, לא משתמש ב-volume כרגע; זה לא אומר שהנתונים בו חסרי ערך.

פקודה

docker system df -v

תשובות

  • ‏volumes גדולים עם LINKS 0 (אף קונטיינר לא משתמש בהם): עוברים אל “‏volumes שאף קונטיינר לא משתמש בהם”
  • את ה-volume הגדול משמש קונטיינר שאני מריץ: עוברים אל “הנתונים של שירות רץ ממשיכים לגדול”

האם זה ה-journal של המערכת?

בשרתים עם systemd, הדייר הגדול ביותר ב-/var/log הוא בדרך כלל ה-journal ב-/var/log/journal. הוא שומר את הפלט של כל שירות, וכברירת מחדל הוא יכול לגדול עד 10% ממערכת הקבצים (עד 4 GB ל-journal), ובדיסק קטן או מלא כבר זה מקום שצריך.

הפקודה מדפיסה כמה מקום תופסים קובצי ה-journal הפעילים והישנים. היא רק קוראת.

פקודה

sudo journalctl --disk-usage

תשובות

  • ה-journal תופס כמה גיגה-בתים: עוברים אל “ה-journal של המערכת גדול מדי”
  • ה-journal קטן; קבצים אחרים ב-/var/log גדולים: עוברים אל “קובצי לוג ב-/var/log לא עוברים רוטציה ולא נמחקים”

הלוגים של הקונטיינרים לא עוברים רוטציה

ה-driver ‏json-file שומר כל שורה שקונטיינר הדפיס מאז שנוצר. התיקון הקבוע הוא מגבלת גודל: ‏max-size ו-max-file ל-json-file, או ה-driver ‏local, שמגלגל ודוחס כברירת מחדל. מגבלה שמוגדרת ב-daemon.json חלה רק על קונטיינרים שנוצרים אחרי השינוי, ולכן צריך ליצור מחדש את הקונטיינרים הקיימים.

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

מה לעשות

  1. התאימו את ה-ID בנתיב של הלוג הגדול ביותר לשם של קונטיינר.

    פקודה

    docker ps -a --no-trunc --format "{{.ID}} {{.Names}}"
  2. קראו קודם את השורות האחרונות, והעתיקו את מה שייתכן שתצטרכו: השלב הבא מוחק אותן.

    פקודה

    docker logs --tail 200 <container>
  3. רוקנו את קובץ הלוג של הקונטיינר. זה מוחק את כל היסטוריית הלוג שלו; הקונטיינר ממשיך לרוץ ולכתוב לאותו קובץ.

    משנה את השרת

    sudo truncate -s 0 "$(docker inspect --format '{{.LogPath}}' <container>)"
  4. הגבילו את הלוגים לתמיד: הגדירו log-driver ל-local, או json-file עם log-opts של max-size (למשל 10m) ו-max-file (למשל 3), ב-/etc/docker/daemon.json, או לכל שירות תחת logging: בקובץ ה-Compose.
  5. אחרי שינוי daemon.json, הפעילו מחדש את Docker כדי שיקרא את הקובץ. כל הקונטיינרים נעצרים ועולים שוב (אלה שיש להם restart policy).

    משנה את השרת

    sudo systemctl restart docker
  6. צרו מחדש את הקונטיינרים כדי שהגדרות הלוג החדשות יחולו עליהם. נתונים ב-volumes נשארים; כל מה שקונטיינר כתב למערכת הקבצים של עצמו אובד.

    משנה את השרת

    docker compose up -d --force-recreate
  7. בדקו כמה מקום התפנה.

    פקודה

    df -h

‏images ישנים ושלא בשימוש ממלאים את הדיסק

כל docker pull של גרסה חדשה משאיר את הישנה. ‏image תלוי (<none> ברשימה) הוא גרסה ישנה שהתג שלה עבר הלאה; ‏image שלא בשימוש הוא כזה שאף קונטיינר, רץ או עצור, לא נוצר ממנו. עדכון stacks לאורך חודשים משאיר גיגה-בתים משניהם.

‏docker image prune מסיר רק images תלויים. עם -a הוא מסיר כל image שאף קונטיינר קיים לא משתמש בו, כולל כאלה שאולי תרצו שוב: הם לא אובדים לתמיד, רק נמשכים שוב בהפעלה הבאה, וזה דורש שה-registry יהיה זמין ושהתג עדיין יהיה קיים.

מה לעשות

  1. הציגו את ה-images ואת הגדלים שלהם.

    פקודה

    docker image ls
  2. הסירו images תלויים. זה מוחק רק גרסאות ישנות בלי תג.

    משנה את השרת

    docker image prune
  3. אם זה לא מספיק, הסירו כל image שאף קונטיינר לא משתמש בו. קונטיינרים עצורים שומרים על ה-images שלהם; ‏stack שהורדתם עם docker compose down ימשוך את ה-images שלו מחדש.

    משנה את השרת

    docker image prune -a
  4. בדקו כמה מקום התפנה.

    פקודה

    df -h

ה-build cache ממשיך לגדול

כל docker build ו-docker compose build שומרים את השכבות ואת הקבצים שהורדו ב-build cache, כדי שה-build הבא יהיה מהיר יותר. בשרת שבונה images בעצמו (‏CI runner, ‏deploy שבונה על השרת), ה-cache גדל עם כל שינוי, ורק ה-garbage collection שלו מגביל אותו.

הסרת build cache אף פעם לא נוגעת ב-images, בקונטיינרים או ב-volumes: ה-build הבא איטי יותר, כי הוא מתחיל בלי cache.

מה לעשות

  1. הציגו מה ה-cache מחזיק.

    פקודה

    docker buildx du
  2. הסירו cache שלא היה בשימוש בשבוע האחרון. זה מוחק build cache בלבד.

    משנה את השרת

    docker builder prune --filter until=168h
  3. או הסירו את כולו, אם הדיסק עדיין מלא.

    משנה את השרת

    docker builder prune -a
  4. שמרו עליו מעכשיו עם מגבלות ה-garbage collection של ה-builder ב-daemon.json (ההגדרות של builder.gc).
  5. בדקו כמה מקום התפנה.

    פקודה

    df -h

קונטיינר כותב למערכת הקבצים של עצמו

כל מה שקונטיינר כותב מחוץ ל-volumes שלו נכנס לשכבה הניתנת לכתיבה שלו תחת overlay2: העלאות, ‏cache, לוגים לקובץ, מסד נתונים בלי volume. הנתונים האלה גדלים כל עוד הקונטיינר קיים, ונמחקים יחד איתו, ולכן זו גם בעיית דיסק וגם סיכון לאובדן נתונים.

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

מה לעשות

  1. הציגו את הקונטיינרים עם הגודל של השכבה הניתנת לכתיבה שלהם (SIZE).

    פקודה

    docker ps -a -s --format "{{.Names}} {{.Size}}"
  2. בדקו אילו קבצים הגדול מביניהם הוסיף או שינה (A ו-C).

    פקודה

    docker diff <container> | head -n 50
  3. חברו את הנתיב הזה כ-volume בקובץ ה-Compose (‏volumes: של השירות), אחרי שהעתקתם ממנו כל מה שצריך עם docker cp.
  4. צרו מחדש את השירות עם ה-volume. השכבה הניתנת לכתיבה הישנה שלו, וכל קובץ בה, נמחקים.

    משנה את השרת

    docker compose up -d --force-recreate <service>
  5. הסירו קונטיינרים עצורים שכבר לא צריך. זה מוחק כל קונטיינר עצור ואת השכבה הניתנת לכתיבה שלו, לא volumes.

    משנה את השרת

    docker container prune
  6. בדקו כמה מקום התפנה.

    פקודה

    df -h

‏volumes שאף קונטיינר לא משתמש בהם

‏volume שלא בשימוש יכול להיות שאריות של נתוני בדיקה, או העותק היחיד של מסד נתונים שה-stack שלו למטה כרגע. הסרת volume מוחקת את הנתונים שלו לתמיד; שום פקודת Docker לא מחזירה אותם. הסתכלו בתוך כל אחד, וגבו את מה שאתם לא בטוחים בו לפני שאתם מסירים.

‏docker volume prune מסיר רק volumes אנונימיים שלא בשימוש (מאז Docker Engine 23); עם -a הוא מסיר גם כל volume עם שם שלא בשימוש. העדיפו להסיר לפי שם את ה-volumes שבדקתם.

מה לעשות

  1. הציגו את ה-volumes שאף קונטיינר לא משתמש בהם.

    פקודה

    docker volume ls --filter dangling=true
  2. בדקו איזה פרויקט Compose יצר volume (התוויות שלו) ומתי.

    פקודה

    docker volume inspect <volume>
  3. הסתכלו מה הוא מחזיק.

    פקודה

    sudo ls -la /var/lib/docker/volumes/<volume>/_data
  4. גבו כל volume שייתכן שתצטרכו את הנתונים שלו, לפני שאתם מסירים אותו.
  5. הסירו volume שבדקתם. הנתונים שלו נמחקים לתמיד.

    משנה את השרת

    docker volume rm <volume>
  6. או הסירו בבת אחת כל volume אנונימי שלא בשימוש. קונטיינרים שהופעלו בלי volume עם שם (‏image של מסד נתונים עם VOLUME) שומרים את הנתונים שלהם בדיוק ב-volumes כאלה: בדקו קודם את הרשימה שלמעלה.

    משנה את השרת

    docker volume prune
  7. בדקו כמה מקום התפנה.

    פקודה

    df -h

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

המקום שייך לאפליקציה שאתם מריצים: מסד הנתונים שלה, העלאות, מדיה, או גיבויים שהיא כותבת ל-volume של עצמה. שום דבר ב-Docker לא אמור להימחק כאן; הניקוי קורה באפליקציה (מדיניות שמירה, גיבויים ישנים, ‏vacuum של מסד הנתונים) או במתן דיסק גדול יותר לנתונים.

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

מה לעשות

  1. בדקו איזו תיקייה בתוך ה-volume גדולה.

    פקודה

    sudo du -h --max-depth=2 /var/lib/docker/volumes/<volume>/_data | sort -h | tail -n 10
  2. אם אלה גיבויים או ייצואים שהאפליקציה כותבת, העבירו אותם אל מחוץ לשרת והגדירו כמה מהם היא שומרת.
  3. אם זה מסד הנתונים עצמו, השתמשו בניקוי המתועד שלו (למשל הגדרות שמירה או vacuum), אף פעם לא rm על הקבצים שלו.
  4. אם הנתונים פשוט גדולים מהדיסק, תכננו דיסק גדול יותר או העברה של ה-data-root של Docker לדיסק כזה; האשף הזה לא מכסה הגדלת דיסק אצל ספק.

ה-journal של המערכת גדול מדי

ה-journal מוחק רשומות ישנות רק כשהוא מגיע למגבלה שלו, ומגבלת ברירת המחדל היא חלק ממערכת הקבצים, לא גודל קבוע. ‏vacuum מוחק את קובצי ה-journal הישנים ביותר עד לגודל שנותנים לו; הקובץ הפעיל נשמר, כך שהרשומות האחרונות נשארות.

אחר כך הגדירו מגבלה קבועה, כדי שה-journal לא יוכל למלא את הדיסק שוב: ‏SystemMaxUse= ב-/etc/systemd/journald.conf, שנכנס לתוקף אחרי הפעלה מחדש של journald.

מה לעשות

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

    משנה את השרת

    sudo journalctl --vacuum-size=500M
  2. הגבילו אותו: הגדירו SystemMaxUse=500M בחלק [Journal] של /etc/systemd/journald.conf.
  3. הפעילו מחדש את journald כדי שיקרא את המגבלה החדשה. הרישום נעצר לרגע.

    משנה את השרת

    sudo systemctl restart systemd-journald
  4. ודאו את הגודל.

    פקודה

    sudo journalctl --disk-usage

קובצי לוג ב-/var/log לא עוברים רוטציה ולא נמחקים

רוב השירותים שכותבים לוגים לקבצים סומכים על logrotate שישנה שם, ידחוס ובסוף ימחק קבצים ישנים. שירות בלי כלל logrotate, או כזה שמתעלם ממנו, מגדיל קובץ אחד בלי סוף; עותקים מגולגלים (.1, ‏.gz) מצטברים כשמספר העותקים שנשמרים גבוה.

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

מה לעשות

  1. הציגו את הקבצים והתיקיות הגדולים ביותר תחת /var/log.

    פקודה

    sudo du -ah /var/log 2>/dev/null | sort -h | tail -n 15
  2. מחקו לוגים מגולגלים ודחוסים שישנים מ-30 יום. הם נעלמים לתמיד.

    משנה את השרת

    sudo find /var/log -type f -name "*.gz" -mtime +30 -delete
  3. בדקו מה logrotate היה עושה, בלי לעשות את זה, כדי למצוא קובץ שאף כלל לא מכסה.

    פקודה

    sudo logrotate --debug /etc/logrotate.conf
  4. הוסיפו כלל לקובץ הזה ב-/etc/logrotate.d/ (עם size, ‏rotate ו-compress), או גרמו לשירות לכתוב ל-journal במקום.
  5. בדקו כמה מקום התפנה.

    פקודה

    df -h

קבצים שנמחקו עדיין פתוחים

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

‏lsof +L1 מציג קבצים פתוחים שכבר אין להם שם, עם התהליך שמחזיק כל אחד. הפעלה מחדש של התהליך הזה, או של הקונטיינר שהוא רץ בו, משחררת את המקום.

מה לעשות

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

    פקודה

    sudo lsof -nP +L1
  2. אם התהליך הוא שירות מערכת, הפעילו אותו מחדש. השירות נעצר לרגע.

    משנה את השרת

    sudo systemctl restart <service>
  3. אם הוא רץ בקונטיינר, הפעילו מחדש את הקונטיינר הזה.

    משנה את השרת

    docker restart <container>
  4. בפעם הבאה, רוקנו לוג שתהליך עדיין כותב אליו במקום למחוק אותו, או תנו ל-logrotate לטפל בו.
  5. בדקו כמה מקום התפנה.

    פקודה

    df -h

במערכת הקבצים נגמרו ה-inodes

‏inodes מתפנים רק במחיקת קבצים, ולכן התיקון הוא למצוא את התיקייה עם הכי הרבה קבצים. בשרת Docker זו הרבה פעמים overlay2 (הרבה images, או build cache עם הרבה שכבות קטנות); במקומות אחרים זה cache, תור דואר או קובצי session של אפליקציה.

אם הספירה נמצאת בתיקייה של Docker, הסרת images ו-build cache שלא בשימוש מפנה inodes באותה דרך שהיא מפנה בתים.

מה לעשות

  1. ספרו קבצים לכל תיקייה, שלוש רמות לעומק, במערכת הקבצים המלאה.

    פקודה

    sudo du --inodes -x --max-depth=3 / 2>/dev/null | sort -n | tail -n 10
  2. אם זה תחת /var/lib/docker: הסירו images תלויים (רק גרסאות ישנות בלי תג).

    משנה את השרת

    docker image prune
  3. וגם build cache שישן משבוע (רק build cache).

    משנה את השרת

    docker builder prune --filter until=168h
  4. אם זה במקום אחר, נקו את התיקייה הזו עם הכלי של האפליקציה שהיא שלה.
  5. בדקו שוב את ה-inodes.

    פקודה

    df -i

המקום נמצא מחוץ ל-Docker

‏Docker הוא לא מה שממלא את מערכת הקבצים הזו: זו תיקייה של המערכת או של משתמש, כמו גיבויים ישנים, הורדות, תיקיית בית, או kernels ישנים ב-/boot קטן. ‏prune של אובייקטים של Docker היה מוחק דברים בלי לפנות את המקום הזה.

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

מה לעשות

  1. הציגו את התיקיות הגדולות ביותר במערכת הקבצים המלאה; החליפו את <mount> בנקודת החיבור שלה מתוך df -h.

    פקודה

    sudo du -xh --max-depth=2 <mount> 2>/dev/null | sort -h | tail -n 15
  2. העבירו גיבויים וארכיונים ישנים אל מחוץ לשרת לפני שאתם מוחקים אותם כאן.
  3. ל-kernels ישנים ול-cache של חבילות, השתמשו במנהל החבילות של ההפצה שלכם.

אף ענף לא התאים: אוספים את מה שצריך כדי להמשיך לחפור

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

כל הפקודות כאן רק קוראות. ‏docker info מדפיס את הגדרות השרת בלי סודות; ובכל זאת עברו על כל פלט לפני ששולחים אותו למישהו.

מה לעשות

  1. מקום ו-inodes בכל מערכת קבצים.

    פקודה

    df -h && df -i
  2. הספירה של Docker עצמו, לכל image, קונטיינר ו-volume.

    פקודה

    docker system df -v
  3. איפה Docker שומר את הנתונים שלו, ומה ה-storage driver וה-logging driver שלו.

    פקודה

    docker info --format "{{.DockerRootDir}} {{.Driver}} {{.LoggingDriver}}"
  4. הגודל של התיקיות של Docker ושל המערכת.

    פקודה

    sudo du -sh /var/lib/docker /var/lib/containerd /var/log 2>/dev/null
  5. הודעות הקרנל מהשעה האחרונה (שגיאות של מערכת קבצים, חיבור מחדש לקריאה בלבד).

    פקודה

    journalctl -k --since "1 hour ago"

מה לא מכוסה כאן

האשף מכסה שרת Linux יחיד עם Docker Engine וה-storage ברירת המחדל overlay2. ‏Docker Desktop שומר את הנתונים שלו בתוך דיסק וירטואלי, ו-nodes של Kubernetes מנקים images ולוגים דרך ה-kubelet; שניהם עובדים אחרת. הגדלת דיסק או volume אצל ספק לא מכוסה.

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

מקורות

האופן שבו ANAROQ מתעד מקורות לעובדות שבעמודים שלו מתואר במתודולוגיה. למתודולוגיה

כל עמודי פתרון התקלות