Vous vous connectez à une machine Ubuntu 24.04 parce que « l’appli est lente ». Vous trouvez la RAM à 97 %, le swap qui frôle, et le noyau a commencé à choisir ses victimes. Puis vous remarquez quelque chose d’embarrassant : personne n’a « fuité » de mémoire. Un tmpfs l’a fait.
tmpfs est merveilleux — jusqu’à ce que ça ne le soit plus. Il donne l’impression que les fichiers sont en RAM, parce que c’est effectivement le cas. Quand il gonfle, il fait ce que la RAM fait quand elle est pleine : il ruine votre après‑midi. Voyons comment l’empêcher de bouffer la machine tout en gardant vos applications stables et votre démarrage banal.
Ce que vous voyez (et pourquoi c’est déroutant)
tmpfs est un système de fichiers qui stocke des données en mémoire (page cache / shmem) et peut swapper sous pression. Ubuntu monte plusieurs instances tmpfs par défaut : /run, /dev/shm, parfois /tmp (selon la configuration), plus divers répertoires d’exécution par service.
La partie déroutante est que les outils affichent une « Size » tmpfs qui paraît énorme — souvent la moitié de la RAM — et les administrateurs interprètent cela comme de la mémoire allouée. Ce n’est pas le cas. Ce nombre est une limite, pas une utilisation. L’utilisation réelle est la colonne « Used », et c’est de la mémoire réelle (ou du swap) qui peut vous pousser en territoire OOM si elle croît.
Quand tmpfs « part en vrille », les causes habituelles sont ennuyeuses :
- Une appli écrit de gros fichiers temporaires dans
/dev/shmou/runparce que c’est « rapide ». - Un répertoire de file d’attente ou de spool se trouve sur tmpfs et subit des pics de charge.
- Des conteneurs montent tmpfs pour
/tmpou un volumeemptyDiret les logs/métriques deviennent incontrôlables. - Un service mal configuré génère des artefacts d’exécution et ne les nettoie jamais.
- Quelqu’un a « optimisé » en mettant
/tmpsur tmpfs sur un serveur à faible RAM.
La correction n’est pas un sysctl magique. C’est (1) mesurer qui écrit, (2) poser des limites adaptées à la réalité, et (3) s’assurer que la charge bascule sur le disque ou échoue proprement au lieu de planter l’hôte.
Faits et courte histoire utile
- tmpfs existe dans Linux depuis des décennies et a remplacé l’ancien mindset « ramdisk partout » parce qu’il peut croître/rapetisser et swapper sous pression mémoire.
- Les ramdisks classiques préallouaient : un périphérique bloc en RAM avec une taille fixe. tmpfs est orienté fichiers et utilise la mémoire à la demande.
- Sur beaucoup de distribs, la taille par défaut de tmpfs apparaît comme ~50 % de la RAM (ou similaire), mais ce n’est que le maximum autorisé avant ENOSPC.
- Les données tmpfs vivent dans le même pool mémoire que tout le reste. Elles entrent en compétition avec le heap applicatif, le cache de fichiers et la mémoire noyau.
- Écrire dans tmpfs augmente « Shmem » et « Cached » différemment selon le mapping et la comptabilité ; lire correctement
/proc/meminfoest important. - systemd a centralisé la gestion des tmpfs : des montages comme
/runet les répertoires runtime par unité font désormais partie du scénario de démarrage, pas d’un assemblage de scripts init ad hoc. /runa remplacé/var/runsur les systèmes modernes : il s’agit d’un tmpfs par conception, donc l’état d’exécution ne persiste pas entre redémarrages./dev/shmest la mémoire partagée POSIX, pas « un joli répertoire scratch ». Certains logiciels l’utilisent quand même comme zone temporaire rapide, et il mangera volontiers votre RAM.- La pression mémoire peut pousser les pages tmpfs en swap, ce qui est « acceptable » jusqu’à ce que ce ne le soit plus : les pics de latence et les tempêtes de swap peuvent être pires que d’utiliser le disque pour des fichiers temporaires.
Une idée paraphrasée de Werner Vogels (CTO d’Amazon) tient encore en exploitation : « tout tombe en panne tout le temps — concevez et opérez en partant de cette hypothèse » (idée paraphrasée). tmpfs n’y échappe pas ; prévoyez qu’il puisse se remplir.
Guide de diagnostic rapide
Voici l’ordre qui vous mène le plus vite au coupable, sans vous perdre dans la théorie.
1) Confirmez que c’est tmpfs et non « mémoire mystère »
- Vérifiez
df -hTpour voir quel montage tmpfs se remplit. - Consultez
/proc/meminfopourShmem,MemAvailableet l’utilisation du swap. - Regardez les signaux OOM ou de pression mémoire récents dans
journalctl.
2) Trouvez quel répertoire grossit
- Utilisez
du -xsur le montage incriminé (reste dans le système de fichiers). - Vérifiez les fichiers supprimés mais toujours ouverts avec
lsof +L1.
3) Identifiez le processus et décidez : limiter, déplacer ou corriger
- Si c’est un service : inspectez l’unité, les répertoires runtime et les variables d’environnement pointant vers
/run,/tmp,/dev/shm. - Si c’est un conteneur : vérifiez les montages et volumes tmpfs ; appliquez des limites mémoire et des limites de taille tmpfs.
- Si c’est un cache connu : configurez la rétention/TTL et imposez un nettoyage.
4) Appliquez d’abord la mitigation la moins dangereuse
- Posez une limite
size=sensée sur le tmpfs risqué. - Déplacez les chemins scratch volumineux sur disque (par exemple
/var/tmpou un répertoire dédié sur SSD). - Ensuite seulement, envisagez des réglages noyau agressifs ; la plupart des explosions tmpfs sont juste de la croissance de fichiers.
Blague #1 : tmpfs n’est pas de la « mémoire gratuite ». C’est la même mémoire, juste déguisée en système de fichiers.
Tâches pratiques (commandes, sorties, décisions)
Ci‑dessous des commandes éprouvées sur le terrain. Pour chacune : ce qu’elle vous dit, et la décision que vous prenez.
Task 1: Lister les montages tmpfs et repérer celui qui est gonflé
cr0x@server:~$ df -hT | awk 'NR==1 || $2=="tmpfs" || $2=="devtmpfs"'
Filesystem Type Size Used Avail Use% Mounted on
tmpfs tmpfs 3.2G 1.9G 1.3G 60% /run
/dev/nvme0n1p2 ext4 80G 22G 54G 29% /
tmpfs tmpfs 16G 8.1G 7.9G 51% /dev/shm
tmpfs tmpfs 5.0M 44K 5.0M 1% /run/lock
tmpfs tmpfs 3.2G 4.0K 3.2G 1% /run/user/1000
Sens : /dev/shm consomme 8.1G. C’est une pression réelle si l’hôte a 16G de RAM.
Décision : Concentrez‑vous d’abord sur ce montage. Ne touchez pas à /run/lock ; il est minuscule et sans rapport.
Task 2: Confirmer la pression mémoire réelle (pas juste une grosse « Size » de tmpfs)
cr0x@server:~$ grep -E 'MemTotal|MemAvailable|Shmem|SwapTotal|SwapFree|Cached' /proc/meminfo
MemTotal: 16329640 kB
MemAvailable: 1128400 kB
Cached: 2413720 kB
Shmem: 8551120 kB
SwapTotal: 4194300 kB
SwapFree: 112340 kB
Sens : Shmem est ~8.1G, ce qui correspond à /dev/shm. MemAvailable est faible et le swap est presque épuisé.
Décision : Traitez cela comme un incident en cours : arrêtez la croissance et/ou évacuez la charge. N’ajoutez pas du swap comme seul remède.
Task 3: Vérifier les kills OOM ou les logs de pression mémoire
cr0x@server:~$ journalctl -k -b | egrep -i 'oom|out of memory|memory pressure' | tail -n 8
kernel: Memory cgroup out of memory: Killed process 27144 (python3) total-vm:9652144kB, anon-rss:5132140kB, file-rss:11320kB, shmem-rss:2048kB
kernel: oom_reaper: reaped process 27144 (python3), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
kernel: Out of memory: Killed process 30911 (node) total-vm:7621400kB, anon-rss:2874100kB, file-rss:9020kB, shmem-rss:1780kB
Sens : Le noyau a déjà tué des processus. Même si shmem-rss dans les processus tués semble petit, le shmem global du système est énorme.
Décision : Réduisez la croissance du tmpfs maintenant (cap, nettoyage, redémarrage des fautifs), puis corrigez la cause racine.
Task 4: Identifier ce qui est réellement dans le montage tmpfs
cr0x@server:~$ sudo du -xh --max-depth=1 /dev/shm | sort -h
0 /dev/shm/snap.lxd
12K /dev/shm/systemd-private-2d3c...-chrony.service-...
20M /dev/shm/app-cache
8.1G /dev/shm/feature-store
8.1G /dev/shm
Sens : Un répertoire domine : /dev/shm/feature-store.
Décision : Trouver quel processus le possède/l’utilise ; c’est votre levier. Nettoyer des systemd‑private aléatoires n’est pas la solution.
Task 5: Associer le répertoire à un processus (rapide et suffisant la plupart du temps)
cr0x@server:~$ sudo lsof +D /dev/shm/feature-store 2>/dev/null | head -n 10
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 18422 svc 12w REG 0,37 536870912 131112 /dev/shm/feature-store/chunk-0001.bin
python3 18422 svc 13w REG 0,37 536870912 131113 /dev/shm/feature-store/chunk-0002.bin
python3 18422 svc 14w REG 0,37 536870912 131114 /dev/shm/feature-store/chunk-0003.bin
Sens : Le PID 18422 écrit des fichiers de plusieurs centaines de Mo dans la mémoire partagée.
Décision : C’est un comportement applicatif, pas Ubuntu « qui utilise aléatoirement la RAM ». Corrigez la config applicative ou changez son chemin scratch.
Task 6: Attraper les fichiers supprimés mais encore ouverts sur tmpfs (le piège « df dit plein, du dit pas grand‑chose »)
cr0x@server:~$ sudo lsof +L1 | head -n 10
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
node 30911 svc 28w REG 0,37 1073741824 0 140221 /dev/shm/feature-store/tmp.log (deleted)
Sens : Un fichier de 1G a été supprimé de l’arbre mais est toujours tenu ouvert par un processus. du ne le compte pas ; df oui.
Décision : Redémarrez ou signalez le processus pour qu’il ferme/rouvre les logs ; sinon l’espace ne reviendra pas.
Task 7: Inspecter les options de montage pour comprendre les limites actuelles
cr0x@server:~$ findmnt -no TARGET,FSTYPE,OPTIONS /dev/shm
/dev/shm tmpfs rw,nosuid,nodev,size=16329640k,inode64
Sens : La limite de taille est essentiellement de la taille de la RAM. C’est permissif ; cela permet à une appli d’essayer de consommer tout l’hôte.
Décision : Posez une limite plus basse, mais seulement après avoir vérifié ce dont a besoin la ou les applis et combien.
Task 8: Vérifier la vue de systemd sur les montages tmpfs et qui les possède
cr0x@server:~$ systemctl status dev-shm.mount --no-pager
● dev-shm.mount - POSIX Shared Memory
Loaded: loaded (/usr/lib/systemd/system/dev-shm.mount; static)
Active: active (mounted) since Mon 2025-12-29 08:31:12 UTC; 3h 12min ago
Where: /dev/shm
What: tmpfs
Sens : Le montage est géré par systemd. Cela compte parce que vous devez le configurer via un drop‑in, pas en éditant des fichiers aléatoires qui seront écrasés.
Décision : Utilisez un override systemd pour les options de montage si vous voulez que ce soit persistant et sûr pour les mises à jour.
Task 9: Voir si /tmp est tmpfs (ça peut dépendre de vos choix)
cr0x@server:~$ findmnt /tmp
TARGET SOURCE FSTYPE OPTIONS
/tmp /dev/nvme0n1p2[/tmp] ext4 rw,relatime
Sens : /tmp est sur disque ici. S’il était tmpfs, vous verriez tmpfs et des options de montage incluant size=.
Décision : Si votre incident concerne /tmp et qu’il est sur disque, tmpfs n’est pas votre méchant.
Task 10: Mesurer l’usage de mémoire partagée par processus (quand /dev/shm est le point chaud)
cr0x@server:~$ ps -eo pid,comm,rss,shr,%mem --sort=-shr | head -n 8
PID COMMAND RSS SHR %MEM
18422 python3 6210040 2101240 38.0
19211 python3 1180240 922120 7.2
1123 gnome-shell 412320 210800 2.5
Sens : SHR est large pour le processus python. Ce n’est pas un proxy parfait, mais c’est un bon signal directionnel.
Décision : Ciblez ce service. Si c’est un problème à l’échelle de la flotte, vous avez maintenant une requête « top talkers » rapide à automatiser.
Task 11: Vérifier les limites des cgroups mémoire (commun dans les conteneurs et services systemd)
cr0x@server:~$ systemctl show myapp.service -p MemoryMax -p MemoryHigh -p MemoryCurrent
MemoryMax=infinity
MemoryHigh=infinity
MemoryCurrent=9312415744
Sens : Le service n’a pas de plafond mémoire. S’il utilise tmpfs massivement, il peut manger l’hôte.
Décision : Envisagez de définir MemoryHigh et MemoryMax pour que le service soit throttlé/tué avant que le nœud entier ne meure.
Task 12: Vérifier si le swap masque le problème (jusqu’à l’explosion)
cr0x@server:~$ swapon --show
NAME TYPE SIZE USED PRIO
/dev/sda2 partition 4G 3.9G -2
Sens : Le swap est presque entièrement utilisé ; les performances seront dégradées et la prochaine allocation pourrait déclencher un OOM.
Décision : Arrêtez la croissance tmpfs. Ajouter du swap peut acheter du temps, mais ce n’est pas une solution responsable à long terme.
Task 13: Identifier les répertoires tmpfs lourds sous /run (coupable classique : fichiers d’exécution en fuite)
cr0x@server:~$ sudo du -xh --max-depth=1 /run | sort -h | tail -n 8
4.0M /run/systemd
12M /run/udev
64M /run/user
1.2G /run/myapp
1.9G /run
Sens : /run/myapp est énorme. Quelque chose traite l’état d’exécution comme du stockage.
Décision : Corrigez l’appli : les répertoires runtime doivent être limités, tournés, ou déplacés sur disque s’ils sont volumineux.
Task 14: Vérifier si tmpfs est contraint par l’épuisement d’inodes (oui, ça arrive)
cr0x@server:~$ df -ih /run
Filesystem Inodes IUsed IFree IUse% Mounted on
tmpfs 800K 792K 8.0K 99% /run
Sens : Vous êtes à court d’inodes sur tmpfs. Vous pouvez être « plein » même quand des octets sont disponibles.
Décision : Trouvez et supprimez le spam de fichiers. Si c’est un comportement attendu, augmentez la limite d’inodes via les options de montage ou déplacez cette charge hors de tmpfs.
Task 15: Remonter un tmpfs avec un plafond temporaire (mitigation d’incident)
cr0x@server:~$ sudo mount -o remount,size=4G /dev/shm
cr0x@server:~$ findmnt -no TARGET,OPTIONS /dev/shm
/dev/shm rw,nosuid,nodev,size=4G,inode64
Sens : Vous venez de poser un plafond dur à 4G. Les écritures au‑delà renverront ENOSPC.
Décision : Ne faites cela que si vous comprenez l’impact applicatif. C’est une garde‑fou, pas une cure.
Task 16: Rendre le plafond persistant avec un drop‑in systemd
cr0x@server:~$ sudo systemctl edit dev-shm.mount
# editor opens; add:
# [Mount]
# Options=rw,nosuid,nodev,size=4G,mode=1777
cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart dev-shm.mount
cr0x@server:~$ findmnt -no TARGET,OPTIONS /dev/shm
/dev/shm rw,nosuid,nodev,size=4G,mode=1777,inode64
Sens : La limite survit aux redémarrages. mode=1777 préserve le comportement de permissions typique pour la mémoire partagée.
Décision : Passez cela en change control si votre parc comprend des applis qui dépendent de gros segments de mémoire partagée (bases de données, navigateurs, pipelines ML).
Comment tmpfs utilise réellement la mémoire (et pourquoi « Size » ment)
tmpfs stocke le contenu des fichiers dans des pages mémoire gérées par le noyau. Ça ressemble à « la RAM est allouée », mais l’allocation a lieu lorsque vous écrivez. Le size= que vous voyez dans df est un maximum, appliqué comme un quota. Il ne réserve pas la mémoire à l’avance.
Où la mémoire apparaît‑t‑elle ? Typiquement dans un mélange de :
- Shmem dans
/proc/meminfo(mémoire partagée et pages tmpfs). - Cached qui peut rester non négligeable, parce que les pages tmpfs sont toujours des objets de cache de pages, mais comptabilisées différemment que le cache de fichiers depuis des périphériques bloc.
- Swap, si le système est sous pression et que ces pages peuvent être swappées.
Ce dernier point trompe les humains. « tmpfs peut swapper » semble rassurant. En pratique, si votre tmpfs contient des données actives et commence à swapper, vous avez alors :
- une application qui s’attend à des fichiers en RAM rapide,
- un noyau qui essaie de la maintenir en paginant,
- et un disque qui fait de son mieux pour ressembler à un grille‑pain en pleurs.
Blague #2 : si votre plan d’intervention est « laisser tmpfs swapper », votre disque vient d’être mis à la rotation d’astreinte.
tmpfs vs « ramdisk » sur Ubuntu
On dit souvent « ramdisk » comme terme générique. Il y a deux choses très différentes :
- tmpfs : dynamique, orienté fichiers, peut swapper, utilise la mémoire au besoin jusqu’à une limite.
- brd/ramdisk : un périphérique bloc en RAM de taille fixe (moins courant dans l’exploitation Ubuntu quotidienne aujourd’hui).
La plupart des « problèmes de ramdisk » sur Ubuntu 24.04 sont des problèmes tmpfs : /dev/shm, /run, ou un tmpfs monté par systemd ou le runtime de conteneurs.
Quand la croissance tmpfs est « normale »
Certaines charges ont légitimement besoin de fichiers en mémoire :
- IPC à haute fréquence utilisant la mémoire partagée POSIX.
- Systèmes de build qui créent d’immenses arbres temporaires et profitent de la vitesse de la RAM (sur des builders à grande mémoire).
- Certains feature stores ML et caches de serving de modèles (si correctement dimensionnés et limités).
« Normal » a deux propriétés : c’est borné et récupérable. Un tmpfs non borné n’est qu’une fuite mémoire avec des étapes supplémentaires.
Poser des limites sûres sans casser les applis
Votre objectif n’est pas « rendre tmpfs petit ». Votre objectif est « localiser la défaillance ». Quand tmpfs est illimité (ou effectivement tel), un composant fautif peut priver l’hôte entier. Quand tmpfs est raisonnablement plafonné, le composant reçoit ENOSPC et échoue d’une façon que votre monitoring et votre logique de retry peuvent gérer.
Choisir la bonne cible à plafonner
Ne plafonnez pas tout au hasard. Commencez par les montages à la fois écriture‑intensifs et faciles à abuser :
/dev/shm: souvent abusé comme répertoire scratch rapide. Il est aussi utilisé pour de l’IPC légitime ; soyez prudent./run: ne devrait pas contenir de grosses données. Si c’est le cas, quelque chose ne va pas. Le plafonnement peut aider, mais la correction du writer est plus importante.- Montages tmpfs personnalisés créés pour des caches applicatifs : ceux‑ci devraient toujours avoir des limites explicites de taille et d’inodes.
Règles empiriques de dimensionnement (opinion)
- /run : normalement quelques centaines de Mo suffisent sur des serveurs typiques. Si vous avez besoin de plus de 1–2G, la conception des répertoires runtime est discutable.
- /dev/shm : dimensionnez selon le plus gros utilisateur légitime de mémoire partagée. Si vous n’en avez pas, plafonnez‑le. Plafonds courants : 1G–4G sur hôtes petits/moyens.
- tmpfs applicatif : dimensionnez‑le pour ce que vous pouvez vous permettre de perdre sans swaper l’hôte en bouillie. Implémentez ensuite nettoyage/TTL dans l’appli.
Privilégiez « le déplacer sur disque » plutôt que « rendre tmpfs infini »
Si une appli veut écrire 20 Go de données « temporaires », ce n’est pas un cas d’utilisation tmpfs. Mettez‑les sur disque. Utilisez :
/var/tmppour des données temporaires qui peuvent survivre au reboot et être volumineuses.- Un répertoire dédié sur un stockage rapide (NVMe) avec quotas si nécessaire.
- Répertoires par service avec ownership et mode gérés par systemd (
StateDirectory=,CacheDirectory=,RuntimeDirectory=).
Mode de défaillance : ENOSPC est une fonctionnalité, pas un bug
Quand vous plafonnez tmpfs, l’appli finira par recevoir « No space left on device ». C’est bien : c’est explicite. L’alternative « mauvaise » est que « le noyau a tué votre base de données parce qu’un sidecar a rempli /dev/shm ».
Votre travail est de s’assurer que l’appli réagit correctement à ENOSPC : reculer, tourner les fichiers, purger le cache, ou échouer vite avec une alerte claire. Si elle plante, cela peut néanmoins être une amélioration par rapport à l’effondrement de l’hôte — selon votre redondance.
Réglages systemd importants sur Ubuntu 24.04
Ubuntu 24.04 est centré systemd. C’est bien : la configuration est centralisée, et les montages sont des unités avec une propriété claire. C’est mauvais si vous continuez à éditer /etc/fstab par habitude et que vous vous demandez pourquoi votre changement n’applique pas à un montage géré par systemd.
Contrôler /dev/shm via dev-shm.mount
/dev/shm est généralement géré par dev-shm.mount. Utilisez un override drop‑in pour définir des options comme size=, mode=, et éventuellement nr_inodes= si l’épuisement d’inodes est un vrai souci.
Si vous le plafonnez, faites‑le intentionnellement :
- Sachez quelles applis utilisent la mémoire partagée POSIX (extensions PostgreSQL, outils basés sur Chromium, certains patterns JVM IPC, frameworks ML).
- Testez sous charge. Les échecs de mémoire partagée peuvent être subtils.
- Déployez progressivement dans la flotte. Les plafonnements tmpfs sont le genre de changement qui « marche en staging » puis rencontre le trafic réel en production avec un churn de fichiers différent.
Contrôler /run : corrigez plutôt le writer que le montage
Un /run plein est presque toujours un comportement fautif : fichiers de logs, spools ou caches dans un répertoire runtime. Vous pouvez plafonner /run, mais vous risquez de casser le démarrage si des services critiques ne peuvent pas créer sockets et fichiers PID.
Mieux : identifiez le gros répertoire (Task 13), puis corrigez le service. Corrections courantes :
- Déplacer les artefacts runtime volumineux vers
/var/lib/myapp(état) ou/var/cache/myapp(cache). - Utiliser les directives d’unité systemd :
StateDirectory=,CacheDirectory=,RuntimeDirectory=, et définirLogsDirectory=si pertinent. - Auditer le nettoyage au redémarrage : les fichiers runtime obsolètes peuvent s’accumuler si l’appli n’écrase qu’en append.
Protections par service : MemoryMax, MemoryHigh et consorts
Si l’usage tmpfs est causé par un service unique, vous pouvez l’empêcher de prendre tout l’hôte en le plaçant dans un cgroup mémoire avec des limites.
Position pratique :
- MemoryHigh est un seuil de pression ; il bride les allocations et fait ressentir la douleur au service en premier.
- MemoryMax est le plafond dur ; le franchir peut déclencher des kills.
Cela ne « répare » pas tmpfs, mais limite le rayon d’impact. En production, le rayon d’impact est souvent l’essentiel du jeu.
Conteneurs : pièges tmpfs Docker et Kubernetes
tmpfs devient plus problématique dans les conteneurs parce que vous ajoutez au moins deux couches de malentendus :
- Le système de fichiers du conteneur peut être overlayfs, et des montages tmpfs peuvent être injectés par conteneur.
- La comptabilité mémoire est basée sur les cgroups ; l’hôte et le conteneur peuvent diverger sur la notion de « mémoire libre ».
- Kubernetes
emptyDiravecmedium: Memoryest littéralement tmpfs. Ce n’est pas un « disque éphémère rapide ». C’est de la RAM.
Docker : les montages tmpfs doivent être dimensionnés explicitement
Si vous utilisez des montages tmpfs Docker (par ex. --tmpfs /tmp), spécifiez la taille. Sinon vous autorisez implicitement une croissance contrainte surtout par les limites hôte et conteneur.
Sachez aussi : les limites mémoire du conteneur peuvent transformer les écritures tmpfs en OOM immédiat dans le conteneur. C’est mieux que de tuer l’hôte, mais c’est quand même un incident de service.
Kubernetes : emptyDir en mémoire n’est pas gratuit
Kubernetes facilite la création de volumes en mémoire. Il est aussi facile d’oublier de définir :
- Requests/limits pour la mémoire du conteneur.
- Limites de taille pour le volume (selon vos politiques de cluster et versions/fonctionnalités).
- Seuils d’éviction pour éviter que les nœuds ne se retrouvent bloqués.
Le pattern que je recommande : si vous utilisez des volumes en mémoire, traitez‑les comme des caches. Bornez‑les, définissez un TTL, et acceptez que l’éviction arrive.
Swap, zram et l’illusion « tmpfs a bouffé la RAM »
Ubuntu 24.04 peut être déployé avec ou sans swap, et certains environnements utilisent zram. Cela change la sensation d’un incident tmpfs :
- Sans swap : la croissance tmpfs atteint plus vite l’OOM, mais au moins vous ne passez pas 30 minutes en « swap‑death » avant que cela arrive.
- Swap sur disque : les pages tmpfs peuvent être swappées. Cela peut maintenir la machine « vivante » tout en la rendant inutilisable.
- zram : le swap compressé en RAM peut absorber une partie de la pression. Il peut aussi masquer plus longtemps un tmpfs en fuite, puis échouer de manière plus confuse.
Si votre tmpfs est utilisé pour des fichiers de travail « chauds », les swapper est contre‑productif. Cette charge devrait être sur disque (rapide, mais disque) ou explicitement bornée pour qu’elle ne force pas le swap.
Règle opérationnelle : si l’utilisation du swap augmente en parallèle avec la croissance tmpfs, vous ne « sauvez » pas de mémoire. Vous payez des intérêts dessus.
Trois mini‑histoires d’entreprise du terrain
Mini‑histoire 1 : L’incident causé par une mauvaise hypothèse
Ils avaient une flotte de serveurs Ubuntu exécutant un service de traitement de données. Un membre d’équipe avait lu que tmpfs « utilise jusqu’à la moitié de la RAM », a vu /dev/shm afficher une grande Size dans df, et a supposé que c’était préalloué. Il a ouvert un ticket : « Ubuntu gaspille 32 Go sur /dev/shm ».
La « correction » fut rapide et confiante : plafonner /dev/shm à quelque chose de minuscule sur toute la flotte. C’était déployé en heures ouvrables parce que le changement semblait inoffensif. Le batch suivant a démarré, et un composant qui utilisait la mémoire partagée POSIX a commencé à échouer de manière intermittente. Pas de crash net — juste une corruption d’état de workflow quand les allocations de mémoire partagée échouaient en plein vol.
L’incident n’était pas que la mémoire partagée était utilisée. C’était l’hypothèse que la Size affichée était de la mémoire gaspillée. En réalité, le service utilisait la mémoire partagée raisonnablement sous charge normale ; le plafond l’a cassé en le faisant échouer sous charge légitime.
Ils ont récupéré en revenant en arrière sur le plafond, puis en faisant le travail ennuyeux : mesurer le Shmem réel pendant la charge de pointe, identifier le haut niveau légitime, et poser un plafond juste au‑dessus. Ils ont ensuite ajouté la gestion applicative des échecs d’allocation pour éviter la corruption silencieuse.
Le postmortem fut simple : df montre des limites, pas des allocations. Les incidents mémoire se règlent rarement par une « optimisation globale » unique.
Mini‑histoire 2 : L’optimisation qui s’est retournée contre eux
Une autre organisation avait une API sensible à la latence. Quelqu’un a décidé d’accélérer le traitement des requêtes en déplaçant un cache JSON et un répertoire de rendu temporaire dans tmpfs. Ça fonctionnait en benchmark : le p99 s’améliorait, les disques restaient plus calmes, les graphiques étaient superbes.
Puis une campagne marketing a frappé, le trafic a triplé, et le cache est passé de « utile » à « non borné ». Le tmpfs s’est rempli. Le cache n’avait pas d’éviction ; il avait de l’espoir. La pression mémoire a monté, le swap s’est rempli, et le nœud est devenu un échec au ralenti où les health checks time‑out et l’orchestrateur remplaçait les instances.
Le pire : la vague de remplacements a amplifié le problème. Les instances froides ont regarni le cache, remplissant à nouveau tmpfs, provoquant un brownout progressif au lieu d’un crash net. L’équipe a passé des heures à traquer des « problèmes réseau » parce que tout devenait lent simultanément.
La vraie correction fut peu glamour : remettre le cache sur disque (NVMe local rapide), implémenter une éviction LRU, et poser des limites explicites. Ils ont gardé un petit tmpfs pour des données vraiment chaudes — kilo‑octets à quelques mégaoctets — pas des gigaoctets. Les performances sont restées bonnes, et le mode de défaillance est devenu gérable.
Mini‑histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Un service lié aux paiements tournait sur Ubuntu avec des exigences de fiabilité strictes. L’équipe avait une checklist pour chaque classe de nœud : vérifier les options de montage tmpfs, plafonner /dev/shm selon la charge, et définir des limites mémoire par service via systemd. C’était du travail d’hygiène dont personne ne tweete.
Un après‑midi, une nouvelle version d’un worker a commencé à écrire des artefacts de debug dans /run. Un flag de fonctionnalité avait été mal appliqué ; au lieu d’échantillonner 1 % du trafic, il a échantillonné quasiment tout. Les fichiers étaient petits, mais le nombre était énorme, et la consommation d’inodes a explosé.
Sur une configuration moins disciplinée, /run aurait rempli et pris en otage des fonctions système de base. Sur leurs nœuds, /run avait une surveillance de l’usage d’inodes et le service avait un plafond mémoire. Le service a commencé à échouer, les alertes ont sonné avec un signal clair « pression d’inodes /run », et l’hôte est resté assez sain pour que les opérateurs se connectent sans se battre contre un système à moitié mort.
La remédiation fut rapide : désactiver le flag, déployer un patch, et purger le répertoire runtime. Pas d’incident en cascade. La pratique ennuyeuse n’a pas empêché le bug, mais l’a contenu.
Erreurs courantes : symptôme → cause → correction
1) « df montre /dev/shm énorme, donc Ubuntu gaspille de la RAM »
Symptôme : df -h affiche tmpfs Size = moitié (ou plus) de la RAM.
Cause : Confusion entre le maximum tmpfs et l’allocation réelle.
Correction : Vérifiez la colonne Used dans df et Shmem dans /proc/meminfo. N’agissez que si l’usage croît.
2) « L’hôte OOM, mais du montre que tmpfs est petit »
Symptôme : df rapporte un tmpfs plein ; du ne correspond pas.
Cause : Fichiers supprimés mais encore ouverts sur tmpfs.
Correction : Utilisez lsof +L1, redémarrez le processus fautif, et confirmez que l’espace est libéré.
3) « Nous avons plafonné /dev/shm et maintenant des applis cassent »
Symptôme : Échecs intermittents, erreurs IPC, crashes étranges après le changement.
Cause : Un consommateur légitime de mémoire partagée POSIX a dépassé le nouveau plafond.
Correction : Mesurez le pic de consommation SHM, augmentez le plafond en conséquence, ou reconfigurez l’application pour utiliser un stockage temporaire sur disque là où c’est acceptable.
4) « /run s’est rempli et la machine a eu un comportement fantomatique »
Symptôme : Services incapables de démarrer, fichiers PID manquants, sockets qui échouent, connexions étranges.
Cause : Quelque chose a écrit beaucoup de données ou trop de fichiers dans /run (octets ou inodes).
Correction : Identifiez les sous‑répertoires volumineux (du -x, df -ih), déplacez le writer vers /var/lib ou /var/cache, ajoutez nettoyage et rotation.
5) « Nous avons mis /tmp sur tmpfs pour la vitesse et maintenant les builds plantent »
Symptôme : Compilateurs et outils échouent avec ENOSPC ou OOM durant de gros builds.
Cause : Les fichiers temporaires de build sont volumineux ; tmpfs était un mauvais choix pour la RAM disponible.
Correction : Gardez /tmp sur disque, ou fournissez un chemin disque rapide dédié et pointez les outils de build dessus.
6) « Des pods Kubernetes OOMKilled après avoir mis emptyDir en mémoire »
Symptôme : Pods redémarrent sous charge ; la mémoire du nœud semble tendue.
Cause : emptyDir avec medium: Memory consomme la mémoire comptée contre les limites pod/conteneur.
Correction : Définissez requests/limits mémoire, plafonnez l’usage tmpfs, ou repassez à emptyDir sur disque et optimisez la charge.
7) « Nous avons remounté tmpfs plus petit et maintenant les écritures échouent »
Symptôme : Erreurs ENOSPC immédiates après la mitigation.
Cause : L’ensemble de travail dépassait déjà votre nouvelle limite ; remonter ne réduit pas magiquement les pages utilisées.
Correction : Réduisez d’abord l’usage (supprimez fichiers, redémarrez processus tenant des fichiers supprimés), puis remontez avec une limite plus basse.
Listes de contrôle / plan étape par étape
Confinement de l’incident (15–30 minutes)
- Localiser le montage : exécutez
df -hTet trouvez le tmpfs avec un Used% élevé. - Confirmer la pression mémoire : vérifiez
/proc/meminfopourMemAvailable,Shmemet le swap. - Trouver le grand répertoire :
du -xh --max-depth=1sur ce montage. - Trouver l’écrivain :
lsof +Doulsof/fuserciblés. - Vérifier les supprimés mais ouverts :
lsof +L1. - Stopper la croissance : pausez le job, réduisez le déploiement, ou redémarrez le service tenant l’espace.
- Garde‑fou si nécessaire : remontez tmpfs avec un
size=temporaire seulement si vous pouvez tolérer ENOSPC. - Stabiliser : assurez‑vous que le swap n’est pas saturé ; si c’est le cas, envisagez de redémarrer les pires fautifs pour récupérer la mémoire rapidement.
Correction permanente (même jour)
- Décider quelles données doivent être en tmpfs : IPC et petits caches chauds uniquement.
- Déplacer les gros scratchs sur disque : changez la config applicative pour utiliser
/var/tmpou un chemin dédié. - Poser des limites tmpfs explicites : utilisez des overrides systemd pour
/dev/shmou vos montages personnalisés. - Ajouter des nettoyages : TTL, éviction basée sur la taille, ou rotation. « On nettoiera plus tard » est la façon dont tmpfs devient une arme.
- Ajouter du monitoring : alertez sur le Used% et l’usage d’inodes de tmpfs (
df -ih), plus MemAvailable et swap. - Ajouter des contrôles de rayon d’impact : MemoryHigh/MemoryMax systemd pour les pires coupables.
Renforcement de la flotte (sprint suivant)
- Standardiser les politiques de montage : par classe de nœud, définir des plafonds tmpfs et documenter quelles applis ont besoin d’une grande mémoire partagée.
- Politique conteneur : exiger des limites mémoire explicites et interdire les volumes en mémoire non bornés pour des données non‑cache.
- Tester les modes de défaillance : forcer ENOSPC sur tmpfs en staging et vérifier que les applis se dégradent de façon prévisible (pas de corruption, pas de blocage).
- Auditer l’usage de /run : les répertoires runtime ne doivent pas contenir de gros datasets ; faire respecter en review de code et packaging.
FAQ
1) Est‑ce que tmpfs utilise réellement la RAM ou juste de la mémoire « virtuelle » ?
Il utilise de vraies pages mémoire au fur et à mesure que les données sont écrites. Ces pages peuvent être swappées sous pression, mais elles comptent quand même dans la comptabilité mémoire du système.
2) Pourquoi tmpfs affiche une Size égale à la moitié de ma RAM ?
C’est un maximum par défaut. Ce n’est pas préalloué. La colonne Used est celle qui compte, ainsi que Shmem dans /proc/meminfo.
3) Dois‑je monter /tmp en tmpfs sur Ubuntu 24.04 ?
Seulement si vous l’avez dimensionné et testé pour vos charges. Sur des serveurs à usage général, garder /tmp sur disque est plus sûr. Si vous utilisez tmpfs, plafonnez‑le et planifiez ENOSPC.
4) Puis‑je simplement augmenter le swap pour résoudre les pics tmpfs ?
Augmenter le swap achète du temps, pas de la correction. Cela peut transformer un échec net en brownout lent. Corrigez le writer et posez des limites.
5) Quel est l’endroit le plus sûr pour mettre de gros fichiers temporaires ?
Utilisez le disque : /var/tmp ou un répertoire dédié sur un stockage rapide. Si vous avez besoin de performance, utilisez NVMe et réservez tmpfs aux petites données chaudes.
6) Pourquoi « df dit plein » mais « du dit petit » sur tmpfs ?
Généralement des fichiers supprimés mais encore ouverts. Les entrées de répertoire ont disparu, mais le processus tient toujours le descripteur. Utilisez lsof +L1 et redémarrez le processus.
7) Si je plafonne /dev/shm, vais‑je casser des choses ?
Possiblement. Certains logiciels utilisent légitimement la mémoire partagée. Mesurez l’utilisation réelle sous pointe, posez un plafond au‑dessus et testez. Choisir au hasard « 512M semble OK » est la voie vers du travail le week‑end.
8) Comment plafonner tmpfs de façon persistante sur Ubuntu 24.04 ?
Pour les montages gérés par systemd comme /dev/shm, créez un override via systemctl edit dev-shm.mount et définissez Options=...size=....
9) /run est‑il censé être tmpfs ?
Oui. C’est pour l’état d’exécution qui ne doit pas persister après reboot. S’il est énorme, quelque chose l’abuse.
10) Est‑ce que tmpfs a aussi des limites d’inodes ?
Oui. Vous pouvez manquer d’inodes avant les octets. Vérifiez avec df -ih. Si l’usage d’inodes est élevé, trouvez le spam de fichiers et corrigez le générateur.
Prochaines étapes à faire aujourd’hui
tmpfs n’est pas un bug dans Ubuntu 24.04. C’est un outil tranchant. Les échecs surviennent quand vous le traitez comme un espace scratch infini et oubliez qu’il partage la même RAM dont vos applications ont besoin pour respirer.
Faites ceci dans l’ordre :
- Identifiez quel tmpfs grossit (
df -hT), puis vérifiez que c’est une pression réelle (/proc/meminfo). - Trouvez le répertoire et le processus responsable (
du,lsof,lsof +L1). - Déplacez les grosses données temporaires sur disque, et plafonnez les tmpfs là où l’abus est probable (surtout
/dev/shm), en utilisant des overrides systemd. - Ajoutez du monitoring pour les octets et les inodes de tmpfs, plus mémoire/swap, pour que ce soit une alerte que vous voyez venir — pas une panne mystérieuse.
- Contenez le rayon d’impact avec des limites mémoire par service quand c’est pertinent.
Si vous ne faites rien d’autre : plafonnez intentionnellement les montages tmpfs risqués, et faites en sorte que les applications gèrent ENOSPC comme des adultes. Votre noyau vous remerciera en ne choisissant pas de victimes à 3 h du matin.