Vous êtes connecté par SSH à un serveur Ubuntu 24.04 qui « a plein d’espace » selon df -h.
Pourtant, chaque déploiement échoue, les logs ne tournent plus, apt ne peut pas dépaqueter, et le noyau continue de lancer
No space left on device comme s’il était payé à l’erreur.
C’est l’un de ces incidents qui fait douter les personnes les plus compétentes. Le disque n’est pas plein.
Quelque chose d’autre l’est. La plupart du temps : les inodes. Et une fois que vous comprenez ce que cela signifie, la correction est presque ennuyeuse.
Presque.
Ce que vous voyez : « disque plein » avec des Go libres
Sous Ubuntu, « disque plein » signifie souvent une des trois choses suivantes :
- Épuisement de l’espace en blocs : le cas classique ; vous avez manqué d’octets.
- Épuisement des inodes : vous avez manqué d’entrées de métadonnées pour les fichiers ; des octets peuvent rester disponibles.
- Blocs réservés, quotas ou corruption du système de fichiers : vous avez de l’espace mais vous ne pouvez pas l’utiliser.
L’épuisement des inodes est sournois parce qu’il n’apparaît pas dans la première commande que tout le monde lance.
df sans options ne rapporte que l’utilisation des blocs. Vous pouvez avoir 200 Go libres et ne pas pouvoir
créer un fichier de 0 octet. Le système de fichiers ne peut pas allouer un nouvel inode, il ne peut donc pas créer un nouveau fichier.
Vous remarquerez des effets secondaires étranges :
- De nouveaux fichiers de journal ne peuvent pas être créés, donc les services plantent ou arrêtent d’écrire les logs au pire moment.
aptéchoue en cours d’installation parce qu’il ne peut pas créer de fichiers temporaires ou dépaqueter des archives.- Les builds Docker commencent à échouer sur des opérations « writing layer » même si les volumes semblent corrects.
- Certaines applications signalent « disque plein » tandis que d’autres continuent de fonctionner (parce qu’elles ne créent pas de fichiers).
Il y a un test simple : essayez de créer un fichier sur le système de fichiers affecté. S’il échoue avec « No space left »
alors que df -h montre de l’espace libre, arrêtez de discuter avec df et vérifiez les inodes.
Les inodes expliqués comme si vous gériez la production
Un inode est l’enregistrement du système de fichiers pour un fichier ou un répertoire. C’est de la métadonnée : propriétaire, permissions, horodatages,
taille, pointeurs vers les blocs de données. Dans de nombreux systèmes de fichiers, le nom de fichier n’est pas stocké dans l’inode ; il vit
dans les entrées de répertoire qui associent les noms aux numéros d’inode.
La vérité opérationnelle importante : la plupart des systèmes Linux ont deux « budgets » séparés :
les blocs (octets) et les inodes (nombre de fichiers). Si vous épuisez l’un ou l’autre, c’est fini.
Pourquoi les inodes s’épuisent dans les systèmes réels
L’épuisement des inodes n’est généralement pas dû à « beaucoup de gros fichiers ». C’est dû à « des millions de petits fichiers ».
Pensez caches, spools de mail, artefacts de build, couches de conteneurs, espaces de travail CI, téléchargements temporaires,
et tampons de métriques que quelqu’un a oublié d’expirer.
Un fichier de 1 Ko coûte toujours un inode. Un fichier de 0 octet coûte toujours un inode. Un répertoire coûte aussi un inode.
Quand vous avez 12 millions de petits fichiers, le disque peut être largement vide en octets, mais la table d’inodes est cuite.
Quels systèmes de fichiers sont les plus susceptibles de vous mordre
- ext4 : courant sur Ubuntu ; les inodes sont généralement créés au formatage selon un ratio d’inodes. Si vous vous trompez, vous pouvez tomber en panne.
- XFS : les inodes sont plus dynamiques ; l’épuisement des inodes est moins courant mais pas mythique.
- btrfs : l’allocation des métadonnées est différente ; vous pouvez toujours rencontrer des problèmes d’espace métadonnées, mais ce n’est pas la même histoire d’« nombre d’inodes fixe ».
- overlayfs (Docker) : ce n’est pas un type de système de fichiers à part entière, mais il amplifie le comportement « beaucoup de fichiers » sur des hôtes riches en conteneurs.
Une citation à garder dans votre runbook mental :
« L’espoir n’est pas une stratégie. » — General Gordon R. Sullivan
Playbook de diagnostic rapide (premier/deuxième/troisième)
Quand l’alerte dit « No space left on device » mais que les graphiques indiquent que vous êtes OK, ne vous dispersez pas.
Suivez le playbook.
Premier : confirmez ce que « espace » signifie réellement
- Vérifiez les blocs (
df -h) et les inodes (df -i) pour le point de montage affecté. - Essayez de créer un fichier sur ce point de montage ; confirmez le chemin d’erreur.
- Vérifiez un remontage en lecture seule ou des erreurs de système de fichiers dans
dmesg.
Deuxième : trouvez le montage et les plus gros consommateurs d’inodes
- Identifiez quel chemin du système de fichiers échoue (logs, tmp, répertoire de données).
- Trouvez les répertoires avec un grand nombre de fichiers en utilisant
findet quelques comptes ciblés. - Si c’est Docker/Kubernetes, vérifiez overlay2, images, containers et logs.
Troisième : libérez des inodes en toute sécurité
- Commencez par des nettoyages sûrs et évidents : anciens logs, caches, fichiers temporaires, vacuum du journal, garbage des conteneurs.
- Supprimez des fichiers, pas des répertoires, si l’application attend une structure de répertoire.
- Confirmez que l’utilisation des inodes baisse (
df -i) et que les services se rétablissent.
Vous n’avez pas besoin d’actions héroïques. Vous avez besoin d’un plan de suppression contrôlé et d’un postmortem qui empêche que cela se reproduise.
Tâches pratiques : commandes, sens des sorties, décisions
Ci‑dessous des tâches réelles que vous pouvez exécuter sur Ubuntu 24.04. Chacune inclut quoi surveiller et quelle décision prendre.
Faites-les dans l’ordre si vous êtes en astreinte ; piochez si vous connaissez déjà le montage.
Tâche 1 : Confirmer l’utilisation des blocs (la vérification évidente)
cr0x@server:~$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 ext4 200G 62G 128G 33% /
tmpfs tmpfs 3.1G 1.2M 3.1G 1% /run
/dev/sdb1 ext4 1.8T 1.1T 648G 63% /data
Sens : l’espace en blocs est correct sur / et /data.
Décision : Si vous recevez toujours « No space left », passez aux vérifications d’inodes. Ne perdez pas de temps à chasser des gros fichiers pour l’instant.
Tâche 2 : Vérifier l’utilisation des inodes (la moitié des cas)
cr0x@server:~$ df -iT
Filesystem Type Inodes IUsed IFree IUse% Mounted on
/dev/sda2 ext4 13107200 13107190 10 100% /
tmpfs tmpfs 790000 420 789580 1% /run
/dev/sdb1 ext4 122142720 982134 121160586 1% /data
Sens : le système de fichiers racine a IUse% 100%. Il ne reste que 10 inodes libres. C’est terminé pour la création de fichiers.
Décision : Vous devez supprimer des fichiers sur / (ou les déplacer) pour libérer des inodes. Supprimer un gros fichier ne suffit pas si vous avez besoin de libérer de nombreux inodes.
Tâche 3 : Reproduire l’échec de façon contrôlée
cr0x@server:~$ touch /tmp/inode-test-file
touch: cannot touch '/tmp/inode-test-file': No space left on device
Sens : le système de fichiers ne peut pas allouer un inode pour un petit fichier.
Décision : Traitez cela comme un incident de disponibilité. Tout ce qui doit écrire (logs, sockets, fichiers PID, temporaires) peut échouer ensuite.
Tâche 4 : Identifier quel chemin est sur le système de fichiers impacté
cr0x@server:~$ findmnt -T /var/log
TARGET SOURCE FSTYPE OPTIONS
/ /dev/sda2 ext4 rw,relatime,errors=remount-ro
Sens : /var/log se trouve sur /. Si les logs ont explosé en millions de fichiers, voilà votre champ de bataille.
Décision : Concentrez votre recherche sous /var, /tmp, /var/lib et tous les répertoires d’applications sur /.
Tâche 5 : Repérer les suspects habituels par taille (octets)
cr0x@server:~$ sudo du -xh --max-depth=1 /var | sort -h
12M /var/cache
180M /var/log
2.1G /var/lib
2.4G /var
Sens : l’utilisation en octets n’est pas extrême. C’est votre premier indice que le nombre de fichiers, pas la taille, est le problème.
Décision : Arrêtez d’optimiser pour les Go. Commencez à optimiser pour le nombre de fichiers.
Tâche 6 : Trouver les répertoires avec un énorme nombre de fichiers (balayage de haut niveau)
cr0x@server:~$ sudo bash -lc 'for d in /var/* /tmp /home; do [ -d "$d" ] && printf "%s\t" "$d" && find "$d" -xdev -type f 2>/dev/null | wc -l; done | sort -n -k2 | tail -n 10'
/var/cache 1320
/var/log 5402
/var/lib 12877190
/tmp 120
/home 88
Sens : /var/lib contient ~12,8 millions de fichiers. Ce n’est pas « un peu désordonné » ; c’est vos inodes.
Décision : Zoomez dans /var/lib. Si c’est un hôte conteneur, attendez-vous à /var/lib/docker ou /var/lib/containerd.
Tâche 7 : Réduire rapidement à l’intérieur de /var/lib
cr0x@server:~$ sudo bash -lc 'for d in /var/lib/*; do [ -d "$d" ] && printf "%s\t" "$d" && find "$d" -xdev -type f 2>/dev/null | wc -l; done | sort -n -k2 | tail -n 10'
/var/lib/systemd 2200
/var/lib/dpkg 9800
/var/lib/docker 12866012
Sens : Docker dévore votre budget d’inodes via les couches, le cache de build et les logs de conteneurs.
Décision : Décidez si vous pouvez exécuter un prune en toute sécurité maintenant. Si cet hôte est dédié à une seule tâche, le prune est généralement correct. Si c’est un serveur « pet » avec des charges inconnues, soyez plus prudent.
Tâche 8 : Vérifier la vue de Docker (octets, pas inodes, mais utile)
cr0x@server:~$ sudo docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 48 12 23.4GB 18.1GB (77%)
Containers 65 18 4.2GB 2.9GB (69%)
Local Volumes 26 20 11.8GB 1.1GB (9%)
Build Cache 152 0 6.4GB 6.4GB
Sens : Il y a beaucoup à supprimer, mais cette sortie ne montre pas le nombre de fichiers.
Décision : Procédez aux actions de prune si vous comprenez l’impact : conteneurs arrêtés, images pendantes, cache de build.
Tâche 9 : Pruner Docker en toute sécurité (commencez conservateur)
cr0x@server:~$ sudo docker image prune -a -f
Deleted Images:
deleted: sha256:1a2b3c...
deleted: sha256:4d5e6f...
Total reclaimed space: 17.8GB
Sens : Les images inutilisées ont été supprimées ; le nombre d’inodes devrait aussi diminuer car les couches contiennent de nombreux petits fichiers.
Décision : Revérifiez df -i. Si l’utilisation des inodes ne baisse pas assez, supprimez ensuite les conteneurs et le cache de build.
Tâche 10 : Pruner le build cache (souvent une usine silencieuse d’inodes)
cr0x@server:~$ sudo docker builder prune -a -f
Deleted build cache objects:
k2r1m3n4o5p6...
Total reclaimed space: 6.4GB
Sens : Les hôtes CI/build laissent souvent des fragments de cache derrière eux.
Décision : Si vous avez besoin de builds reproductibles et de rebuilds rapides, planifiez ce nettoyage plutôt que de l’exécuter constamment. Pour l’instant, vous stabilisez le nœud.
Tâche 11 : Confirmer la récupération des inodes (c’est votre métrique de succès)
cr0x@server:~$ df -i /
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda2 13107200 8123400 4983800 63% /
Sens : Vous êtes revenu de la falaise. Les services peuvent créer des fichiers à nouveau.
Décision : Redémarrez les services qui ont planté à cause des écritures échouées, et mettez en place des garde-fous pour éviter une récidive.
Tâche 12 : Si les logs sont en cause, nettoyez et limitez (systemd-journald)
cr0x@server:~$ sudo journalctl --disk-usage
Archived and active journals take up 1.7G in the file system.
Sens : Les journaux ne sont pas nécessairement lourds en inodes (ce sont généralement des fichiers moins nombreux et plus volumineux), mais ils peuvent quand même peser.
Décision : Si les octets importent aussi, vacuum. Si ce sont les inodes qui importent, concentrez-vous sur les applications qui créent de nombreux fichiers de logs séparés, pas sur le journal lui‑même.
cr0x@server:~$ sudo journalctl --vacuum-time=7d
Vacuuming done, freed 1.2G of archived journals from /var/log/journal.
Sens : Octets libérés. Inodes libérés de façon modeste seulement.
Décision : Définissez des limites persistantes dans la config de journald si cet hôte est sujet à des logs bruyants.
Tâche 13 : Si apt échoue, nettoyez le cache des paquets
cr0x@server:~$ sudo apt-get clean
Sens : Supprime les archives de paquets téléchargés sous /var/cache/apt/archives.
Décision : Bonne hygiène, mais rarement une solution miracle pour les inodes. Aide lorsque les caches contiennent beaucoup de petits fichiers partiels.
Tâche 14 : Trouver les répertoires à grand nombre de fichiers avec du (style inode)
cr0x@server:~$ sudo du -x --inodes --max-depth=2 /var/lib | sort -n | tail -n 10
1200 /var/lib/systemd
9800 /var/lib/dpkg
12866012 /var/lib/docker
12877190 /var/lib
Sens : C’est la vue qui compte : consommation d’inodes par répertoire.
Décision : Ciblez le plus gros consommateur. Ne faites pas « un peu de nettoyage partout ». Vous perdrez du temps et serez toujours à 100%.
Tâche 15 : En cas de doute, inspectez la fan-out pathologique
cr0x@server:~$ sudo find /var/lib/docker -xdev -type f -printf '%h\n' 2>/dev/null | sort | uniq -c | sort -n | tail -n 5
42000 /var/lib/docker/containers/8a7b.../mounts
78000 /var/lib/docker/overlay2/3f2d.../diff/usr/lib
120000 /var/lib/docker/overlay2/9c1e.../diff/var/cache
250000 /var/lib/docker/overlay2/b7aa.../diff/usr/share
980000 /var/lib/docker/overlay2/2d9b.../diff/node_modules
Sens : Une couche de conteneur avec node_modules peut générer des nombres de fichiers absurdes.
Décision : Corrigez le build (build multi‑étapes, suppression des dépendances dev, .dockerignore) et/ou déplacez le data root de Docker vers un système de fichiers conçu pour cette charge.
Tâche 16 : Confirmer le type de système de fichiers et les détails de provisioning des inodes
cr0x@server:~$ sudo tune2fs -l /dev/sda2 | egrep -i 'Filesystem features|Inode count|Inode size|Block count|Reserved block count'
Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Inode count: 13107200
Inode size: 256
Block count: 52428800
Reserved block count: 2621440
Sens : ext4 a un nombre d’inodes fixe ici. Vous ne pouvez pas « ajouter plus d’inodes » sans reconstruire le système de fichiers.
Décision : Si la mission de cet hôte est « millions de petits fichiers », planifiez une migration : nouveau système de fichiers avec un ratio d’inodes différent, ou un agencement de stockage différent.
Blague #1 : Les inodes sont comme des salles de réunion : vous pouvez avoir un immeuble vide et être « plein » si chaque salle est occupée par un petit post‑it.
Trois mini-récits d’entreprise (anonymisés, douloureusement réels)
1) Incident causé par une mauvaise hypothèse : « df dit que tout va bien »
Une entreprise SaaS de taille moyenne gérait une flotte de serveurs Ubuntu traitant l’ingestion de webhooks. Les ingénieurs surveillaient l’utilisation du disque en pourcentage,
déclenchaient des alertes à 80%, et étaient fiers : « Nous ne remplissons plus les disques ». Un mardi après‑midi, le pipeline d’ingestion a commencé à renvoyer
des 500 intermittents. Les retries s’accumulaient, les files d’attente se remplissaient, les dashboards s’enflammaient.
L’astreignant a lancé la routine standard : df -h semblait sain. Le CPU allait bien. La mémoire n’était pas excellente mais tenable.
Ils ont redémarré un service et il est mort immédiatement parce qu’il ne pouvait pas créer un fichier PID. Ce message d’erreur s’est finalement montré :
No space left on device.
Quelqu’un a suggéré « peut‑être que le disque a menti », ce qui est une façon humaine et charmante de dire « nous ne mesurions pas la bonne chose ».
Ils ont exécuté df -i et ont trouvé le système de fichiers racine à 100% d’utilisation des inodes. Le coupable n’était pas une base de données.
C’était un « magasin de retries temporaire » implémenté comme un fichier JSON par événement webhook sous /var/lib/app/retry/.
Chaque fichier était minuscule. Il y en avait des millions.
Le correctif immédiat a été simple : supprimer les fichiers plus anciens qu’un seuil et redémarrer. Le vrai correctif a pris un sprint :
migrer le magasin de retries vers une file conçue pour cela, cesser d’utiliser le système de fichiers comme une base de données à bas coût, et ajouter des alertes sur les inodes.
Le titre du postmortem était poli. Le chat interne, moins.
2) Optimisation qui a échoué : « tout mettre en cache sur le disque local »
Une équipe de data engineering a accéléré des jobs ETL en mettant en cache des artefacts intermédiaires sur le SSD local.
Ils sont passés de « un artefact par batch » à « un artefact par partition », pour la parallélisation.
Les performances ont augmenté. Les coûts semblaient meilleurs. Tout le monde a continué sa vie.
Des semaines plus tard, des nœuds ont commencé à tomber de façon échelonnée. Pas tous en même temps, ce qui rendait le diagnostic plus difficile.
Certains jobs réussissaient, d’autres échouaient aléatoirement en essayant d’écrire la sortie. Les erreurs étaient inconsistantes :
exceptions Python, erreurs Java IO, ou parfois « filesystem en lecture seule » après que le noyau ait remonté un disque en difficulté.
La cause racine était mécaniquement embarrassante : le cache a créé des dizaines de millions de petits fichiers.
Le système ext4 avait été formaté avec un ratio d’inodes par défaut adapté à un usage général, pas à des « millions de shards ».
Les nœuds n’ont pas manqué d’octets ; ils ont manqué d’identités de fichiers. L’« optimisation » était en fait un test de stress des inodes.
Ils ont « corrigé » en augmentant la taille du disque. Ça n’a pas aidé, car le nombre d’inodes restait fixé.
Ils ont ensuite reformatté avec une densité d’inodes appropriée et changé la stratégie de cache pour empaqueter des partitions dans des bundles de type tar.
Les performances ont légèrement régressé. La fiabilité s’est améliorée considérablement. C’est le compromis à accepter.
3) Pratique ennuyeuse mais correcte qui a sauvé la journée : fichiers séparés et garde-fous
Une autre organisation exécutait des charges mixtes sur des nœuds Kubernetes : services système, Docker/containerd, et un espace de travail local.
Ils avaient une règle : tout ce qui peut exploser en nombre de fichiers obtient son propre système de fichiers. Docker vivait sur /var/lib/docker
monté depuis un volume dédié. L’espace scratch était sur un montage séparé avec des politiques de nettoyage agressives.
Ils avaient aussi deux moniteurs ennuyeux : « utilisation des blocs » et « utilisation des inodes ». Pas de ML sophistiqué. Juste deux séries temporelles et des alertes
qui envoyaient une page avant la falaise. Ils testaient les alertes trimestriellement en créant une tempête d’inodes en staging (oui, ça existe).
Un jour, une nouvelle pipeline de build a commencé à produire des couches pathologiques avec d’énormes arbres de dépendances.
Les inodes du volume Docker ont monté rapidement. L’alerte a tiré tôt. L’astreignant n’a pas eu à apprendre quoi que ce soit de nouveau sous pression.
Ils ont pruné, rollbacké la pipeline et relevé les limites. Le reste du nœud est resté sain parce que le racine n’était pas impliqué.
Le rapport d’incident était court. Le correctif était ennuyeux. Tout le monde a dormi.
C’est tout l’intérêt du SRE.
Faits intéressants et un peu d’histoire (parce que ça explique les modes de panne)
- Les inodes datent de l’Unix primitif : le concept remonte à la conception du système de fichiers Unix original, où métadonnées et blocs de données étaient des structures séparées.
- Les ext traditionnels préallouent les inodes : ext2/ext3/ext4 décident typiquement du nombre d’inodes au moment de
mkfsen fonction d’un ratio, pas dynamiquement selon la charge. - Les ratios d’inodes par défaut sont un compromis : ils visent des charges générales ; ils ne sont pas adaptés aux couches de conteneurs, caches CI ou explosions de maildir.
- Les répertoires coûtent aussi des inodes : « nous avons seulement créé des répertoires » n’est pas une défense ; chaque répertoire consomme aussi un inode.
- « No space left on device » couvre plusieurs raisons : la même chaîne d’erreur peut signifier manque de blocs, manque d’inodes, quota dépassé, ou même système de fichiers passé en lecture seule après des erreurs.
- Les blocs réservés existent pour une raison : ext4 réserve généralement un pourcentage des blocs pour root, destiné à garder le système utilisable sous pression ; il ne réserve pas les inodes de la même façon.
- Les charges de petits fichiers sont plus difficiles qu’elles en ont l’air : les opérations de métadonnées dominent ; l’efficacité des inodes et des recherches de répertoire peut compter plus que le débit.
- Les images de conteneurs amplifient les schémas de petits fichiers : les écosystèmes de langage avec de grands arbres de dépendances (Node, Python, Ruby) peuvent créer des couches avec un nombre massif de fichiers.
- Certaines filesystems ont évolué vers des métadonnées dynamiques : XFS et btrfs gèrent différemment les métadonnées, ce qui change la nature des pannes « full », mais ne les élimine pas.
Corrections : du nettoyage rapide à la prévention permanente
Stabilisation immédiate (minutes) : libérer des inodes sans empirer la situation
Votre travail pendant un incident n’est pas « rendre propre ». C’est « rendre le système réinscriptible » sans supprimer la mauvaise chose.
Voici ce qui tend à être sûr et efficace, par ordre décroissant de raison :
- Supprimez les caches éphémères connus (cache de build, cache de paquets, fichiers temporaires) avec les commandes adaptées.
- Prunez les ordures des conteneurs si l’hôte est centré conteneurs et que vous pouvez tolérer la suppression d’artefacts inutilisés.
- Expirez les fichiers générés par l’application selon l’âge, pas au doigt mouillé. Préférez des politiques « plus vieux que N jours ».
- Déplacez des répertoires hors du système de fichiers si la suppression est risquée : archivez vers un autre montage, puis supprimez localement.
Quand c’est lié aux logs : corrigez le problème de nombre de fichiers, pas seulement la rotation
Logrotate résout « un fichier qui grossit indéfiniment ». Il ne résout pas automatiquement « nous créons un fichier par requête ».
Si votre application crée des fichiers de log uniques par unité de travail (ID de requête, ID de job, ID de client), vous êtes en train d’attaquer votre propre table d’inodes en DDOS.
Préférez :
- un flux de logs unique avec champs structurés (JSON suffit, gardez‑le raisonnable)
- l’intégration à journald quand c’est approprié
- du spool local borné avec rétention explicite
Quand c’est Docker : choisissez un data root adapté à la charge
Docker sur ext4 peut très bien fonctionner, jusqu’à ce que non. Si vous savez qu’un nœud va construire des images, exécuter de nombreux conteneurs,
et chasser des couches, traitez /var/lib/docker comme un datastore à fort churn et donnez‑lui son propre système de fichiers.
Options pratiques :
- Montage séparé pour
/var/lib/dockeravec une densité d’inodes adaptée au nombre de fichiers attendu. - Nettoyage régulier du cache de build, programmé, pas manuel en urgence.
- Corriger les builds d’images pour réduire la fan‑out des fichiers : builds multi‑étapes, réduire les dépendances, utiliser
.dockerignore.
Correctif permanent : concevoir le système de fichiers pour la charge
Si l’épuisement des inodes revient, vous n’avez pas un « problème de nettoyage ». Vous avez un problème de capacity planning.
Sur ext4, le nombre d’inodes est fixé à la création. La seule vraie solution est de migrer vers un système de fichiers avec plus d’inodes
(ou un agencement différent), ce qui implique :
- créer un nouveau système de fichiers avec une densité d’inodes plus élevée
- déplacer les données
- mettre à jour les mounts et les services
- ajouter surveillance et politiques de rétention
Comment créer un ext4 avec plus d’inodes (migration planifiée)
Le nombre d’inodes sur ext4 est influencé par -i (octets par inode) et -N (nombre d’inodes explicite).
Baisser les octets par inode signifie plus d’inodes. Plus d’inodes signifie plus de surcharge en métadonnées. C’est un compromis, pas du gratuit.
cr0x@server:~$ sudo mkfs.ext4 -i 16384 /dev/sdc1
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 976754176 4k blocks and 61079552 inodes
Filesystem UUID: 9f1f4a1c-8b1d-4c1b-9d88-8d1aa14d4e1e
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
Sens : Cet exemple crée bien plus d’inodes qu’un ratio par défaut le ferait sur le même volume.
Décision : N’utilisez ceci que lorsque vous savez que vous avez besoin de beaucoup de fichiers. Pour de grosses données séquentielles, ne gaspillez pas de métadonnées.
Blague #2 : Si vous traitez le système de fichiers comme une base de données, il finira par vous facturer en inodes.
Erreurs courantes : symptôme → cause racine → correctif
1) « df montre 30% utilisé mais je ne peux pas écrire » → épuisement d’inodes → vérifiez et supprimez les points chauds de petits fichiers
- Symptôme : les écritures échouent,
touchéchoue,aptéchoue, les services plantent en créant des fichiers temporaires. - Cause racine :
df -imontre 100% d’inodes utilisés sur le montage. - Fix : identifiez les répertoires à fort nombre de fichiers avec
du --inodes/find ... | wc -l, supprimez les fichiers éphémères sûrs, puis empêchez la récidive.
2) « J’ai supprimé un gros fichier, c’est toujours cassé » → vous avez libéré des blocs, pas des inodes → supprimez beaucoup de fichiers
- Symptôme : les Go libres augmentent, mais « No space left » continue.
- Cause racine : l’utilisation des inodes n’a pas changé.
- Fix : libérez des inodes en supprimant des nombres de fichiers, pas des tailles de fichiers. Ciblez caches, spools, artefacts de build.
3) « Seul root peut écrire ; les utilisateurs ne peuvent pas » → blocs réservés ou quotas → vérifiez avec tune2fs et les outils de quota
- Symptôme : root peut créer des fichiers, non-root ne peut pas.
- Cause racine : pourcentage de blocs réservés sur ext4, ou quotas utilisateurs atteints.
- Fix : vérifiez les blocs réservés avec
tune2fs; vérifiez les quotas ; ajustez avec précaution. Ne mettez pas aveuglément les blocs réservés à 0% sur les partitions système.
4) « Il est passé en lecture seule et maintenant tout échoue » → erreurs système de fichiers → inspectez dmesg, exécutez fsck (hors ligne)
- Symptôme : le noyau a remonté
errors=remount-ro, les écritures échouent avec des erreurs en lecture seule. - Cause racine : erreurs d’E/S ou corruption du système de fichiers, pas la capacité.
- Fix : inspectez
dmesg; planifiez un reboot en recovery et lancezfsck. Le nettoyage de capacité ne réglera pas la corruption.
5) « Le nœud Kubernetes a DiskPressure mais df semble ok » → pression d’inodes du runtime des conteneurs → prune et montages séparés
- Symptôme : pods évincés ; kubelet se plaint ; nœud instable.
- Cause racine : répertoires du runtime remplissent le budget d’inodes (overlay2, logs).
- Fix : prune du stockage runtime, appliquez la garbage collection d’images, mettez le runtime sur un volume dédié avec surveillance.
6) « Nous avons nettoyé /tmp ; ça a tenu une heure » → l’application recrée la tempête → corrigez la rétention à la source
- Symptôme : incidents d’inodes répétés après nettoyage.
- Cause racine : bug applicatif, mauvais design (un fichier par événement), ou TTL/rotation manquants.
- Fix : ajoutez une politique de rétention, redesign du stockage (base de données/file d’attente/object store), imposer des limites et des alertes.
Listes de contrôle / plan étape par étape
Checklist d’astreinte (stabiliser en 15–30 minutes)
- Exécutez
df -hTetdf -iTpour le montage défaillant. - Confirmez avec
touchdans le chemin affecté. - Trouvez le mapping du montage avec
findmnt -T. - Identifiez les gros consommateurs d’inodes avec
du -x --inodes --max-depth=2et desfind ... | wc -lciblés. - Choisissez une action de nettoyage sûre et à fort impact (Docker prune, nettoyage de cache, suppression basée sur l’âge).
- Revérifiez
df -ijusqu’à être sous ~90% sur le montage critique. - Redémarrez les services impactés (seulement après que les écritures réussissent).
- Capturez des preuves : commandes exécutées, comptages d’inodes avant/après, répertoires responsables.
Checklist ingénierie (prévenir la récidive)
- Ajoutez la surveillance et les alertes d’inodes par système de fichiers (pas seulement l’utilisation disque en %).
- Mettez les répertoires à fort churn sur des montages dédiés :
/var/lib/docker, spool d’app, cache de build. - Implémentez la rétention côté producteur : TTL, limites, compactage périodique, ou backend de stockage différent.
- Revoyez les builds et images : réduisez le nombre de fichiers par couche ; évitez d’emballer d’énormes arbres de dépendances dans les images runtime.
- Si ext4 est utilisé pour des charges de petits fichiers, planifiez la densité d’inodes lors du formatage et documentez le choix.
- Faites un game day en staging : simulez la pression d’inodes et validez les alertes et les étapes de reprise.
Checklist de migration (quand le nombre d’inodes ext4 est fondamentalement mauvais)
- Mesurez le nombre actuel de fichiers et le taux de croissance (nouveaux fichiers quotidiens, comportement de rétention).
- Choisissez la cible : ext4 avec densité d’inodes plus élevée, XFS, ou une architecture différente (stockage objet, base de données, file d’attente).
- Provisionnez un nouveau volume et système de fichiers ; montez‑le à l’emplacement prévu.
- Arrêtez la charge, copiez les données (préservant propriétaires/permissions), validez, puis basculez.
- Réactivez la charge avec des valeurs par défaut de rétention activées dès le départ.
- Laissez des garde-fous : alertes, timers de nettoyage et politique de cap stricte.
FAQ
1) Qu’est‑ce qu’un inode en une phrase ?
Un inode est un enregistrement de métadonnées du système de fichiers qui représente un fichier ou un répertoire ; il faut un inode libre pour créer un nouveau fichier.
2) Pourquoi Ubuntu affiche « No space left on device » alors que df -h montre de l’espace libre ?
Parce que « espace » peut signifier des octets (blocs) ou des métadonnées de fichiers (inodes). df -h montre les blocs ; df -i montre les inodes.
3) Comment confirmer rapidement un épuisement d’inodes ?
Exécutez df -i sur le montage et vérifiez la présence de IUse% 100%, puis essayez touch pour confirmer que la création de fichiers échoue.
4) Puis‑je augmenter le nombre d’inodes sur un ext4 existant ?
Pas de manière pratique en ligne. Le nombre d’inodes ext4 est effectivement défini à la création du système de fichiers. La vraie solution est de migrer vers un nouveau système de fichiers avec plus d’inodes.
5) Pourquoi les conteneurs rendent-ils les problèmes d’inodes plus probables ?
Les couches d’images et les arbres de dépendances peuvent contenir d’énormes nombres de petits fichiers. Le stockage en overlay multiplie les opérations de métadonnées, et les caches de build s’accumulent silencieusement.
6) Supprimer un gros répertoire est‑il sûr ?
Parfois. Il est plus sûr de supprimer des fichiers basés sur l’âge dans un chemin éphémère connu que de supprimer un répertoire attendu par un service. Préférez des suppressions ciblées et vérifiez les configurations des services.
7) Que dois‑je surveiller pour détecter cela tôt ?
Surveillez l’utilisation des inodes par système de fichiers (df -i) et alertez sur la croissance soutenue et les seuils hauts (par exemple 85% et 95%), pas seulement le pourcentage d’utilisation du disque.
8) Si je n’ai plus d’inodes, dois‑je redémarrer ?
Redémarrer ne crée pas d’inodes. Cela peut temporairement supprimer quelques fichiers temporaires, mais ce n’est pas une solution et peut compliquer l’investigation. Libérez des inodes de manière délibérée à la place.
9) Pourquoi cela affecte‑t‑il parfois une seule application ?
Parce que seules les applications qui doivent créer de nouveaux fichiers sont bloquées. Les services en lecture seule peuvent continuer à fonctionner tant qu’ils n’essaient pas d’écrire des logs, sockets ou états.
10) Les logs journald sont‑ils susceptibles de causer un épuisement d’inodes ?
Moins fréquemment que les logs applicatifs qui créent un fichier par événement. journald a tendance à stocker les données dans quelques fichiers plus volumineux, ce qui est plus consommateur d’octets que d’inodes.
Prochaines étapes concrètes
Si vous ne prenez qu’une habitude : quand vous voyez « No space left on device », exécutez df -i aussi automatiquement que df -h.
Le système de fichiers a deux limites, et la production se moque de celle que vous avez oublié de surveiller.
Étapes pratiques :
- Ajoutez des alertes d’inodes sur chaque montage persistant (surtout
/et les stockages des runtimes de conteneurs). - Déplacez les chemins à fort churn sur des systèmes de fichiers dédiés pour qu’une charge défectueuse ne handicape pas tout le nœud.
- Corrigez le comportement des producteurs : rétention, TTL, moins de fichiers, meilleur empaquetage des artefacts.
- Pour ext4, planifiez la densité d’inodes en amont pour les charges de petits fichiers, et documentez votre choix.
- Organisez un game day : créez une tempête d’inodes contrôlée en staging, vérifiez vos alertes et la procédure de nettoyage.
Vous n’avez pas besoin de plus de disque. Vous avez besoin de moins de fichiers, de meilleurs contrôles de cycle de vie, et d’un agencement de système de fichiers qui reflète la réalité au lieu des hypothèses.