Docker « le volume est utilisé » : supprimer ou remplacer sans perte de données

Cet article vous a aidé ?

Ce moment : vous lancez docker volume rm, vous attendez un nettoyage propre, et Docker vous répond par une petite erreur satisfaite : le volume est utilisé. La production attend. Votre pager commence à chauffer. Et le nom du volume que vous voulez supprimer est celui que l’équipe applicative a juré « n’est plus utilisé maintenant ».

Le truc, c’est que Docker dit généralement la vérité—mais pas toute la vérité. Les volumes peuvent être retenus par des conteneurs arrêtés, des projets Compose orphelins, des tâches Swarm, des pilotes de plugin, ou une définition périmée que vous aviez oubliée. Ce guide explique comment supprimer ou remplacer un volume Docker sans perdre de données, et sans faire le classique « rm -rf et prier ».

Ce que Docker entend par « le volume est utilisé »

Le message « le volume est utilisé » de Docker n’est pas poétique. C’est un refus précis : Docker ne supprimera pas un volume si un quelconque conteneur—en cours d’exécution ou arrêté—le référence encore dans sa configuration de conteneur. Docker suit cela au niveau des métadonnées (configuration du conteneur + références de montage), pas en vérifiant si un processus a actuellement des fichiers ouverts.

Cette distinction compte. Un volume peut être « utilisé » même lorsque :

  • Le conteneur est exited mais existe toujours.
  • Le conteneur a été créé par Compose il y a des mois, et personne ne l’a nettoyé.
  • Une tâche de service Swarm est encore enregistrée, même si elle redémarre sur un autre nœud.
  • Un conteneur a été remplacé, mais l’ancien est toujours présent comme un fantôme avec un nom parlant comme myapp_web_1.

Autre précision : Docker distingue clairement les volumes (gérés par Docker, généralement sous /var/lib/docker/volumes) et les bind mounts (votre chemin hôte). Les bind mounts n’ont pas le même comportement de « le volume est utilisé » ; à la place, vous détruirez vos propres données comme un adulte.

Encore une subtilité : l’erreur est généralement déclenchée par le refus de docker volume rm d’aller plus loin. Si vous essayez de forcer avec des commandes de nettoyage système, vous pouvez supprimer plus que prévu. L’objectif ici est une suppression ou un remplacement ciblé, avec un plan de migration des données que vous pouvez expliquer à un auditeur sans transpirer.

Mode opératoire de diagnostic rapide

Si vous n’avez que cinq minutes avant que quelqu’un ne demande « peut‑on juste redémarrer l’hôte ? », faites ceci. Dans l’ordre. Ne improvisez pas.

Première étape : identifier le volume et son pilote

  1. Inspectez le volume (nom, pilote, labels, point de montage).
  2. Si le pilote n’est pas local, arrêtez‑vous et relisez : les pilotes externes ont une sémantique différente et peuvent impliquer du stockage distant.

Deuxième étape : trouver chaque conteneur qui le référence (en cours d’exécution ou arrêté)

  1. Listez les conteneurs attachés au volume via un filtre.
  2. Inspectez les conteneurs suspects et confirmez que la liste des montages inclut votre volume.

Troisième étape : décider entre trois actions

  • Dégager la suppression : supprimez le(s) conteneur(s) référents, puis supprimez le volume.
  • Remplacer sans perte de données : copiez les données dans un nouveau volume, puis repointez les conteneurs/Compose vers celui‑ci.
  • Conserver mais détacher : arrêtez les conteneurs, mettez à jour la configuration pour qu’ils n’utilisent plus le volume, et gardez‑le comme sauvegarde.

Quatrième étape : vérifier la sécurité des données

  1. Faites une sauvegarde de type snapshot (export tar) du contenu du volume.
  2. Faites un contrôle d’intégrité rapide : les fichiers attendus sont présents, les tailles semblent cohérentes, et l’application peut les lire après remontage.

Il n’y a rien de glamour ici. C’est le but. Les corrections glamour sont celles que vous regrettez ensuite.

Quelques faits et contexte historique (parce que ça change la manière de déboguer)

  • Les volumes Docker existaient tôt, mais ont mûri ensuite. Les premiers utilisateurs de Docker s’appuyaient fortement sur les bind mounts ; les volumes nommés sont devenus le « lieu sûr » par défaut à mesure que les pratiques d’exploitation ont évolué.
  • La vérification « volume utilisé » de Docker est pilotée par des métadonnées. Docker ne supprimera pas un volume référencé par une définition de conteneur, même si le conteneur est arrêté et que rien n’a les fichiers ouverts.
  • Les labels Compose ont changé la façon dont les volumes sont « orphelinés ». Docker Compose attache des labels comme project et service ; vous pouvez utiliser ces labels pour retracer l’origine d’un volume, mais aussi pour découvrir des stacks abandonnés.
  • Les systèmes de fichiers en overlay ne sont pas votre volume. La couche inscriptible d’un conteneur (overlay2) est différente d’un volume. Supprimer un conteneur supprime la couche inscriptible, mais pas les volumes nommés.
  • Swarm a introduit l’ordonnancement distribué, pas le stockage distribué. Les gens confondent cela. Swarm peut replanifier des tâches ; votre volume local ne peut pas se téléporter sur un autre nœud.
  • Les pilotes de volume comptent. local se comporte comme des répertoires locaux. Les pilotes plugin (NFS, volumes cloud, intégrations de type CSI) peuvent avoir leurs propres règles d’attachement/détachement et modes de défaillance.
  • Les « volumes anonymes » sont un piège connu. Ils sont créés automatiquement (surtout dans d’anciens modèles Compose) et peuvent s’accumuler. Ils sont plus difficiles à suivre car le nom ressemble à un hash.
  • Les commandes de prune sont devenues populaires après des incidents disque. La pression disque a poussé les équipes vers docker system prune. Ça aide—jusqu’à ce que ça enlève quelque chose que vous pensiez « temporaire ».

Règles d’or : comment ne pas perdre de données

  1. Supposez que le volume contient des données importantes tant que l’on ne vous a pas prouvé le contraire. « Ce n’est que du cache » a détruit plus de bases de données que les malwares.
  2. Ne supprimez jamais un volume tant que vous ne pouvez nommer ce qui l’utilise. Si vous ne pouvez pas, vous ne le supprimez pas ; vous jouez.
  3. Sauvegardez avant de migrer. « Mais on le copie » n’est pas une sauvegarde. Les opérations de copie échouent de façon créative : permissions, fichiers spéciaux, liens symboliques cassés, transferts partiels, et troncation silencieuse si le système de fichiers est plein.
  4. Préférez créer un nouveau volume et migrer les données vers lui. Remplacer sur place est tentant mais vous laisse sans possibilité de rollback.
  5. Soyez précis avec les commandes de nettoyage. Si vous lancez docker system prune --volumes en production, au moins écrivez d’abord votre plan de post-mortem. Cela vous fera gagner du temps plus tard.

Blague #1 : Si vous vous sentez inutile, souvenez‑vous qu’il y a un bouton « suppression forcée » en production. Il existe surtout pour tester votre stratégie de sauvegarde.

Une citation, parce que l’exploitation est une discipline, pas un état d’esprit. Tom Limoncelli a une idée souvent paraphrasée dans les cercles SRE : si ce n’est pas documenté et pratiqué, ce n’est pas une procédure ; c’est un souhait. — Tom Limoncelli (idée paraphrasée).

Tâches pratiques : commandes, sorties et décisions

Voici les actions pratiques. Chaque tâche vous donne une commande, un type de sortie réaliste, et la décision à prendre. Exécutez-les dans l’ordre quand vous êtes sous pression ; sélectionnez‑en quand vous faites une maintenance planifiée.

Tâche 1 : Confirmer l’erreur et le nom exact du volume

cr0x@server:~$ docker volume rm pgdata
Error response from daemon: remove pgdata: volume is in use - [2d8c1f8b6a1d5e2f6f4e62b2d64a0d1b8a5b0a7c7d0f1a2b3c4d5e6f7a8b9c0d]

Ce que cela signifie : Docker a trouvé au moins un conteneur qui référence le volume. Le long hexadécimal est un ID de conteneur.

Décision : N’essayez pas à nouveau. Trouvez le(s) conteneur(s) référents et décidez de les supprimer ou de migrer.

Tâche 2 : Inspecter le volume (pilote, labels, point de montage)

cr0x@server:~$ docker volume inspect pgdata
[
  {
    "CreatedAt": "2025-11-20T09:12:13Z",
    "Driver": "local",
    "Labels": {
      "com.docker.compose.project": "billing",
      "com.docker.compose.volume": "pgdata"
    },
    "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
    "Name": "pgdata",
    "Options": null,
    "Scope": "local"
  }
]

Ce que cela signifie : C’est un volume nommé local créé par le projet Compose billing. C’est votre première piste.

Décision : Si Driver n’est pas local, faites une pause et identifiez le backend de stockage et la sémantique de détachement. S’il est local, poursuivez la découverte des conteneurs et les options de migration.

Tâche 3 : Trouver les conteneurs qui référencent le volume (filtre rapide)

cr0x@server:~$ docker ps -a --filter volume=pgdata --format 'table {{.ID}}\t{{.Names}}\t{{.Status}}'
CONTAINER ID   NAMES                 STATUS
2d8c1f8b6a1d   billing-postgres-1    Up 3 days
c91a44dd210e   billing-postgres-old  Exited (0) 2 weeks ago

Ce que cela signifie : Deux conteneurs le référencent. L’un est en cours d’exécution, l’autre est arrêté mais bloque toujours la suppression.

Décision : Si vous voulez supprimer le volume, vous devez supprimer les deux conteneurs (ou au moins retirer leur référence en supprimant les conteneurs). Si vous voulez remplacer le volume, vous migrerez puis recréerez les conteneurs avec le nouveau volume.

Tâche 4 : Confirmer l’usage du montage dans la configuration du conteneur

cr0x@server:~$ docker inspect 2d8c1f8b6a1d --format '{{json .Mounts}}'
[{"Type":"volume","Name":"pgdata","Source":"/var/lib/docker/volumes/pgdata/_data","Destination":"/var/lib/postgresql/data","Driver":"local","Mode":"z","RW":true,"Propagation":""}]

Ce que cela signifie : Le conteneur utilise bien pgdata et le monte sur le répertoire de données PostgreSQL.

Décision : Traitez‑le comme un stockage de base de données. Planifiez un arrêt contrôlé, une sauvegarde cohérente et une migration. Pas de copies improvisées pendant que la base écrit.

Tâche 5 : Identifier le projet Compose via les labels (qui en est propriétaire)

cr0x@server:~$ docker inspect 2d8c1f8b6a1d --format '{{json .Config.Labels}}'
{"com.docker.compose.project":"billing","com.docker.compose.service":"postgres","com.docker.compose.version":"2.24.6"}

Ce que cela signifie : C’est géré par Compose, pas un docker run manuel au hasard.

Décision : Privilégiez les modifications via Compose (ou au moins gardez l’état Compose cohérent), sinon le prochain docker compose up pourrait recréer d’anciens éléments et vous surprendre.

Tâche 6 : Voir ce qu’il y a dans le volume (vérification rapide)

cr0x@server:~$ sudo ls -lah /var/lib/docker/volumes/pgdata/_data | head
total 132K
drwx------  19 999 999 4.0K Jan  3 10:11 .
drwx-----x   3 root root 4.0K Nov 20 09:12 ..
-rw-------   1 999 999    3 Jan  3 10:11 PG_VERSION
drwx------   6 999 999 4.0K Jan  3 10:11 base
drwx------   2 999 999 4.0K Jan  3 10:11 global
drwx------   2 999 999 4.0K Jan  3 10:11 pg_wal

Ce que cela signifie : C’est un vrai répertoire de données Postgres. Les permissions correspondent à l’usage typique d’un UID dans le conteneur. Supprimer cela serait un événement « mettez votre CV à jour ».

Décision : Si vous devez remplacer le volume, faites‑le par un dump/restore contrôlé ou une copie au niveau système de fichiers pendant l’arrêt, selon les RPO/RTO et le type de base.

Tâche 7 : Arrêter proprement le(s) conteneur(s) adéquat(s)

cr0x@server:~$ docker stop billing-postgres-1
billing-postgres-1

Ce que cela signifie : Postgres s’arrête. Si votre conteneur gère correctement le signal d’arrêt, il doit effectuer un checkpoint et sortir proprement.

Décision : Si l’arrêt bloque, n’allez pas directement à docker kill. Vérifiez d’abord les logs et la santé. Les arrêts forcés augmentent le risque de copier des données incohérentes.

Tâche 8 : Vérifier qu’aucun conteneur ne référence encore le volume (y compris les arrêtés)

cr0x@server:~$ docker ps -a --filter volume=pgdata --format 'table {{.ID}}\t{{.Names}}\t{{.Status}}'
CONTAINER ID   NAMES                 STATUS
2d8c1f8b6a1d   billing-postgres-1    Exited (0) 3 seconds ago
c91a44dd210e   billing-postgres-old  Exited (0) 2 weeks ago

Ce que cela signifie : Les deux conteneurs existent toujours et référencent le volume.

Décision : Si vous essayez de supprimer le volume, vous devez supprimer ces conteneurs. Si vous migrez, conservez‑les jusqu’à ce que la sauvegarde soit terminée, puis supprimez‑les ou recréez‑les avec le nouveau volume.

Tâche 9 : Créer une archive tar de sauvegarde du volume (assurance bon marché)

cr0x@server:~$ docker run --rm -v pgdata:/data -v $PWD:/backup alpine sh -c 'cd /data && tar -cpf /backup/pgdata-backup.tar .'

Ce que cela signifie : Vous avez utilisé un conteneur temporaire pour lire le volume et écrire un tar dans votre répertoire courant sur l’hôte.

Décision : Validez que le tar existe et a une taille plausible. Si vous avez peu d’espace, écrivez‑le sur un système de fichiers de sauvegarde monté, pas sur votre disque root.

Tâche 10 : Vérifier la taille et le contenu basique de la sauvegarde

cr0x@server:~$ ls -lh pgdata-backup.tar
-rw-r--r-- 1 cr0x cr0x 1.3G Jan  3 10:19 pgdata-backup.tar

cr0x@server:~$ tar -tf pgdata-backup.tar | head
./
./PG_VERSION
./base/
./global/
./pg_wal/

Ce que cela signifie : Le tar existe et contient la structure attendue.

Décision : Vous avez maintenant un artefact de rollback. Ce n’est toujours pas une sauvegarde parfaite de base de données, mais suffisant pour récupérer des fichiers si vous faites une erreur lors du remplacement du volume.

Tâche 11 : Créer le nouveau volume de remplacement

cr0x@server:~$ docker volume create pgdata_v2
pgdata_v2

Ce que cela signifie : Nouveau volume nommé vide créé.

Décision : Utilisez un nom clairement versionné. Évitez de l’appeler « new » à moins que vous n’aimiez l’archéologie plus tard.

Tâche 12 : Copier les données de l’ancien volume vers le nouveau (copie hors ligne)

cr0x@server:~$ docker run --rm -v pgdata:/from -v pgdata_v2:/to alpine sh -c 'cd /from && cp -a . /to'

Ce que cela signifie : Copie au niveau fichier avec cp -a pour préserver permissions et horodatages.

Décision : Ne faites cela que pour des données sûres à copier hors ligne (conteneur arrêté). Pour les bases de données, la méthode privilégiée est dump/restore si vous avez besoin de garanties de cohérence ; la copie de fichiers fonctionne si la BD est complètement arrêtée et ne récupère pas d’un crash pendant la copie.

Tâche 13 : Comparer rapidement la forme des répertoires (détecter les échecs de copie évidents)

cr0x@server:~$ docker run --rm -v pgdata:/from -v pgdata_v2:/to alpine sh -c 'cd /from && find . -maxdepth 2 -type d | sort | tail -n 5 && echo "---" && cd /to && find . -maxdepth 2 -type d | sort | tail -n 5'
./pg_commit_ts
./pg_dynshmem
./pg_logical
./pg_notify
./pg_stat_tmp
---
./pg_commit_ts
./pg_dynshmem
./pg_logical
./pg_notify
./pg_stat_tmp

Ce que cela signifie : La structure des répertoires correspond à première vue.

Décision : Poursuivez, mais ne confondez pas « a l’air similaire » avec « identique bit à bit ». Pour les systèmes critiques, effectuez des vérifications au niveau applicatif après le redémarrage.

Tâche 14 : Supprimer les anciens conteneurs qui maintiennent l’ancien volume « en usage »

cr0x@server:~$ docker rm billing-postgres-old
billing-postgres-old
cr0x@server:~$ docker rm billing-postgres-1
billing-postgres-1

Ce que cela signifie : Les conteneurs sont supprimés ; leurs références au volume ont disparu.

Décision : Vous pouvez maintenant supprimer pgdata si vous le souhaitez vraiment, ou le garder jusqu’à ce que la nouvelle configuration soit validée.

Tâche 15 : Recréer le conteneur (ou le stack Compose) pointant vers le nouveau volume

cr0x@server:~$ docker run -d --name billing-postgres-1 \
  -e POSTGRES_PASSWORD=redacted \
  -v pgdata_v2:/var/lib/postgresql/data \
  postgres:16
8b2fa1d22b2c4b8f8f0e6e7f3a2d1c0b9a8f7e6d5c4b3a2f1e0d9c8b7a6f5e4d

Ce que cela signifie : Nouveau conteneur démarré avec le volume de remplacement.

Décision : Validez la santé de l’application. Si c’est géré par Compose, traduisez le changement dans compose.yaml et exécutez via Compose plutôt que d’utiliser un docker run ad hoc sur le long terme.

Tâche 16 : Confirmer que le nouveau conteneur utilise le nouveau volume

cr0x@server:~$ docker inspect billing-postgres-1 --format '{{range .Mounts}}{{.Name}} -> {{.Destination}}{{"\n"}}{{end}}'
pgdata_v2 -> /var/lib/postgresql/data

Ce que cela signifie : Le montage du nouveau conteneur est correct.

Décision : Ce n’est qu’à présent que vous pouvez envisager de supprimer l’ancien volume.

Tâche 17 : Supprimer l’ancien volume (optionnel, après validation)

cr0x@server:~$ docker volume rm pgdata
pgdata

Ce que cela signifie : Docker a autorisé la suppression parce qu’aucun conteneur ne référence le volume.

Décision : Si vous voulez un filet de sécurité supplémentaire, ne supprimez pas encore—renommez ou conservez‑le pendant quelques jours, selon votre politique de changements et votre budget disque.

Tâche 18 : Rechercher les volumes anonymes/orphelins et comprendre ce que vous êtes sur le point de nettoyer

cr0x@server:~$ docker volume ls --format 'table {{.Name}}\t{{.Driver}}'
NAME                                    DRIVER
billing_cache                            local
pgdata_v2                                local
b3f3b9d9d79e0a9dfb2a2d8c6b77d8b8c0a...   local

Ce que cela signifie : Ce long nom en forme de hash est souvent un volume anonyme. Parfois inoffensif. Parfois c’est la seule copie du répertoire d’upload de quelqu’un parce que c’était « temporaire ».

Décision : Inspectez avant de faire un prune. Vous n’êtes pas payé pour être courageux ; vous êtes payé pour avoir raison.

Remplacer un volume en toute sécurité (trois schémas)

Schéma A : copie « lift-and-shift » au niveau fichier (bon pour les données statiques, prudence avec les bases)

C’est ce que nous avons fait plus haut avec cp -a via un conteneur Alpine temporaire. C’est rapide, simple, et correct lorsque l’application est totalement arrêtée et que le format des données est cohérent hors ligne.

Fonctionne bien pour :

  • Répertoires de contenu web
  • Bundles de configuration statiques
  • Caches d’artefacts que l’on peut reconstruire (mais ne supprimez pas à l’aveugle)
  • Bases de données uniquement quand elles sont complètement arrêtées et que vous acceptez la sémantique de récupération après crash

À éviter pour :

  • Bases de données actives (copier pendant l’exécution) à moins d’aimer les segments WAL corrompus
  • Applications qui maintiennent plusieurs fichiers avec des exigences de cohérence croisée pendant l’exécution

Schéma B : migration au niveau applicatif (dump/restore) pour une forte cohérence

Si vous avez besoin de conformité plutôt que de vitesse, faites l’export/import au niveau applicatif. Pour PostgreSQL c’est typiquement pg_dump / pg_restore ou des outils de sauvegarde physique. Pour MySQL, mysqldump ou des outils de sauvegarde physique. Pour Elasticsearch, snapshot/restore. L’idée : migrez les données d’une manière supportée, pas en copiant les fichiers internes du moteur en plein vol.

Opérationnellement, ce schéma est plus lent mais prévisible. C’est aussi la seule migration qui vous donne une histoire défendable lors d’un post‑mortem : « nous avons utilisé la méthode de sauvegarde supportée ».

Schéma C : garder le volume, remplacer les conteneurs (quand le volume n’est pas le problème)

Parfois vous n’avez pas besoin de remplacer le volume du tout. Il suffit de supprimer les conteneurs qui le référencent pour supprimer un autre volume, ou de reconstruire un conteneur applicatif en gardant les données intactes.

Dans ce cas :

  • Arrêtez le conteneur.
  • Supprimez le conteneur (pas le volume).
  • Recréez le conteneur en pointant vers le même volume nommé.

C’est le mouvement le plus sûr quand les données sont précieuses et que votre seul souci est une modification de configuration du conteneur.

Compose et Swarm : façons particulières d’être trompé

Compose : les volumes persistent même quand vous pensez avoir « descendu » la stack

docker compose down supprime par défaut les conteneurs et les réseaux, mais il ne supprime pas les volumes nommés à moins d’ajouter --volumes. C’est généralement bon. Cela signifie aussi que le volume reste et peut accumuler de la dérive : migrations anciennes, fichiers oubliés.

Compose vous aide aussi à identifier les propriétaires via les labels. Utilisez‑les. Ils existent pour une raison.

Swarm : tâches et ordonnancement amplifient la confusion

Dans Swarm, une tâche de service peut être « arrêtée » mais exister encore dans l’historique. Pendant ce temps, votre volume nommé existe sur un seul nœud. Si vous pensez « Swarm va le déplacer », vous confondez orchestration et stockage.

Swarm + volumes locaux fonctionne si vous épinglez les services aux nœuds et comprenez le basculement. Si vous voulez la mobilité du stockage, il vous faut un pilote/stockage qui le supporte (et tester en cas de panne, pas sur une diapositive).

Blague #2 : Swarm replanifiera volontiers votre conteneur sur un nœud qui n’a pas les données. Ce n’est pas malveillant—juste optimiste.

Erreurs courantes (symptôme → cause → correctif)

1) « docker volume rm dit utilisé, mais docker ps ne montre rien en cours »

Symptôme : Aucun conteneur en cours, le volume est toujours « utilisé ».

Cause : Des conteneurs arrêtés existent encore et référencent le volume.

Correctif : Listez tous les conteneurs, y compris les arrêtés, filtrés par volume. Supprimez les conteneurs (ou recréez‑les avec un autre volume).

cr0x@server:~$ docker ps -a --filter volume=pgdata
CONTAINER ID   IMAGE        COMMAND                  CREATED       STATUS                     PORTS     NAMES
c91a44dd210e   postgres:16  "docker-entrypoint.s…"   2 weeks ago   Exited (0) 2 weeks ago               billing-postgres-old

2) « J’ai supprimé le conteneur et Docker refuse encore de supprimer le volume »

Symptôme : Vous avez supprimé un conteneur, blocage toujours présent.

Cause : Plus d’un conteneur référence le volume (souvent des déploiements anciens/renommés/échoués).

Correctif : Utilisez le filtre volume et supprimez tous les conteneurs référents.

3) « Nous avons remplacé le volume et l’app a démarré… avec un jeu de données vide »

Symptôme : L’app démarre à neuf, état manquant.

Cause : Le nouveau volume a été monté, mais les données n’ont jamais été migrées (ou migrées vers le mauvais chemin/volume).

Correctif : Confirmez les noms de montages et destinations avec docker inspect. Copiez les données hors ligne ou restaurez depuis le tar de sauvegarde. Puis redéployez.

4) « La copie a réussi, mais les permissions sont cassées »

Symptôme : L’app échoue avec des erreurs permission denied après migration.

Cause : La méthode de copie n’a pas préservé la propriété/les bits (ex. cp sans -a, ou extraction tar en root avec de mauvais flags, ou copie via un chemin Windows).

Correctif : Utilisez cp -a ou tar en préservant la propriété. Validez les attentes UID/GID à l’intérieur du conteneur.

5) « docker system prune –volumes a supprimé quelque chose de critique »

Symptôme : Perte de données. Réinitialisation d’apps. Gens en colère.

Cause : Le prune a supprimé des volumes non référencés par des conteneurs, même s’ils contenaient des états précieux ou servaient de sauvegarde.

Correctif : Cessez d’utiliser prune comme scalpel. Avant de lancer prune, inventoriaz les volumes et labellez/taguez tout ce qui est précieux. Conservez des sauvegardes explicites en dehors de la gestion de volumes Docker.

6) « Le volume est local, mais le disque hôte est plein »

Symptôme : Échecs d’écriture, conteneurs en crashloop, migrations interrompues en cours de transfert.

Cause : Les volumes Docker partagent le système de fichiers hôte. Si le root est plein, tout devient bizarre.

Correctif : Vérifiez l’utilisation disque avant et après la migration. Déplacez la racine Docker ou le stockage, ou augmentez la capacité. N’essayez pas de créer une énorme archive tar sur un disque root presque plein.

Listes de contrôle / plan pas à pas

Checklist A : Supprimer un volume dont vous êtes certain qu’il n’est plus nécessaire (en sécurité)

  1. Inspecter le volume ; confirmer que le pilote est attendu.
  2. Trouver tous les conteneurs qui le référencent (en cours et arrêtés).
  3. Confirmer que le contenu n’est pas critique ou est déjà sauvegardé.
  4. Supprimer les conteneurs référents.
  5. Supprimer le volume.
  6. Vérifier que l’application fonctionne encore (parce que parfois « non utilisé » veut dire « non utilisé aujourd’hui »).

Checklist B : Remplacer un volume sans perte de données

  1. Inspecter le volume et identifier la stack propriétaire (les labels Compose aident).
  2. Planifier une fenêtre de maintenance si la charge est stateful.
  3. Arrêter proprement l’app/conteneur.
  4. Prendre une sauvegarde tar de l’ancien volume (la stocker en lieu sûr).
  5. Créer un nouveau volume avec un nom versionné.
  6. Migrer les données (copie hors ligne ou restauration au niveau applicatif).
  7. Recréer les conteneurs/stack pointant vers le nouveau volume.
  8. Exécuter des validations : logs, health checks, requêtes de sanity des données.
  9. Conserver l’ancien volume pendant une période de grâce, puis le supprimer.

Checklist C : « Il faut que ça parte maintenant » mode urgence

  1. Arrêter le conteneur qui utilise le volume.
  2. Exporter immédiatement une archive tar de sauvegarde.
  3. Supprimer les conteneurs référents.
  4. Supprimer ensuite le volume.
  5. Documenter ce que vous avez fait tant que c’est encore frais dans votre mémoire.

Trois mini-récits d’entreprise issus du terrain

Incident causé par une mauvaise hypothèse : « Exited veut dire inutilisé »

Une entreprise SaaS de taille moyenne avait une stack billing gérée par Compose. L’équipe voulait nettoyer de l’espace disque sur un hôte Docker chargé. Quelqu’un a lancé un check rapide : docker ps semblait propre. Ils n’ont vu aucun conteneur utilisant un ancien nom de volume, alors ils ont tenté de le supprimer. Docker a dit « le volume est utilisé ». Gênant, mais au moins ça les a bloqués.

La mauvaise hypothèse est venue ensuite : ils ont décidé que Docker était confus et ont essayé un nettoyage plus large. Ils ont supprimé des conteneurs qu’ils connaissaient, puis relancé des commandes prune pour « en finir ». Le volume a disparu—pas celui ciblé, mais un autre volume « non utilisé » contenant l’état d’un petit sidecar qui s’est avéré être la seule copie du cache de réconciliation de paiements.

L’incident n’était pas dramatique ; c’était pire. Les paiements n’ont pas échoué immédiatement. Ils ont dérivé. Les jobs de réconciliation ont commencé à produire des rapports discordants, déclenchant une revue de conformité. La correction a pris une journée ; la réparation de la confiance a pris des semaines.

Le postmortem était douloureusement ennuyeux : un conteneur arrêté peut toujours référencer un volume, et « non utilisé par des conteneurs en cours » n’est pas la même chose que « sûr à supprimer ». Ils ont ajouté une règle : toute suppression de volume nécessite la liste des conteneurs référents via docker ps -a --filter volume=... et une sauvegarde tar préalable. Personne n’aimait ces étapes supplémentaires. Tout le monde a aimé ne pas revivre l’incident.

Optimisation qui s’est retournée contre eux : « On prune les volumes chaque nuit »

Une autre org a voulu être proactive face à la pression disque. Ils ont ajouté un job nocturne lançant docker system prune -af --volumes. Ça a marché pendant des semaines. Les graphes disque étaient plus plats. L’équipe se sentait responsable.

Puis un ingénieur a déployé une nouvelle version d’un service qui faisait un swap blue/green. L’ancien conteneur a été supprimé comme prévu, et le nouveau a démarré. Mais le volume contenant les fichiers uploadés utilisateur a été temporairement détaché pendant la chorégraphie du déploiement—il y a eu une courte fenêtre où aucun conteneur ne le référençait.

Le prune nocturne est passé dans cette fenêtre et a supprimé le volume d’upload. Le lendemain matin, le service était « sain » mais servait silencieusement des images manquantes et reconstruisait des index contre un répertoire vide. La correction n’a pas été « restaurer depuis une sauvegarde », car il n’y en avait pas. La correction a été « annoncer aux clients que leurs données ont disparu », ce qui est une excellente façon d’entendre le service juridique au téléphone.

La leçon : prune n’est pas une optimisation ; c’est une décision de politique. Si vous voulez un nettoyage automatisé, taggez les volumes et prunez selon des critères explicites, pas simplement selon l’absence de références courantes. Aussi : si vous stockez des données utilisateur dans un volume Docker, traitez‑les comme une base de données—sauvegardes, rétention, et exercices de restauration.

Pratique ennuyeuse mais correcte qui a sauvé la mise : « Volumes versionnés + fenêtre de rollback »

Une entreprise du secteur financier exécutait Postgres dans Docker sur quelques hôtes dédiés. Peu tendance, mais stable. Ils faisaient des upgrades routiniers en créant un nouveau volume par changement : pgdata_2025q4, pgdata_2025q4_patch1, etc. Chaque changement incluait une archive tar stockée hors hôte et un script de validation qui exécutait des checks SQL basiques.

Pendant une mise à jour, le conteneur a démarré, mais les requêtes sont devenues plus lentes. Pas catastrophique, mais suffisant pour déclencher des alarmes de latence. L’équipe a suspecté une régression de stockage sous‑jacente, peut‑être des options de montage ou un bug kernel subtil. Ils n’ont pas débattu pendant des heures. Ils ont rollbacké.

Le rollback a été simple : arrêter le conteneur, repointer vers l’ancien volume, redémarrer. L’ancien volume existait toujours parce que leur processus conservait le volume précédent pendant une période de grâce définie. L’incident visible par les clients a été minimal.

Ensuite, ils ont débogué calmement et ont trouvé qu’un changement « innocent » dans l’étape de migration avait modifié les permissions sur un sous‑répertoire, forçant Postgres dans un comportement moins optimal. Ils ont corrigé la migration, exécuté les validations, et ont poursuivi. La pratique ennuyeuse—volumes versionnés et fenêtre de rollback—a exactement fait ce qu’elle devait : rendre la pire journée moins excitante.

FAQ

1) Pourquoi Docker dit qu’un volume est utilisé quand le conteneur est arrêté ?

Parce que la vérification de Docker se base sur les références de configuration du conteneur, pas sur les processus en cours. Un conteneur arrêté « utilise » toujours le volume dans les métadonnées Docker tant que le conteneur n’est pas supprimé.

2) Comment trouver le conteneur qui utilise mon volume ?

Utilisez le filtre volume sur docker ps -a :

cr0x@server:~$ docker ps -a --filter volume=pgdata
CONTAINER ID   IMAGE        COMMAND                  CREATED       STATUS                 PORTS     NAMES
2d8c1f8b6a1d   postgres:16  "docker-entrypoint.s…"   3 days ago    Up 3 days                        billing-postgres-1

3) Puis‑je « détacher » un volume d’un conteneur sans supprimer le conteneur ?

Pas vraiment. Docker ne supporte pas la modification in‑place de la configuration de montage d’un conteneur. Vous recréez le conteneur avec les montages souhaités.

4) Est‑ce sûr de copier un volume de base de données avec cp -a ?

Uniquement si la base est complètement arrêtée et que vous comprenez les attentes de cohérence au niveau fichier du moteur. Pour des garanties fortes, utilisez les outils natifs de sauvegarde/restauration de la base.

5) Quelle est la façon la plus sûre de remplacer un volume dans Docker Compose ?

Créez un nouveau volume nommé, migrez les données dedans, mettez à jour le fichier Compose pour référencer le nouveau nom de volume, puis docker compose up -d. Conservez l’ancien volume pour rollback jusqu’à validation.

6) Pourquoi ai‑je des volumes avec des noms longs et aléatoires ?

Ce sont souvent des volumes anonymes créés implicitement (par exemple, quand une image déclare un volume et que Compose/run ne l’a pas nommé explicitement). Ils s’accumulent facilement et sont difficiles à attribuer. Inspectez‑les avant de supprimer.

7) Que signifie vraiment « Driver: local » ?

Cela signifie que Docker stocke les données sur le système de fichiers hôte sous la racine des données Docker. Ce n’est ni répliqué, ni partagé entre nœuds, et pas protégé d’une panne disque hôte sauf si vous avez ajouté une protection ailleurs.

8) Puis‑je renommer un volume Docker ?

Docker n’a pas d’opération de renommage pour les volumes. La méthode standard : créer un nouveau volume avec le nom désiré, copier les données, puis mettre à jour les conteneurs/Compose pour l’utiliser.

9) Est‑ce que docker volume prune est sûr ?

Il supprime les volumes non référencés par des conteneurs. Cela peut néanmoins être dangereux si vous conservez des volumes de sauvegarde détachés volontairement ou si vos déploiements détachent temporairement des volumes. Utilisez‑le seulement en connaissance de cause et avec une politique.

Conclusion : prochaines étapes pratiques

Quand Docker dit « le volume est utilisé », il vous protège généralement de vous‑même—en empêchant la suppression d’un volume référencé par une définition de conteneur. Votre travail consiste à identifier la chaîne de références, décider si vous supprimez ou remplacez, et rendre la sécurité des données explicite.

Prochaines étapes que vous pouvez entreprendre aujourd’hui :

  • Choisissez un hôte et inventoriez les volumes avec labels et propriétaires. Les volumes inconnus sont des incidents futurs.
  • Adoptez un schéma standard de remplacement : nouveau volume versionné + migration + validation + fenêtre de rollback.
  • Rédigez une runbook d’une page qui inclut : inspecter le volume, découverte des conteneurs, sauvegarde tar, et l’étape d’approbation avant suppression.
  • Cessez de traiter prune comme une maintenance de routine en production sauf si vous pouvez prouver qu’il ne supprimera pas de données « actuellement détachées » mais précieuses.

L’objectif n’est pas de ne jamais supprimer de volumes. L’objectif est de les supprimer volontairement.

← Précédent
Rspamd : configuration minimale pour un premier déploiement qui fonctionne réellement
Suivant →
WordPress « Réponse JSON invalide » : causes et solutions qui fonctionnent vraiment

Laisser un commentaire