Histoires « rm -rf / » : la commande devenue un genre d’horreur IT

Cet article vous a aidé ?

Chaque équipe ops a une histoire de fantôme. Pas du genre « la salle des serveurs est hantée » — ce sont pour la plupart des problèmes de flux d’air et des portes d’armoire mal fermées.
Je veux dire l’histoire qui commence par une fenêtre de maintenance calme et se termine par une console qui renvoie le même vide qu’un frigo vide.

rm -rf / est le croque-mitaine, certes, mais le vrai méchant est toujours le même : la certitude humaine appliquée à un système incertain.
Voici comment la commande est devenue un genre, ce qui casse réellement quand elle s’exécute (ou manque de s’exécuter), et ce que vous devriez faire pour que votre nom ne devienne jamais une légende chez d’autres.

Ce que rm -rf / signifie vraiment (et pourquoi c’est pire que ça en a l’air)

Sur le papier, rm supprime des entrées de répertoire. En pratique, sur un système en production, il supprime les chemins dont votre OS a besoin pour rester un OS.
Les options sont ce qui en fait une légende :

  • -r (récursif) : parcourir l’arborescence, supprimer tout ce qu’on peut atteindre.
  • -f (force) : ne pas poser de questions ; supprimer de nombreuses erreurs ; continuer malgré tout.
  • / : commencer à la racine, le sommet de presque tout ce qui vous importe.

« Presque » fait beaucoup de travail là-dedans. Linux n’est pas un gros tas unique de fichiers. C’est un empilement de montages : système de fichiers racine, /boot séparé,
/var, /home, /run éphémère, montages réseau, bind mounts, montages overlay de conteneurs, et tout ce que votre équipe plateforme a bricolé pendant un incident il y a trois ans.

rm -rf / tente de traverser toute cette topologie. Jusqu’où il ira dépend des frontières de montage, des permissions, des attributs immuables,
si vous êtes root, si vous êtes dans un conteneur, et si votre distribution a des garde-fous. Mais même « partiel » est catastrophique : supprimer
assez de /lib ou /usr peut transformer chaque processus en cours en touriste condamné — vivant un moment, mais incapable de charger
la prochaine bibliothèque partagée, d’exécuter le prochain binaire, ou de redémarrer le service que vous tentiez de réparer.

Une façon pratique de le penser : vous ne « supprimez pas l’OS », vous supprimez les hypothèses qui permettent à l’OS de continuer à se réparer lui-même.
La plupart des incidents de production ne sont pas des explosions dramatiques. Ce sont des systèmes qui perdent la capacité de récupérer de petites défaillances.

Blague n°1 : Le moyen le plus rapide d’apprendre la reprise après sinistre est de taper rm -rf / une fois. Le deuxième plus rapide est de voir votre collègue le faire.

Il y a un autre twist : sur les systèmes modernes, la commande que vous avez tapée n’est pas toujours celle qui s’exécute. Les alias de shell, les wrappers (bons ou mauvais),
et les couches d’automatisation peuvent changer la sémantique. Si vous êtes dans un conteneur, / peut être le système du conteneur, pas l’hôte — sauf si vous
avez monté l’hôte dedans. Dans Kubernetes, vous pouvez supprimer un déploiement et le recréer ; supprimer le mauvais PersistentVolumeClaim et vous êtes en plein entraînement.

Le danger plus profond : supprimer des « noms » alors que des processus tournent encore

Unix permet à un processus de garder un fichier ouvert même après qu’il a été désinscrit (unlinked). C’est une fonctionnalité — jusqu’à ce que ça ne le soit plus.
Quand vous supprimez un fichier de log utilisé par un processus en cours, l’utilisation disque peut ne pas baisser, parce que l’inode est toujours retenu.
Quand vous supprimez des bibliothèques partagées sous un service en cours, le service peut continuer à fonctionner jusqu’au prochain reload, déploiement progressif, crash, ou fork/exec.
C’est pourquoi certains incidents rm -rf semblent « corrects » pendant des minutes ou des heures, puis se délitent au pire moment : au redémarrage, pendant un basculement, ou après un reboot du nœud.

Comment cela arrive réellement en entreprise

La plupart des équipes imaginent un incident « rm -rf / » comme un admin ennuyé faisant quelque chose de cartoonispement imprudent. La réalité est plus terne et plus dangereuse :
c’est un ingénieur fatigué, un délai serré, un copier-coller, un shell de production qui ressemble à celui de staging, et une commande qui « a toujours marché avant ».

Le genre persiste parce que c’est la tempête parfaite d’anti-patterns opérationnels :

  • Intention ambiguë : « Nettoyer le disque » n’est pas une tâche ; c’est un symptôme.
  • Commandes réflexes : rm -rf devient un réflexe plutôt qu’une décision.
  • Dérive de privilèges : vous avez eu sudo « temporairement », et il est resté.
  • Confusion d’environnement : les shells prod vs stage diffèrent d’un seul titre d’onglet.
  • Automatisation sans freins : la commande était dans un script, un outil ou un job.

Je suis catégorique : si un système exige que des humains suppriment régulièrement des fichiers sous pression, le système manque d’une couche de sécurité. Les humains ne sont pas
des couches de sécurité. Les humains sont la raison pour laquelle nous avons besoin de couches de sécurité.

Faits et histoire : comment nous en sommes arrivés là

Cette commande n’est pas devenue un mème par accident. Un peu d’histoire concrète vous aide à prédire comment votre environnement se comportera :

  1. Les premiers Unix faisaient de la suppression une opération volontairement simple. La philosophie favorisait les petits outils et la composabilité ; les garde-fous étaient culturels, pas techniques.
  2. rm supprime des entrées de répertoire, pas « efface en toute sécurité ». Les données peuvent persister sur le disque jusqu’à être réécrites ; c’est pourquoi les outils de récupération fonctionnent parfois.
  3. La « protection du répertoire racine » a évolué dans le temps. GNU coreutils a introduit des défauts --preserve-root dans de nombreuses distributions pour empêcher rm -rf /.
  4. BusyBox et les systèmes embarqués diffèrent. Certains environnements ont des implémentations plus petites ou différentes de rm ; les hypothèses venant des serveurs ne s’appliquent pas toujours.
  5. Les espaces de noms de montage ont changé le rayon d’impact. Les conteneurs et chroots peuvent faire en sorte que « / » signifie autre chose — jusqu’à ce que vous montiez l’hôte dedans.
  6. Systemd a accru la dépendance à /run et aux états générés. Supprimer sous /run peut casser les services immédiatement de manière étrange.
  7. Les systèmes de fichiers Copy-on-Write ont changé les probabilités de récupération. ZFS/Btrfs et leurs snapshots peuvent rendre un « oups » récupérable — si des snapshots existent et que la rétention est raisonnable.
  8. L’automatisation ops a transformé une erreur unique en événement de flotte. Un mauvais rm dans une exécution de gestion de configuration peut se propager rapidement.

Remarquez le schéma : chaque ère ajoute de la puissance, puis ajoute de nouvelles façons d’appliquer cette puissance largement. C’est pourquoi le genre continue d’avoir de nouvelles suites.

Modes d’échec : ce qui casse en premier, en second, et de façon étrange plus tard

1) Cassure immédiate : les binaires et bibliothèques disparaissent

Supprimez assez de /bin, /sbin, /usr/bin, /lib, /lib64, et vous perdez la capacité d’exécuter des commandes,
de redémarrer des daemons, ou même d’authentifier. Les sessions SSH peuvent rester, mais toute nouvelle tentative de connexion peut échouer si des modules PAM ou des shells manquent.

2) Échec au ralenti : le système continue… jusqu’à ce qu’il ait besoin d’exécuter

Les processus en cours peuvent continuer à exécuter du code déjà en mémoire. C’est pourquoi le premier graphique que vous voyez peut être « tout vert ».
Puis un reload de service survient. Un nouveau worker tente de démarrer. Une vérification de santé déclenche un redémarrage. Et soudain la machine ne peut plus lancer le processus
qui aurait réparé le service.

3) Confusion plan de données vs plan de contrôle

Dans les systèmes modernes, le plan de contrôle (orchestration, agents, gestionnaires de paquets, configuration) est ce qui remet le plan de données en marche.
rm -rf tue souvent le plan de contrôle en premier : les binaires des agents disparaissent, les services système s’arrêtent, les configs DNS disparaissent, les certificats manquent.
Maintenant « réinstaller le paquet » devient « comment lancer l’installateur ? »

4) Douleurs spécifiques au stockage : suppressions partielles, état applicatif incohérent

Les systèmes de fichiers ne garantissent pas la cohérence au niveau applicatif. Si vous supprimez des parties d’un répertoire de base de données, vous pouvez obtenir quelque chose de pire que « hors service » :
vous obtenez « en service mais ment ». Certaines bases refusent de démarrer si des fichiers manquent (bon). D’autres démarrent et servent des données partielles (mauvais).
Si vous êtes sur un stockage en réseau, les suppressions peuvent être asynchrones ou retardées par la mise en cache.

5) Nuances de virtualisation et conteneurs

Sur un hôte, supprimer / est généralement fatal. Dans un conteneur, cela peut être une couche réinitialisable — sauf si le conteneur a des montages privilégiés ou écrit dans des volumes.
Le schéma d’incident le plus tragique en 2026 n’est pas « quelqu’un a rasé le filesystem du conteneur ».
C’est « quelqu’un a rasé le volume persistant monté parce qu’il ressemblait à un répertoire temporaire ».

Citation (idée paraphrasée) : Tout échoue, et la résilience vient de la conception pour la récupération, pas de la croyance que vous pouvez empêcher toutes les erreurs. — Werner Vogels (idée paraphrasée)

Blague n°2 : La seule chose plus permanente qu’une ressource cloud est une commande delete exécutée avec -f.

Guide de diagnostic rapide

Voici l’ordre de triage que j’utilise quand quelqu’un dit « je crois que j’ai supprimé quelque chose » ou « la machine se comporte comme si elle était hantée » et que les logs sont étrangement silencieux.
Vous tentez de répondre à trois questions rapidement : (1) l’hôte est-il encore fiable, (2) qu’est-ce qui manque, (3) récupérons-nous par réparation, rollback ou reconstruction ?

Premier : confirmer l’étendue et arrêter l’hémorragie

  • Geler l’automatisation : arrêter les exécutions de gestion de config, les cron jobs, les déploiements CI/CD, et l’auto-remédiation qui pourraient continuer à supprimer ou « corriger » la mauvaise chose.
  • Conserver la session : garder tout shell root existant ouvert ; ne pas se déconnecter. Un reboot est souvent un point de non-retour.
  • Identifier si c’est hôte vs conteneur : un conteneur peut être remplacé ; un hôte peut contenir des données uniques.

Deuxième : vérifier si le système peut encore exécuter des outils de base

  • Pouvez-vous lancer /bin/ls ? Si non, vous êtes en territoire reconstruction.
  • /lib est-il assez intact pour le linkage dynamique ? Si les libs partagées sont absentes, beaucoup de commandes renverront « No such file or directory » même si le binaire existe.
  • Le gestionnaire de paquets est-il exécutable ? Si oui, vous pouvez réinstaller des paquets manquants.

Troisième : choisir la voie de récupération selon ce qui importe

  • Si les données sont intactes et que l’OS est reproductible : reconstruire l’hôte et rattacher les volumes de données.
  • Si l’OS est intact et qu’un petit ensemble de fichiers manque : restaurer depuis snapshot/sauvegarde, ou réinstaller des paquets, puis vérifier l’intégrité.
  • Si l’intégrité des données est incertaine : arrêter les services, snapshotter l’état endommagé (si possible), et restaurer dans un environnement propre pour validation.

Localisateur de goulot d’étranglement rapide (quand le système est « lent » après une quasi-incident)

Parfois l’incident est un quasi-accident : la suppression a été interrompue, mais le système boite maintenant — verrous de base de paquets, pic IO disque, relecture du journal, exhaustion d’inodes, ou un processus en boucle scannant le filesystem. Voici le chemin le plus court vers le goulot :

  1. Saturation IO disque ? Vérifiez iostat/pidstat et les indices de latence filesystem.
  2. Filesystem plein ou épuisement d’inodes ? Vérifiez df et df -i.
  3. Une suppression est-elle encore en cours ? Trouvez les processus rm et la traversée de répertoires via lsof et ps.
  4. Confusion de montages ? Vérifiez ce qui est monté où avec findmnt.
  5. Journalisation ou journald en spirale ? Vérifiez les erreurs de journalctl et l’utilisation disque.

Tâches pratiques : commandes, sorties et décisions (12+)

Ce sont des commandes réelles et exécutables. Chacune inclut ce que la sortie signifie et quelle décision elle doit vous forcer à prendre.
Utilisez-les dans l’ordre du moins destructeur au plus invasif.

Tâche 1 : Confirmer où « / » pointe réellement (hôte vs conteneur)

cr0x@server:~$ cat /proc/1/cgroup | head
0::/user.slice/user-1000.slice/session-3.scope

Sens : Si PID 1 est systemd sur l’hôte, vous verrez des slices de l’hôte. Dans les conteneurs, vous voyez souvent des chemins docker/kubepods.
Décision : Si c’est un conteneur, le remplacement peut être préférable à la récupération — sauf si des volumes persistants ont été affectés.

Tâche 2 : Vérifier ce qui est monté et où les suppressions ont pu franchir des frontières

cr0x@server:~$ findmnt -R / | head -n 15
TARGET            SOURCE              FSTYPE  OPTIONS
/                 /dev/nvme0n1p2      ext4    rw,relatime
|-/boot           /dev/nvme0n1p1      ext4    rw,relatime
|-/var            /dev/nvme1n1p1      xfs     rw,relatime
|-/run            tmpfs               tmpfs   rw,nosuid,nodev
`-/mnt/data       tank/data           zfs     rw,xattr,noacl

Sens : Supprimer « / » aurait pu toucher /var et /mnt/data aussi, selon la traversée et les permissions.
Décision : Si des données critiques sont sur des montages séparés, priorisez la préservation et la création de snapshots de ces montages avant de faire quoi que ce soit d’autre.

Tâche 3 : Vérifier si une suppression est encore en cours (arrêter l’hémorragie)

cr0x@server:~$ ps -eo pid,etime,cmd | grep -E 'rm -rf|rm -r|unlink' | grep -v grep
24188       00:02 rm -rf /var/tmp/cache

Sens : Le processus fautif peut encore être en train de parcourir.
Décision : S’il cible le mauvais chemin, arrêtez-le immédiatement (kill ou isolez l’hôte). S’il cible le bon chemin et est nécessaire, envisagez de le throttler plutôt que de le tuer.

Tâche 4 : Confirmer que le système racine n’est pas plein ou en épuisement d’inodes

cr0x@server:~$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/nvme0n1p2   80G   78G  1.2G  99% /

Sens : Vous êtes à une installation de paquet près de l’échec, et les fichiers temporaires ne peuvent pas être créés de façon fiable.
Décision : Si vous avez besoin d’actions de récupération qui écrivent sur le disque (réinstaller des paquets, restaurer des fichiers), libérez d’abord de l’espace — prudemment et avec des suppressions ciblées.

cr0x@server:~$ df -i /
Filesystem       Inodes   IUsed    IFree IUse% Mounted on
/dev/nvme0n1p2  5242880 5242000     880  100% /

Sens : Épuisement d’inodes. Vous pouvez avoir des Go libres mais être incapable de créer des fichiers.
Décision : Cherchez une explosion de petits fichiers (caches, répertoires temporaires). Ne lancez pas de « scripts de nettoyage » qui pourraient vagabonder vers des territoires dangereux.

Tâche 5 : Repérer rapidement les répertoires cœur manquants

cr0x@server:~$ ls -ld /bin /sbin /lib /lib64 /usr /etc
ls: cannot access '/lib64': No such file or directory
drwxr-xr-x 2 root root 4096 Jan 22 09:10 /bin
drwxr-xr-x 2 root root 4096 Jan 22 09:10 /etc
drwxr-xr-x 2 root root 4096 Jan 22 09:10 /lib
drwxr-xr-x 2 root root 4096 Jan 22 09:10 /sbin
drwxr-xr-x 9 root root 4096 Jan 22 09:10 /usr

Sens : Si des répertoires sont complètement manquants, le système est déjà dans un mauvais état ; s’ils sont présents, leur contenu peut quand même être parti.
Décision : Si les chemins cœur manquent, penchez vers la reconstruction et la restauration plutôt que des réparations au coup par coup.

Tâche 6 : Tester si le linkage dynamique est cassé

cr0x@server:~$ /bin/ls --version
/bin/ls: error while loading shared libraries: libselinux.so.1: cannot open shared object file: No such file or directory

Sens : Le binaire existe, mais les bibliothèques partagées requises sont manquantes.
Décision : Ne perdez pas de temps à essayer de « réparer un service ». Si les libs cœur manquent, il faut réinstaller les paquets depuis une source connue bonne, ou reconstruire.

Tâche 7 : Déterminer quel paquet possède un fichier manquant (exemple RPM)

cr0x@server:~$ rpm -qf /usr/bin/ssh
openssh-clients-8.7p1-36.el9.x86_64

Sens : Le paquet qui devrait fournir ce fichier.
Décision : Si le gestionnaire de paquets fonctionne et que les dépôts sont accessibles, réinstallez l’ensemble de paquets pour les binaires manquants — puis vérifiez l’intégrité.

Tâche 8 : Vérifier les signaux d’intégrité du système de fichiers (exemple ext4)

cr0x@server:~$ dmesg | tail -n 12
[ 9832.118331] EXT4-fs warning (device nvme0n1p2): ext4_dx_add_entry:2534: Directory index full!
[ 9832.118899] EXT4-fs (nvme0n1p2): mounted filesystem with ordered data mode. Quota mode: none.

Sens : Vous pouvez avoir des problèmes d’index/répertoire/inode, ou des nombres de fichiers pathologiques.
Décision : Si le kernel avertit sur la structure du filesystem, planifiez un fsck hors-ligne et préparez-vous à reconstruire ; ne continuez pas à marteler le disque.

Tâche 9 : Identifier les fichiers « supprimés mais encore ouverts » consommant de l’espace

cr0x@server:~$ lsof +L1 | head
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NLINK  NODE NAME
java     4121 app   123w  REG  253,0 104857600     0 91827 /var/log/app/app.log (deleted)

Sens : L’espace disque ne sera pas récupéré tant que le processus ne ferme pas le descripteur de fichier.
Décision : Redémarrez le service (prudemment) ou envoyez-lui un signal pour rouvrir les logs. C’est le piège classique « on a supprimé les logs mais le disque reste plein ».

Tâche 10 : Confirmer ce qui a changé récemment (scan mtime avec retenue)

cr0x@server:~$ find /etc -maxdepth 2 -type f -mmin -60 | head
/etc/resolv.conf
/etc/ssh/sshd_config
/etc/systemd/system/app.service

Sens : Montre les fichiers modifiés dans la dernière heure — utile pour corréler à un mauvais script ou un déploiement.
Décision : Si des configs cœur ont changé de façon inattendue, considérez une défaillance d’automatisation ; restaurez les configs via GitOps ou restaurez des versions connues bonnes.

Tâche 11 : État des snapshots ZFS avant de « réparer » quoi que ce soit

cr0x@server:~$ zfs list -t snapshot | tail -n 5
tank/data@hourly-2026-01-22-0800  0B      -    120G  -
tank/data@hourly-2026-01-22-0900  0B      -    120G  -

Sens : Des snapshots existent. C’est votre filet de sécurité, si vous ne le détruisez pas avec un « nettoyage ».
Décision : Si une perte de données est suspectée, clonez le snapshot pour investigation plutôt que de faire un rollback en place.

Tâche 12 : Restaurer un seul répertoire depuis un snapshot ZFS (via clone + rsync)

cr0x@server:~$ zfs clone tank/data@hourly-2026-01-22-0900 tank/restore_tmp
cr0x@server:~$ rsync -aH --numeric-ids /tank/restore_tmp/appstate/ /mnt/data/appstate/
sending incremental file list
./
db/
db/manifest.json
sent 1,284 bytes  received 92 bytes  2,752.00 bytes/sec
total size is 9,812,034  speedup is 7,131.35

Sens : Vous avez restauré uniquement ce dont vous aviez besoin, en préservant propriétaires et hardlinks.
Décision : Préférez une restauration chirurgicale à un rollback complet quand la disponibilité compte et que vous n’êtes pas sûr de l’étendue exacte de la suppression.

Tâche 13 : Listing de snapshot Btrfs et restauration ciblée

cr0x@server:~$ btrfs subvolume list /mnt
ID 256 gen 9012 top level 5 path @
ID 257 gen 9011 top level 5 path @home
ID 410 gen 9001 top level 5 path @snapshots/2026-01-22_0900
cr0x@server:~$ rsync -aH --numeric-ids /mnt/@snapshots/2026-01-22_0900/etc/ /etc/
sending incremental file list
./
ssh/sshd_config
sent 23,110 bytes  received 1,204 bytes  48,628.00 bytes/sec
total size is 214,980  speedup is 8.84

Sens : Vous pouvez traiter les snapshots comme des arbres sources en lecture seule pour la restauration.
Décision : Si vous n’avez pas de snapshots, arrêtez de discuter « on n’en a pas besoin » et commencez à les budgéter.

Tâche 14 : Détecter les alias dangereux et options de shell qui cachent le risque

cr0x@server:~$ alias rm
alias rm='rm -i'

Sens : L’invite interactive peut empêcher des erreurs dans votre shell — mais elle ne protège pas les scripts, cron, ou sessions non interactives.
Décision : Ne comptez pas sur les alias comme sécurité. Utilisez des limites de permissions, des snapshots, et des garde-fous dans les outils.

Tâche 15 : Confirmer le paramètre preserve-root de GNU rm

cr0x@server:~$ rm --help | grep -E 'preserve-root|no-preserve-root'
      --preserve-root   do not remove '/' (default)
      --no-preserve-root   do not treat '/' specially

Sens : Sur ce système, rm refuse par défaut /.
Décision : Bien, mais insuffisant : les scripts peuvent toujours cibler des montages critiques, et quelqu’un peut toujours passer --no-preserve-root.

Tâche 16 : Auditer un script suspect sans l’exécuter

cr0x@server:~$ bash -n /usr/local/bin/cleanup.sh
cr0x@server:~$ shellcheck /usr/local/bin/cleanup.sh | head
In /usr/local/bin/cleanup.sh line 18:
rm -rf "$TARGET_DIR"/*
^-- SC2115 (warning): Use "${var:?}" to ensure this never expands to /* .

Sens : L’analyse statique a repéré un hazard classique d’expansion.
Décision : Si un script de nettoyage peut s’étendre en /*, considérez-le comme une arme chargée. Corrigez-le, ajoutez des garde-fous, et ajoutez des tests.

Trois mini-récits d’entreprise (anonymes, douloureusement plausibles)

Mini-récit 1 : La panne causée par une fausse supposition

Une équipe maintenait une flotte d’hôtes Linux qui exécutaient un mélange de services legacy et de workloads conteneurisés. Ils avaient une « disposition standard » :
les données applicatives vivaient dans /srv/app, et l’OS était sur le volume racine. Le runbook on-call disait : « Si le disque est plein, effacer les anciens fichiers dans
/srv/app/tmp. »

Une nouvelle image d’hôte a été déployée discrètement. Elle avait toujours /srv/app/tmp, mais il s’agissait désormais d’un lien symbolique vers /var/tmp/app pour unifier la gestion des logs et temporaires.
Ce changement n’a jamais été documenté, parce que cela ressemblait à une « refactorisation interne », et les services ne s’en préoccupaient pas.

Une nuit, l’utilisation disque a franchi un seuil. L’on-call s’est connecté, a lancé la commande habituelle pour vider les fichiers temporaires, et a remarqué que ça prenait plus de temps que d’habitude.
Il a ajouté un -f et est parti répondre à un autre page. La suppression parcourait maintenant /var, pas un répertoire temp étroit,
et elle avalait plus que du cache : logs rotatifs, état runtime, et des parties de la base de paquets.

Le service n’a pas planté immédiatement. Il s’est dégradé. Puis le nœud a rebooté à cause d’un schedule de mise à jour du kernel, et le vrai dommage est apparu :
les services système n’ont pas démarré, la résolution DNS a cassé, et le nœud n’a pas pu tirer les images de conteneurs parce que certificats et bundles CA manquaient.
La couche d’orchestration l’a marqué comme non sain et a replanifié les workloads, ce qui a masqué l’incident jusqu’à ce qu’un événement d’échelle consomme la capacité restante.

Le postmortem n’a pas dit « ne supprimez rien ». La correction a été structurelle : supprimer les surprises dues aux symlinks, faire du nettoyage temp une opération au niveau service,
et traiter « où pointe réellement ce chemin ? » comme une vérification de première classe dans les runbooks. Aussi : arrêter de considérer la « disposition standard » comme une religion.
La disposition standard est une rumeur à moins d’être continuellement validée.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une équipe plateforme voulait des déploiements plus rapides. Ils ont construit une étape de nettoyage dans leur pipeline pour supprimer les anciens répertoires de release :
/opt/app/releases/*, garder les trois derniers, supprimer le reste. Sensé. Puis quelqu’un a remarqué que le nettoyage prenait parfois des minutes sur des hôtes occupés.
Ils l’ont « optimisé » avec une suppression parallèle : trouver les anciennes releases et les supprimer concurrentiellement.

L’optimisation a marché en staging. En production, elle a créé un nouveau mode d’échec : les releases contenaient des bind mounts utilisés pour le profiling de performance et des caches éphémères.
Les suppressions parallèles ont déclenché une tempête d’opérations filesystem, saturant l’IO. La latence a grimpé, pas seulement pour l’app, mais pour tout le nœud.
Les vérifications de santé ont échoué. Les services ont redémarré. Les redémarrages s’exécutaient depuis des répertoires partiellement supprimés.

Puis le vrai piège : dans un déploiement, la variable qui pointait vers le répertoire de releases était vide parce qu’une étape précédente avait échoué.
Le script a quand même tourné. Le garde-fou était « si le répertoire existe », ce qui a réussi car le script est retombé sur /opt/app.
Sous suppression parallèle, il a supprimé bien plus que prévu, y compris des bibliothèques partagées fournies avec l’app.

L’équipe s’est remise rapidement en redéployant, mais l’incident a été coûteux en temps et en crédibilité. La leçon était ennuyeuse et peu glorieuse :
n’optimisez pas les opérations destructrices sans mesurer les effets à l’échelle du système, et ne laissez jamais un chemin de suppression être calculé sans validation stricte.
Si vous voulez de la vitesse, utilisez des snapshots et des switches atomiques, pas une suppression plus rapide.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Un service lié aux finances stockait des données critiques sur des datasets ZFS avec des snapshots horaires conservés 72 heures, et des snapshots journaliers pendant 30 jours.
Ce n’était pas sophistiqué. C’était une politique : « Chaque dataset a des snapshots. Aucune exception. La rétention est appliquée. Les exercices de restauration ont lieu trimestriellement. »
Les gens se plaignaient parce que cela consommait de l’espace et demandait de la planification.

Pendant une fenêtre de maintenance, un ingénieur a exécuté une commande de nettoyage destinée à un montage de staging. Le chemin semblait correct, et l’auto-complétion a « aidé ».
C’était le montage de production. Ils s’en sont rendu compte en quelques minutes parce que la surveillance était réglée sur le churn de fichiers et les pics d’écriture des datasets ZFS, pas seulement sur le CPU.

Ils ont fait deux choses intelligentes immédiatement : d’abord, ils ont arrêté le service pour éviter d’écrire de nouvelles données dans une arborescence à moitié supprimée. Ensuite,
ils ont créé un nouveau snapshot du dataset endommagé (oui, snapshotter le désordre) pour préserver l’état forensic. Puis ils ont cloné le dernier snapshot propre
et restauré uniquement les sous-répertoires manquants.

Le service était de retour en temps raisonnable, et ils n’ont pas eu besoin de rollback du dataset entier, évitant la perte des minutes après le snapshot.
Le postmortem était aussi ennuyeux : pas d’héroïsme, juste un rappel que les snapshots ne sont pas du « théâtre de sauvegarde » si vous pouvez effectivement restaurer rapidement.
Les exercices de restauration ont fait que personne n’a dû deviner les commandes sous pression.

Erreurs courantes : symptôme → cause racine → correctif

1) « Le disque est toujours plein après avoir supprimé des logs »

Symptôme : df -h n’affiche pas d’espace libre même après suppression de gros fichiers.

Cause racine : Les fichiers ont été supprimés mais restent ouverts par des processus en cours (inodes désinscrits).

Correctif : Utilisez lsof +L1 pour trouver les coupables ; redémarrez le processus ou signalez-lui de rouvrir les logs. Envisagez copytruncate seulement si nécessaire ; préférez la réouverture correcte.

2) « Les commandes disent ‘No such file or directory’ mais le binaire existe »

Symptôme : Lancer /bin/ls renvoie une erreur même si ls est présent.

Cause racine : Le loader dynamique ou des bibliothèques partagées ont été supprimés (ex. /lib64/ld-linux-x86-64.so.2 ou dépendances).

Correctif : Arrêtez d’essayer des redémarrages au hasard. Restaurez/réinstallez les bibliothèques cœur via le gestionnaire de paquets ou reconstruisez depuis l’image. Si le gestionnaire est cassé, utilisez un média de secours ou attachez le disque à un autre hôte.

3) « Le système boote mais les services ne démarrent pas »

Symptôme : Après reboot, beaucoup d’unités échouent ; journald râle ; le réseau peut être cassé.

Cause racine : Suppression partielle sous /etc, /usr, /var, ou fichiers d’unités systemd et dépendances manquants.

Correctif : Traitez cela comme une défaillance d’intégrité. Si vous avez des snapshots, restaurez configs et unités ; sinon reconstruisez et rattachez les données. Vérifiez avec des contrôles d’intégrité de paquets (rpm -Va sur systèmes RPM) si disponible.

4) « Les pods Kubernetes redémarrent après un nettoyage »

Symptôme : Pods en crashloop ; les nœuds semblent corrects ; erreurs applicatives indiquant des fichiers manquants sous des chemins montés.

Cause racine : Le nettoyage visait un chemin PersistentVolume monté, pas la couche conteneur.

Correctif : Arrêtez le job/pod qui supprime. Restaurez le PVC depuis snapshot/backup du stockage. Ajoutez des contrôles d’admission et runAsNonRoot ; retirez les hostPath sauf si absolument nécessaire.

5) « L’automatisation a supprimé le mauvais répertoire sur plusieurs hôtes »

Symptôme : Beaucoup d’hôtes se dégradent simultanément ; les mêmes chemins manquent.

Cause racine : Gestion de configuration ou job CI a exécuté une tâche destructive avec une mauvaise expansion de variable ou un mauvais ciblage d’inventaire.

Correctif : Geler le pipeline. Revenir la modification. Ajouter des conditions de garde : exiger une allowlist explicite de chemins, refuser les variables vides, et exécuter les tâches destructrices seulement avec approbation manuelle + dry run.

6) « Le script de nettoyage fonctionnait depuis des mois puis a tout supprimé »

Symptôme : Un script ancien devient soudainement destructeur.

Cause racine : L’environnement a changé : cibles de symlink, points de montage, nouveaux bind mounts, changements d’image de base du conteneur, ou le chemin pointe maintenant vers un autre filesystem.

Correctif : Faites valider les invariants par les scripts : assurez-vous que le chemin est sur le filesystem attendu (findmnt), qu’il correspond à un pattern exact, qu’il n’est pas / ou vide, et qu’il n’est pas un symlink sauf autorisation explicite.

7) « Nous avons restauré depuis la sauvegarde mais l’app est incohérente »

Symptôme : L’app démarre mais les données sont corrompues ou des écritures récentes manquent.

Cause racine : Restauration d’une sauvegarde au niveau filesystem sans snapshot consistant applicativement ; WAL/transactions non alignés.

Correctif : Utilisez des sauvegardes consistantes applicativement (outils natifs de la base) ou quiescez avant snapshot. Après restauration, lancez des vérifications d’intégrité et réconciliez avec logs/réplicas.

Listes de vérification / plan pas à pas

Checklist préventive : faire en sorte que « rm -rf / » soit une histoire que racontent les autres

  1. Snapshots sur tout ce qui compte. Si vous ne pouvez pas le snapshotter, il vous faut une sauvegarde avec restaurations testées. Préférez les deux.
  2. Moindre privilège par défaut. Supprimez les sudo larges ; utilisez l’élévation juste-à-temps avec piste d’audit.
  3. Rendre les chemins dangereux difficiles à toucher. Montages séparés pour les données ; considérez une racine en lecture seule pour les appliances ; utilisez des attributs immuables quand approprié.
  4. Garde-fous dans les scripts : exiger des variables non vides (${VAR:?}), interdire /, refuser les globbing surprises, résoudre les symlinks délibérément.
  5. Culture du dry-run : utilisez find pour afficher les candidats avant suppression ; stockez la sortie dans les notes d’incident.
  6. Observabilité du churn de fichiers : alerter sur des taux de suppression inhabituels sur des datasets critiques, pas seulement CPU/mémoire.
  7. Exercices de restauration. La première fois que vous restaurez ne devrait pas avoir lieu pendant un incident.

Checklist opérationnelle : suppression sûre sous pression

  1. Prouvez le chemin. Utilisez readlink -f et findmnt pour confirmer frontières de montage et symlinks.
  2. Lister, ne pas supprimer. Commencez par : « qu’est-ce qui sera exactement supprimé ? »
  3. Préférez déplacer en quarantaine. Renommez un répertoire en chemin de quarantaine d’abord si possible, puis supprimez plus tard.
  4. Throttlez et observez. Si la suppression est massive, elle peut devenir une panne IO. Envisagez des suppressions par lots hors-pointe.
  5. Arrêtez les services avant de supprimer des données stateful. Surtout bases et queues.
  6. Ayez une voie de rollback. Snapshottez avant suppression si le filesystem le supporte ; sinon sauvegardez le répertoire cible.

Checklist incident : suspicion de suppression accidentelle

  1. Geler l’automatisation (CI/CD, Ansible, cron cleanup jobs).
  2. Capturer les preuves : montages actuels, processus en cours, stats disque/inodes, dernières commandes si disponibles.
  3. Évaluer l’étendue : OS seulement vs mount de données ; conteneur vs hôte ; nœud unique vs flotte.
  4. Choisir la stratégie de récupération : reconstruire + rattacher, restauration snapshot, réinstallation de paquets, ou outils de récupération de fichiers.
  5. Valider : santé des services, contrôles d’intégrité des données, et vérification des dépendances.
  6. Postmortem : corriger le garde-fou, pas la personne.

FAQ

1) Est-ce que rm -rf / fonctionne encore sur les Linux modernes ?

Souvent non, parce que GNU rm utilise typiquement --preserve-root par défaut. Mais ne vous relâchez pas : des gens peuvent passer
--no-preserve-root, utiliser d’autres outils (find -delete, rsync --delete), ou supprimer des montages critiques sous / sans viser la racine elle-même.

2) Pourquoi certains systèmes continuent-ils à tourner après des suppressions majeures ?

Parce que les processus en cours ont déjà chargé du code et ont des descripteurs de fichiers ouverts. Ils peuvent tenir la charge jusqu’à ce qu’ils aient besoin d’exécuter un nouveau binaire,
charger une bibliothèque partagée, faire une rotation de logs, ou redémarrer.

3) Est-ce sûr de supprimer à l’intérieur d’un conteneur ?

C’est plus sûr seulement si vous supprimez la couche du conteneur et pas des volumes montés. La partie dangereuse est généralement le mount de volume qui contient de vraies données.
Si votre conteneur peut voir des chemins hôte ou des montages privilégiés, « conteneur » n’est plus une frontière significative.

4) Quelle est l’alternative la plus sûre à rm -rf pour le nettoyage ?

Quand c’est possible : renommer/déplacer vers un répertoire de quarantaine d’abord, puis supprimer plus tard. Si vous devez supprimer : utilisez find avec des contraintes explicites
(frontière filesystem, profondeur, âge, propriétaire) et journalisez ce que vous supprimez. Et snapshottez avant sur les filesystems qui le supportent.

5) Puis-je récupérer des fichiers supprimés sur ext4/xfs ?

Parfois, mais ne comptez pas dessus. La récupération dépend de si les blocs ont été réécrits, si TRIM a été exécuté sur des SSD, et de la rapidité à arrêter les écritures.
Les snapshots et sauvegardes sont la voie fiable ; la récupération forensic est le dernier recours.

6) Pourquoi rm -rf est-il parfois si lent ?

Supprimer de nombreux petits fichiers est coûteux en métadonnées : parcours de répertoire, mises à jour d’inode, écritures de journal. Sur du stockage réseau c’est pire.
De plus, la suppression peut saturer l’IO et bloquer d’autres workloads. Le « nettoyage » peut devenir la panne.

7) Devrait-on aliaser rm en rm -i globalement ?

Correct pour les shells interactifs, essentiellement inutile pour l’automatisation. Ça habitue aussi les gens à taper aveuglément « y » mille fois.
Mieux : appliquer le moindre privilège, ajouter des allowlists de chemins, et compter sur les snapshots/sauvegardes pour une vraie sécurité.

8) Quelle est la meilleure défense contre des commandes destructrices à l’échelle d’une flotte ?

Défense en profondeur : approbations pour l’automatisation destructive, découpage d’environnement, infrastructure immuable avec workflows de reconstruction,
et snapshots au niveau stockage. Aussi : un staging vraiment représentatif, pour que les scripts échouent bruyamment avant la production.

9) Que faire si nous n’avons pas de snapshots aujourd’hui ?

Alors votre première étape n’est pas un nouvel outil ; c’est une politique. Décidez quelles données doivent être récupérables, définissez RPO/RTO,
implémentez des sauvegardes, et exécutez des exercices de restauration. Les snapshots sont puissants, mais seulement si rétention et procédures de restauration existent.

10) Comment arrêter une suppression hors de contrôle en toute sécurité ?

Si la cible est incorrecte, arrêtez-la vite : tuez le processus, démontez le filesystem affecté si possible, ou isolez l’hôte.
Puis snapshottez le dataset endommagé (si supporté) avant d’essayer des réparations pour ne pas perdre l’état forensic.

Conclusion : prochaines étapes réalisables cette semaine

« rm -rf / » est célèbre parce que c’est simple, irréversible, et toujours prêt pour votre pire jour. Mais les histoires ne parlent pas vraiment d’une commande.
Elles parlent d’absence de freins : pas de snapshots, privilèges laxistes, scripts acceptant des variables vides, et des runbooks qui supposent que la disposition du filesystem est statique.

Prochaines étapes pratiques :

  • Inventoriez les datasets critiques et placez-les sur du stockage compatible snapshots (ou sauvegardez-les avec restaurations vérifiées).
  • Auditez les scripts de nettoyage pour les risques de variables vides et surprises de symlink/montage ; ajoutez des allowlists et des arrêts forcés.
  • Faites un exercice de restauration ce mois-ci. Chronométrez-le. Rédigez le runbook à partir de ce qui s’est réellement passé.
  • Réduisez les privilèges permanents et exigez une approbation explicite pour l’automatisation destructive à l’échelle.
  • Actualisez votre runbook on-call « disque plein » pour commencer par le diagnostic, pas par la suppression.

Si vous faites cela, vous n’éviterez pas seulement un incident digne d’un genre. Vous rendrez aussi le quotidien plus calme — moins de panique, moins de surprises,
et moins de mythes « ça a marché la dernière fois » traités comme de l’ingénierie.

← Précédent
ZFS : utiliser NVMe comme L2ARC — quand l’ARC ne suffit pas
Suivant →
P-cores vs E-cores : CPU hybrides expliqués sans marketing

Laisser un commentaire