Blog von Thomas Puppe, Web Developer.

Inodes im Linux: Volle Festplatte, obwohl noch Platz ist?

Kürzlich fiel mein Bundestwitter-Server aus. Bei der Suche nach der Ursache habe ich einige neue Dinge über Linux gelernt, die ich hier dokumentieren möchte.

Die Tweet-Sammel-Cronjobs auf meinem Linux (Ubuntu) Server meldeten sich, dass sie keine Daten mehr schreiben könnten. Ich kenne das Problem schon, wenn zu viele Logs und Backups herumliegen ohne aufgeräumt zu werden.

Diesmal allerdings sagt df -h, es sei noch ordentlich Platz auf der Platte frei:

Size    Used    Avail    Use%
 77G     50G      28G    65%

Nach kurzer Recherche stieß ich darauf, dass nicht nur der Platz auf der Festplatte begrenzt ist, sondern auch die maximale Zahl der Dateien. Wikipedia sagt:

Die Anzahl der möglichen Inodes und somit der möglichen Dateien ist bei manchen Dateisystemen beschränkt; wird die Maximalanzahl erreicht, lassen sich keine weiteren Dateien anlegen.

Wikipedia: Inode

Also: df -i.

 Inodes      IUsed   IFree    IUse%
1000000    1000000       0     100%

Eine Lösung könnte darin bestehen, die Festplatte neu zu formatieren und die Zahl der möglichen Inodes höher festzulegen. Ob das bei meinem 1und1 VirtualServer so einfach möglich ist, ist fraglich. Zunächst möchte ich aber wissen, wo diese vielen Dateien liegen und woher sie kommen. Bundestwitter legt zwar viele Logfiles für Tweets an, aber diese werden regelmäßig gepackt, heruntergeladen und vom Server gelöscht. Sie erklären die volle Platte vermutlich nicht.

Ich suche also einen Befehl, der mir zeigt, in welchen Verzeichnissen viele Inodes verbraucht werden. Google ist mein Freund:

find /var/www/ -xdev -printf '%h\n' | sort | uniq -c | sort -k 1 -n

... listet alle Folder und subfolder mit der Zahl ihrer enthaltenen Inodes auf. Was ggf. sehr lang wird — in meinem Fall knapp 2000 Einträge:

1       /var/www/blog_thomaspuppe_de/assets
[... 2000 weitere Einträge ...]
2563    /var/www/bundestwitter/cache/www_bundestwitter_de/connectionStatistics

Das hilft also nur bei überschaubarer Ordnertiefe. Besser ist dieser Befehl, der die Anzahl der Inodes in einem Verzeichnis (oder in jedem Unterverzeichnis) zeigt:

for i in /var/www/*; do echo $i; find $i | wc -l | sort ; done (ohne "/*" für das einzelne Verzeichnis):

104      /var/www/blog_thomaspuppe_de
76266    /var/www/bundestwitter
2        /var/www/html
1371     /var/www/lab_thomaspuppe_de
32748    /var/www/socialmediapolitik
2        /var/www/thomas_works
3        /var/www/www_meetingtimer_biz
101      /var/www/www_thomaspuppe_de

Es zeigt sich, dass Bundestwitter nicht der Verursacher ist. Aber mit dem genannten Befehl kann ich nun die Ordner des Root-Verzeichnisses auflisten ...

sudo su #(um sich eine Menge "Permission denied" Meldungen zu sparen)
for i in /*; do echo $i; find $i | wc -l | sort ; done

... zeigt, dass die allermeisten Inodes in /var verbraucht werden. (Warum in proc so viel los ist, wird Gegenstand einer anderen Untersuchung sein.)

16        /home
22271     /proc
29687     /usr
953965    /var

Von hier aus kann ich mich mit dem Befehl for i in /var/*; do echo $i; find $i | wc -l | sort ; done usw. fortbewegen.

662       /var/log
836952    /var/spool
112120    /var/www

In /var/spool liegt also sehr viel Zeugs. Dies ist das "Verzeichnis für abzuarbeitende Warteschlangen (Druckaufträge, E-Mail-Versandaufträge …)" (Wikipedia).

Mit der bekannten Technik taste ich mich weiter voran und stoße auf ein Verzeichnis, in dem fast alle Dateien liegen:

836836    /var/spool/postfix/maildrop

Das sind also felgeschlagene Versuche des Systems, E-Mails zu versenden. Stichproben (cat /var/spool/postfix/maildrop/D7E6A90D4CA9) ergeben, dass meine Cronjobs versuchen, Mails zu versenden.

Ich habe also meinen Übeltäter. Nun geht es ans Aufräumen.

Die erste Maßnahme, für den Seelenfrieden, ist natürlich

sudo rm -rf /var/spool/postfix/maildrop/*
bash: /bin/rm: Argument list too long

Eine schnelle Suche führt mich auf`sysadminslife.com, wo folgender Befehl vorgeschlagen wird:

find -type f -print0 | xargs -0 rm

An der Stelle möchte ich Explainshell erwähnen. Eine Website, die Shell-Befehle aufdröselt und die einzelnen Bestandteile erklärt. http://explainshell.com/explain?cmd=find+-type+f+-print0+%7C+xargs+-0+rm

Ta dah:

$ ls /var/spool/postfix/maildrop | wc -l
14

$ df -i
Inodes      IUsed     IFree    IUse%
1000000    143491    856509      15%

Es bleibt die Frage: Wie vermeide ich, dass die Ausführung der Cronjobs Mails erzeugt (die dann in der Spool Queue landen)?

http://www.cyberciti.biz/faq/disable-the-mail-alert-by-crontab-command/:

The crontab command is used to maintain crontab files for individual users. By default the output of a command or a script (if any produced), will be email to your local email account.

Die einfachste Methode, dies zu verhindern, ist die Zeile MAILTO="" an den beginn der Crontab-Datei (crontab -e) zu schreiben. Damit werden alle Cron-Mails aus diesr Datei unterdrückt. Alternativ kann man auch pro Zeile den Versand von Mails verhintern durch den Output nach /dev/null: 0 1 5 10 * /path/to/script.sh > /dev/null.

Kleines Extra: In Zukunft möchte ich eine Warnung erhalten, wenn der Plattenplatz (oder die Inodes) zur Neige gehen. Der Test dafür ist leicht geschrieben (siehe oben), und einen Mechanismus zur Benachrichtigung habe ich schon für andere Zwecke. Und zwar benutze ich den Service und die App von Pushover: Simple Notifications for Android, iOS, and Desktop und Dead Man's Snitch — A dead simple cron job monitoring tool.