Skip to content

Volume de production Docker ou Kubernetes supprimé : sauvetage docker system prune --volumes, overlay2 Inodes, et etcd Instantanés

Les numéros d'urgence diffèrent selon les pays. Cette page utilise le 911, le numéro des États-Unis et du Canada. De nombreux autres pays utilisent le 112, 999 ou un autre numéro. Trouvez le numéro de votre pays.

En cours d'exécution docker compose down -v, docker system prune -a --volumes, docker volume rm, ou kubectl delete pvc sur le mauvais onglet de terminal en production est l'un des moyens les plus rapides d'effacer un volume de base de données PostgreSQL, MySQL, MariaDB, Redis, MongoDB ou SQLite en direct. Contrairement aux instantanés de machine virtuelle cloud qui sont déplacés vers une corbeille de 7 jours, le pilote de volume local de Docker (/var/lib/docker/volumes/<name>/_data) et Kubernetes local-path / hostPath les fournisseurs publient immédiatement la norme POSIX unlink() et rmdir() appelle directement le système de fichiers hôte Linux sous-jacent (ext4, XFS, ou Btrfs). Chaque écriture effectuée sur cet hôte Linux une fois la commande terminée peut écraser les blocs de base de données libérés sur le disque. Si le disque de votre serveur est rempli à 100 % (0 bytes free) avant que quelqu'un ne s'enfuie docker system prune --volumes en panique, consultez disque du serveur plein à 100 %, surcharge des journaux WAL de la base de données et récupération sans espace; pour les suppressions de fichiers Linux nus en dehors des conteneurs, voir accidentel rm -rf ou Shift-Delete sur ext4, XFS, APFS et NTFS : remontage en lecture seule et sculpture d'inode et Corruption de la chaîne d'instantanés VMDK, VHDX et qcow2 des machines virtuelles et sauvetage de l'hyperviseur. Si cette interruption de production a un impact sur les soins aux patients hospitalisés, la répartition des urgences ou les systèmes de sécurité des services publics, appelez votre numéro d'urgence local (911 aux États-Unis et au Canada, 112 dans toute l'Union européenne, 999 au Royaume-Uni) ou consultez notre annuaire des numéros d'urgence.

Fais ça maintenant

  1. ** NE PAS courir docker compose up -d, systemctl restart docker, ou redéployez le pod Kubernetes** : la recréation du conteneur ou le redémarrage du démon Docker écrit des mégaoctets de nouveaux overlay2 métadonnées, journaux JSON du conteneur et fichiers de base de données vides fraîchement initialisés (initdb) directement sur l'exact ext4 ou XFS bloque où se trouvait votre volume supprimé il y a quelques secondes.
  2. Vérifiez dans 5 secondes si le processus du conteneur (postgres, mysqld, redis-server, node, python) est toujours en cours d'exécution en mémoire (ps aux et sudo lsof +L1) : Si quelqu'un supprime des fichiers à l'intérieur d'un volume monté ou dissocie un volume anonyme alors que le conteneur est toujours en cours d'exécution, le noyau Linux conserve 100 % des fichiers de base de données non liés en vie sur le disque tant que l'ID de processus hôte du conteneur (PID) contient un descripteur de fichier ouvert (FD). Vous pouvez copier ces fichiers directement depuis /proc/<PID>/fd/ ou /proc/<PID>/root/ avec zéro perte de données avant l'arrêt du conteneur.
  3. Si le conteneur est déjà arrêté et que le volume a été supprimé (docker compose down -v ou docker system prune --volumes), geler immédiatement les écritures du disque hôte : Arrêtez le démon Docker (sudo systemctl stop docker.socket docker.service containerd) afin que les conteneurs d'arrière-plan et les contrôles de santé cessent d'écrire des journaux dans /var/lib/docker, puis soit remonter /var/lib/docker (ou la racine / partition) en lecture seule (sudo mount -o remount,ro /) ou prenez un instantané immédiat du volume cloud au niveau du bloc (AWS EBS Snapshot, GCP Persistent Disk Snapshot, DigitalOcean Volume Snapshot) avant de toucher quoi que ce soit.
  4. Si vous êtes sur Kubernetes (kubectl delete pvc ou kubectl delete namespace), vérifiez le PersistentVolume (PV) ReclaimPolicy (kubectl get pv) immédiatement :
  5. Si le PV avait persistentVolumeReclaimPolicy: Retain, vos données ne sont pas supprimées : le PV simplement déplacé vers Released statut et votre disque cloud (EBS, Azure Disk, Ceph RBD, NFS) est intact à 100 pour cent.
  6. Même si kubectl delete pvc est coincé dans Terminating, Kubernetes Finaliseurs (kubernetes.io/pvc-protection) empêche le pilote CSI de supprimer le stockage sous-jacent tant qu'un pod fait toujours référence à ce PVC. Ne supprimez pas le pod tant que vous n'avez pas copié les données du pod en cours d'exécution.
  7. Imagez la partition de bloc sous-jacente (dd / ddrescue via SSH) sur un disque externe ou un volume cloud séparé avant d'exécuter ext4magic, extundelete, ou PhotoRec : N'exécutez jamais des sculpteurs de fichiers qui écrivent des fichiers de sortie sur la même partition de disque à partir de laquelle vous effectuez la récupération. /var/lib/docker/volumes.
  8. Pour l'état du cluster Kubernetes corrompu ou accidentellement effacé (kubectl delete crd / namespace), arrêt kube-apiserver et restaurez votre dernier etcd instantané (etcdctl snapshot restore) : Si l'état du cluster dans etcd a été effacé alors que les volumes de stockage cloud sous-jacents existent toujours, restaurant etcd récupère tout PV, PVC, Secret, et ConfigMap objets simultanément.

Danger

Ne retirez jamais le kubernetes.io/pvc-protection ou kubernetes.io/pv-protection finaliseur avec kubectl patch ... -p '{"metadata":{"finalizers":null}}' quand un PVC est coincé dedans Terminating : Ce finaliseur est la seule chose qui conserve votre pilote cloud CSI (aws-ebs-csi-driver, pd.csi.storage.gke.io, Longhorn, Rook-Ceph) de délivrer un matériel DeleteVolume Appel API pour détruire votre disque de production. Pendant que le PVC est coincé Terminating, le Pod est toujours en cours d'exécution et le volume est toujours monté : exécutez kubectl exec ou kubectl cp (ou pg_dump / mysqldump) immédiatement pour récupérer 100 % de votre base de données avant la fin du Pod.


Arbre de décision : volume Docker supprimé, overlay2 couche, ou triage Kubernetes PVC

Utilisez cet organigramme pour choisir le chemin de récupération sans perte le plus rapide selon que le processus du conteneur est toujours actif, si le volume a été sauvegardé par un disque local ou un stockage CSI cloud et quel système de fichiers héberge /var/lib/docker:

flowchart TD
    Start["Données de production manquantes après la commande de suppression Docker ou Kubernetes"] --> WhichEnv{"Quelle plate-forme et quelle commande ont déclenché la perte ?"}

    WhichEnv -->|"Docker : conteneur toujours en cours d'exécution (fichiers non liés à l'intérieur du volume/conteneur)"| ProcRescue["Sauvetage des descripteurs de fichiers ouverts non liés via sudo lsof +L1 et /proc/PID/fd/N ou /proc/PID/root/"]

    WhichEnv -->|"Docker : conteneur arrêté et volume supprimé (compose down -v / prune --volumes)"| StopDocker["Exécuter immédiatement : sudo systemctl stop docker.socket docker containersd"]

    WhichEnv -->|"Kubernetes : kubectl supprime pvc / pv / statefulset / espace de noms"| K8sCheck{"Le pod est-il toujours en cours d'exécution OU le PVC est-il bloqué lors de la terminaison ?"}

    K8sCheck -->|"Oui : le pod est toujours en cours d'exécution (le finaliseur bloque la suppression de CSI)"| K8sExec["NE PAS supprimer le pod -> Exécuter immédiatement kubectl exec / pg_dump / tar via stdout sur le disque local"]
    K8sCheck -->|"Non : Pod Gone -> Vérifiez que kubectl obtient pv"| ReclaimCheck{"Quelle était la politique de récupération des PV ?"}

    ReclaimCheck -->|"Conserver (Statut PV = Libéré)"| ClearClaimRef["100 % de données intactes -> Modifier le PV pour supprimer spec.claimRef.uid -> Relier au nouveau PVC"]
    ReclaimCheck -->|"Supprimer (Cloud EBS / PD / Longhorn / Local-Path)"| CloudOrLocal{"Volume Cloud CSI ou disque hôte local ?"}

    CloudOrLocal -->|"Cloud CSI (AWS EBS/GCP/Azure/Ceph)"| CloudSnap["Vérifiez la corbeille de Cloud Console / les instantanés EBS automatisés / la corbeille Ceph RBD (rbd trash ls)"]
    CloudOrLocal -->|"Disque de nœud local (chemin-local / hostPath)"| StopDocker

    StopDocker --> RemountRO["Remonter la partition hôte en lecture seule (mount -o remount,ro) OU diffuser l'image de bloc via SSH"]
    RemountRO --> HostFS{"Quel système de fichiers héberge /var/lib/docker ?"}
    HostFS -->|"poste4"| Ext4Rec["Utiliser debugfs / ext4magic Journal Inode Transaction Rollback (-un horodatage)"]
    HostFS -->|"XFS/Btrfs"| CarveRec["Utilisez Btrfs Roots / xfs_irecover / Custom Signature Carving pour SQLite, Postgres Heap ou InnoDB .ibd"]

Phase 1 : Comment Docker et Kubernetes suppriment réellement les volumes sur le disque

Avant d'exécuter une commande de récupération, comprenez où se trouvaient physiquement vos données sur l'hôte Linux et ce que la commande de suppression a réellement touché :

Type de stockage et commande de suppression Chemin du système de fichiers hôte sur le nœud Linux Ce que la commande Supprimer a réellement fait Méthode de récupération immédiate
Volume Docker nommé (docker volume rm ou docker compose down -v) /var/lib/docker/volumes/<vol_name>/_data Dissocié les fichiers à l'intérieur _data/ et supprimé l'entrée du répertoire de /var/lib/docker/volumes/metadata.db (boltdb). Arrêtez Docker immédiatement, remontez /var/lib/docker en lecture seule et récupérer les inodes non liés via ext4magic / debugfs ou une sculpture de signature.
Volume Docker anonyme (docker run -v /var/lib/mysql + docker rm -v ou docker system prune --volumes) /var/lib/docker/volumes/<64-char-hex-id>/_data docker system prune --volumes supprime tous les volumes anonymes et nommés non actuellement référencés par au moins un conteneur existant. Arrêtez Docker immédiatement ; si vous aviez d'autres conteneurs arrêtés dont les volumes n'étaient pas élagués, vérifiez le reste /var/lib/docker/volumes/*/_data dossiers avant de sculpter des blocs non alloués.
Couche inscriptible du conteneur (docker rm <container> lorsque les données ont été écrites en dehors d'un volume) /var/lib/docker/overlay2/<layer-id>/diff/ Dissocier la partie supérieure du conteneur diff/ répertoire à l'intérieur du overlay2 pilote de stockage. Arrêtez Docker immédiatement et récupérez l'arborescence de répertoires non liée à partir du ext4 journal ou XFS blocs.
Docker Desktop sur macOS ou Windows (docker system prune --volumes) Dans une seule image disque de machine virtuelle : -/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw (macOS) ou %LocalAppData%\Docker\wsl\disk\docker_data.vhdx (Windows WSL2). Envoyé unlink() à l'intérieur de la machine virtuelle Linux, et si discard/TRIM est actif sur Docker.raw / docker_data.vhdx, a percé des trous clairsemés dans le fichier hôte. Quittez Docker Desktop dans les 5 secondes, copiez Docker.raw ou docker_data.vhdx sur un disque externe et exécutez ext4magic / PhotoRec par rapport à l’image du disque virtuel.
Kubernetes PVC avec Delete ReclaimPolicy sur Ceph RBD (Rook-Ceph) ou Longhorn Pool OSD Ceph (rbd) ou /var/lib/longhorn/replicas/. Si csi-rbdplugin a trash activé (rbd trash), l'image RBD est déplacée vers la corbeille Ceph ; sinon les blocs ne sont pas mappés. Courir rbd trash ls --pool <pool> à l'intérieur du rook-ceph-tools pod et restaurer avec rbd trash restore.

Phase 2 : Récupération des fichiers de base de données ouverts à partir d'un conteneur toujours en cours d'exécution (/proc/<pid>/fd/)

Attendez : le conteneur est-il toujours en cours d'exécution ? Souvent, un ingénieur exécute un script de migration d'application, une tâche cron de nettoyage ou un manuel rm -rf /var/lib/postgresql/data/* ou rm /app/data/production.sqlite3 à l'intérieur d'un conteneur en cours d'exécution, ou supprime le dossier de montage de liaison de l'hôte sous-jacent /opt/app/data tandis que le conteneur lui-même (postgres, mysqld, mariadbd, redis-server, mongod, gunicorn, node) est toujours opérationnel.

Sous Linux, un fichier n'est pas supprimé du disque lorsque rm ou unlink() est appelé. Ses blocs de disque et son inode restent 100 % alloués et lisibles jusqu'au dernier processus contenant un descripteur de fichier ouvert (FD) vers cet inode le ferme ou le quitte.

Étape 1 : Recherchez l'ID du processus hôte (PID) du processus de conteneur

Sur le nœud hôte Linux (pas à l'intérieur du conteneur), recherchez l'hôte PID de votre base de données ou de votre processus de candidature :

sudo lsof +L1 | grep -E "postgres|mysqld|mariadbd|sqlite|redis|mongo|node|python|java"
Regardez le résultat :
COMMAND     PID   USER   FD   TYPE DEVICE  SIZE/OFF NLINK    NODE NAME
mysqld    18492    999   14u   REG  259,1 482344960     0 1849201 /var/lib/mysql/app_prod/users.ibd (deleted)
mysqld    18492    999   15u   REG  259,1 125829120     0 1849202 /var/lib/mysql/app_prod/orders.ibd (deleted)
mysqld    18492    999   16u   REG  259,1  79691776     0 1849190 /var/lib/mysql/ibdata1 (deleted)
python3   22104   1000    4u   REG  259,1  89128960     0 3102944 /data/production.sqlite3 (deleted)
Regardez la colonne NLINK: ça dit 0, et le nom du fichier se termine par (deleted). Le fichier a complètement disparu de ls /var/lib/docker/volumes/..., mais chaque octet (482 MB dans users.ibd, 89 MB dans production.sqlite3) est toujours vivant à l'intérieur /proc/<PID>/fd/<FD>.

Étape 2 : Copiez les fichiers de base de données non liés directement depuis /proc/<PID>/fd/

N'arrêtez pas et ne redémarrez pas le conteneur. Pendant que le processus est toujours en cours, copiez les descripteurs de fichiers bruts directement dans un dossier sécurisé sur votre hôte :

sudo mkdir -p /root/proc_emergency_rescue

# Example 1: Rescuing an unlinked SQLite3 database (PID 22104, FD 4)
sudo cp /proc/22104/fd/4 /root/proc_emergency_rescue/production.sqlite3
# Check if PID 22104 also holds the -wal file open (e.g. FD 5) and copy it too:
sudo cp /proc/22104/fd/5 /root/proc_emergency_rescue/production.sqlite3-wal

# Example 2: Automatically rescuing ALL open (deleted) MySQL/Postgres files for PID 18492
for fd in /proc/18492/fd/*; do
    target=$(sudo readlink "$fd" 2>/dev/null)
    if echo "$target" | grep -q "(deleted)"; then
        fd_num=$(basename "$fd")
        clean_name=$(echo "$target" | sed 's/ (deleted)//; s/\//_/g')
        echo "Rescuing FD $fd_num -> $clean_name"
        sudo cp "$fd" "/root/proc_emergency_rescue/${fd_num}${clean_name}"
    fi
done

Étape 3 : Encore mieux : exécutez un vidage logique en direct (pg_dump / mysqldump / .backup) avant que le conteneur ne ferme les FD

Si postgres ou mysqld est toujours en cours d'exécution avec ses fichiers de données ouverts en mémoire et /proc/<PID>/fd/, essayez d'abord d'exécuter un vidage logique en direct sur le socket Unix existant ou la connexion TCP :

# If the database engine can still read its open file descriptors:
docker exec <container_name> pg_dumpall -U postgres > /root/proc_emergency_rescue/live_dump.sql
# Or for MySQL:
docker exec <container_name> mysqldump -u root -p --all-databases --single-transaction > /root/proc_emergency_rescue/live_mysql.sql
(Remarque : PostgreSQL s'ouvre et se ferme .1, .2 segmenter les fichiers à travers les processus de travail de manière dynamique, donc pg_dump peut échouer sur les tables non mises en cache ; combinant une requête SQL en direct avec la copie de chaque ouverture /proc/<pid>/fd/* dans tous postgres Les PID du backend enfant enregistrent le maximum de données de tas de table possible.)


Phase 3 : Récupération d'un volume Docker supprimé sur ext4 ou XFS après l'arrêt du conteneur

Et si tu courais docker compose down -v ou docker system prune --volumes, donc le conteneur est déjà arrêté et tout /proc/<pid>/fd/ les descripteurs sont fermés ? Vous êtes maintenant dans une course contre les écritures de disque en arrière-plan sur l'hôte Linux.

Étape 1 : Gelez le système de fichiers hôte Linux dans les 10 secondes

  1. Arrêtez immédiatement Docker, containersd, kubelet et cron afin qu'aucun conteneur, contrôle de santé ou rotateur de journal n'écrive un autre octet dans /var/lib/docker:
    sudo systemctl stop docker.socket docker.service containerd.service cron.service
    
  2. ** Vérifiez quel périphérique de bloc et quel système de fichiers contiennent /var/lib/docker** :
    df -Th /var/lib/docker
    
    Filesystem     Type  Size  Used Avail Use% Mounted on
    /dev/nvme0n1p1 ext4  100G   42G   58G  42% /
    
  3. Remontez la partition en lecture seule (ou diffusez une image de partition brute via SSH sur une autre machine) :
  4. Si /var/lib/docker se trouve sur sa propre partition dédiée ou volume LVM (par exemple /dev/nvme0n1p2 ou /dev/mapper/vg0-docker), remontez-le immédiatement en lecture seule :
    sudo mount -o remount,ro /var/lib/docker
    
  5. Si /var/lib/docker est à la racine / partition (/), essayez de forcer la partition racine en lecture seule à l'aide du déclencheur Magic SysRq du noyau (echo u | sudo tee /proc/sysrq-trigger) ou sudo mount -o remount,ro /.
  6. Si vous êtes sur un VPS cloud (AWS EC2, GCP, DigitalOcean, Hetzner, Linode) : accédez immédiatement à votre console Web cloud et cliquez sur Créer un instantané sur le volume de bloc du serveur (ou diffusez le périphérique de bloc brut via SSH vers un deuxième serveur : sudo dd if=/dev/nvme0n1p1 bs=4M status=progress | gzip -1 | ssh user@backup-server "cat > /mnt/storage/docker_host_raw.img.gz").

Étape 2 : Vérifiez si vos données se trouvent toujours dans UN AUTRE volume non élagué ou overlay2 couche

Avant de découper des blocs de disque non alloués, vérifiez que votre base de données n'a pas été réellement stockée dans un montage lié ou dans un volume nommé différemment qui a survécu :

# Search the entire /var/lib/docker tree read-only for any surviving database files:
sudo find /var/lib/docker -name "PG_VERSION" -o -name "ibdata1" -o -name "*.sqlite*" -o -name "*.db" -o -name "dump.rdb" -o -name "WiredTiger" 2>/dev/null
Chaque semaine, les administrateurs paniquent après avoir exécuté docker volume rm app_db_data, à découvrir avec find /var/lib/docker que docker-compose.yml avait effectivement créé projectname_app_db_data (qui est encore intact à 100 pour cent sur le disque) tandis que app_db_data était un vieux volume inutilisé d’il y a six mois.

Étape 3 : Récupération des répertoires de volumes Docker non liés sur ext4 en utilisant le ext4 Journal (ext4magic et debugfs)

Quand docker volume rm supprime /var/lib/docker/volumes/<vol_name>/_data sur un ext4 système de fichiers, ext4 remet à zéro les pointeurs de bloc directs (i_block / racine de l'arborescence) dans la table des inodes en direct. Cependant, le ext4 journal (inode <8>, généralement 128 MB à 1024 MB tampon en anneau circulaire) contient toujours des copies historiques des tables d'inodes exactes et des blocs de répertoire juste avant docker compose down -v a été exécuté.

+-------------------------------------------------------------------------+
| HOW ext4magic RECOVERS A DELETED DOCKER VOLUME FROM THE EXT4 JOURNAL    |
|                                                                         |
| Live Inode Table on Disk (After docker volume rm):                      |
|   Inode #918402 (users.ibd): [Size = 0, Extent Pointers = ZEROED]       |
|                                                                         |
| Ext4 Journal Ring Buffer (Inode <8> on Disk):                           |
|   Transaction #41902 (10 mins ago):                                     |
|   Inode #918402 (users.ibd): [Size = 482MB, Extents = Blocks 9000..9999]|
|                                                                         |
| -> ext4magic reads the old Inode Copy from Journal Transaction #41902   |
|    and extracts Blocks 9000..9999 directly to your rescue drive.        |
+-------------------------------------------------------------------------+

Courir ext4magic contre votre partition en lecture seule (ou le .img copie d'instantané sur un deuxième serveur), en spécifiant un horodatage (-a) de 5 minutes avant votre course docker compose down -v ou docker system prune --volumes:

# Install ext4magic on your rescue machine (never on the affected partition)
sudo apt-get install -y ext4magic e2fsprogs

# Dump the ext4 journal from the frozen partition / image to a file in RAM (/dev/shm)
sudo debugfs -R "dump <8> /dev/shm/ext4_journal.copy" /dev/nvme0n1p1

# Recover all files deleted under var/lib/docker/volumes after (Current Time - 15 minutes)
sudo mkdir -p /mnt/external_rescue/docker_recovered
sudo ext4magic /dev/nvme0n1p1 \
  -j /dev/shm/ext4_journal.copy \
  -f var/lib/docker/volumes \
  -a $(date -d "-15 minutes" +%s) \
  -r -d /mnt/external_rescue/docker_recovered
- -j /dev/shm/ext4_journal.copy: lit l'instantané du journal que vous avez enregistré dans la RAM immédiatement après l'arrêt de Docker. - -f var/lib/docker/volumes: cible l'arborescence exacte des répertoires des volumes Docker (remarque : omettez le début / dans ext4magic chemins relatifs). - -a $(date -d "-15 minutes" +%s): raconte ext4magic pour reconstruire l'arborescence des répertoires à l'aide de copies d'inodes valides il y a 15 minutes (juste avant la suppression accidentelle). - -r: Récupère les répertoires complets où aucun bloc n'a été écrasé ; si -r manque les fichiers partiellement écrasés, exécutez une deuxième passe en remplaçant -r avec -m (sculpture magique + mode hybride journal).

Étape 4 : Sculpture de fichiers bruts SQLite, PostgreSQL ou MySQL InnoDB une fois le journal terminé (XFS ou ext4)

Warning

Pourquoi XFS ne supporte pas ext4magic et nécessite un démontage immédiat en lecture seule : contrairement à ext4, qui écrit des copies complètes d'inodes de 256 octets dans son journal, XFS enregistre les deltas d'intention des métadonnées et réutilise de manière agressive les arbres B d'inodes libérés (agi). Si /var/lib/docker est assis sur un XFS partition (par défaut sur RHEL, Rocky Linux, AlmaLinux et Amazon Linux), démontage /var/lib/docker ou remontage / la lecture seule en quelques secondes est l'étape la plus importante avant la sculpture.

Si l'hôte utilise XFS ou si le ext4 journal déjà enroulé sur les pointeurs d'inode, utilisez la signature et la sculpture de structure sur l'image disque brute (docker_host_raw.img) :

  1. Pour les bases de données SQLite3 (.sqlite, .db - par exemple, Vaultwarden, Nextcloud, Home Assistant, Gitea, Grafana) : Chaque base de données SQLite3 commence par un en-tête ASCII indubitable de 16 octets à l'octet 0 de sa première page de 4 kilo-octets : 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 ("SQLite format 3\0"), et stocke la taille exacte de la page de la base de données (Bytes 16..17, généralement 4096) et la taille totale de la base de données en pages (Bytes 28..31, entier big-endian 32 bits) directement à l'intérieur de ce même en-tête.
  2. Courir PhotoRec avec [File Opt] -> [x] sqlite activé, ou scannez la partition directement avec grep -ab "SQLite format 3" pour trouver le décalage d'octets exact de votre fichier SQLite supprimé et l'extraire avec dd:
    # Find the exact byte offsets of every "SQLite format 3" header on the partition:
    sudo grep -ab "SQLite format 3" /dev/nvme0n1p1
    
    Une fois extrait, exécutez sqlite3 carved.db ".recover" | sqlite3 repaired.db pour reconstruire chaque page de feuille intacte de l'arbre B.

Tip

Comment calculer le montant exact dd taille en octets d'un fichier SQLite3 non lié à partir de son en-tête : une fois grep -ab "SQLite format 3" vous donne le décalage d'octet de départ OFFSET de votre base de données SQLite supprimée, lire les octets 16..17 (Taille de page big-endian uint16, par exemple : 0x1000 = 4096 octets) et octets 28..31 (Nombre de pages big-endian uint32, par exemple : 25000 pages) en utilisant hexdump -C -s OFFSET -n 32. Multiplier Page Size x Page Count vous donne la longueur exacte d'octet à transmettre dd (iflag=skip_bytes,count_bytes) lorsque le fichier est contigu sur le disque.

  1. Pour MySQL/MariaDB InnoDB (.ibd fichiers de table) : Chaque InnoDB .ibd le tableau se compose de séquences 16 KB (16,384 octet) pages contenant le FIL_PAGE_INDEX (0x45BF) en-tête et unique de la table space_id. Utilisez le Percona / TwinDB undrop-for-innodb (stream_parser + c_parser) boîte à outils pour analyser /dev/nvme0n1p1 pour tous 16 KB Pages d'index InnoDB et videz chaque ligne directement dans des fichiers TSV/SQL pour la réimporter.
  2. Pour les fichiers de tas PostgreSQL ($PGDATA/base/<db_oid>/<relfilenode>) : PostgreSQL stocke chaque table comme contiguë 8 KB (8,192 octet) pages de tas contenant PageHeaderData (pd_lower, pd_upper, pd_special). Utiliser pg_filedump ou pglazarus / pdu pour analyser les régions de disque non allouées 8 KB pages correspondant à la disposition des tuples de colonnes de votre table (HeapTupleHeaderData) et reconstruisez les lignes.

Phase 4 : Kubernetes PVC, PV et etcd Récupération d'urgence d'un instantané

Dans Kubernetes (EKS, GKE, AKS, k3s, RKE2, kubeadm, OpenShift), supprimant accidentellement un PersistentVolumeClaim (kubectl delete pvc), un StatefulSet ou un espace de noms entier (kubectl delete ns prod) suit une architecture très différente de celle de Docker autonome.

Scénario A : Les spectacles PVC Terminating (Le finaliseur Lifesaver)

Courir:

kubectl get pvc -n <namespace>
Si le STATUS la colonne dit Terminating, poussez un soupir de soulagement : vos données n'ont PAS encore été supprimées. - Pourquoi? Chaque PVC Kubernetes créé depuis Kubernetes 1.9 inclut automatiquement finalizers: [kubernetes.io/pvc-protection]. - Tant qu'un pod monte toujours ce PVC, le contrôleur Kubernetes refuse de terminer la suppression du PVC et ** n'appelle jamais le pilote CSI. DeleteVolume RPC**. - Action immédiate : Ne supprimez ou ne redémarrez PAS le pod, et ne corrigez PAS le finaliseur. Copiez immédiatement toutes les données du pod en cours d'exécution sur votre ordinateur local ou dans un bucket S3 :
# Stream a compressed tar backup or pg_dump out of the still-running pod immediately:
kubectl exec -n <namespace> <pod-name> -- pg_dumpall -U postgres > ./rescued_k8s_db.sql
# Or tar an entire mounted volume directory out over stdout:
kubectl exec -n <namespace> <pod-name> -- tar czf - /var/lib/postgresql/data > ./rescued_pvc_files.tar.gz

Scénario B : la PVC a été supprimée et kubectl get pv affiche le volume persistant dans Released État (ReclaimPolicy: Retain)

Courir:

kubectl get pv
Si votre PersistentVolume (pv-prod-postgres) est toujours répertorié avec STATUS: Released (car sa StorageClass utilisée reclaimPolicy: Retain), 100 % de vos données restent intactes sur le disque sous-jacent. Cependant, Kubernetes refuse de laisser un nouveau PVC se lier à un Released PV car le PV contient toujours un spec.claimRef pointant vers les anciens PVC supprimés UID.

Comment faire un Released PV Available à nouveau en 10 secondes sans perte de données : 1. Modifiez l'objet PersistentVolume et supprimez le spec.claimRef bloc:

kubectl patch pv <your-pv-name> --type json -p '[{"op": "remove", "path": "/spec/claimRef"}]'
2. Courir kubectl get pv encore une fois : le statut passe immédiatement de Released à Available. 3. Recréez votre PersistentVolumeClaim (en précisant volumeName: <your-pv-name> et correspondant à la capacité/storageClassName). Il se liera immédiatement au PV existant avec tous les fichiers intacts.

Scénario C : Restauration d'un état de cluster Kubernetes effacé à partir d'un etcd instantané (etcdctl snapshot restore)

Et si quelqu'un courait kubectl delete namespace prod ou helm uninstall et effacé 200 manifestes Kubernetes, secrets, ConfigMaps et définitions PV sur un site autogéré. kubeadm, k3s, ou RKE2 avion de contrôle ?

  1. ** Localisez votre dernier etcd instantané** (par défaut dans /var/lib/rancher/k3s/server/db/snapshots/, /var/lib/rancher/rke2/server/db/snapshots/, ou votre horaire /var/backups/etcd/snapshot.db).
  2. Vérifiez l'intégrité de l'instantané avant de toucher le cluster actif :
    ETCDCTL_API=3 etcdctl snapshot status /path/to/snapshot.db --write-out=table
    
  3. Arrêt kube-apiserver et etcd sur le(s) nœud(s) du plan de contrôle :
  4. Sur kubeadm (pods statiques) : Déplacer /etc/kubernetes/manifests/kube-apiserver.yaml et /etc/kubernetes/manifests/etcd.yaml temporairement pour /root/manifests_hold/ donc kubelet arrête proprement les deux conteneurs, puis recule /var/lib/etcd à /var/lib/etcd.bak.
  5. Sur k3s: Courir sudo systemctl stop k3s et sudo k3s server --cluster-reset --cluster-reset-restore-path=/path/to/snapshot.
  6. ** Restaurer le etcd répertoire de données sur kubeadm** :
    sudo ETCDCTL_API=3 etcdctl snapshot restore /path/to/snapshot.db \
      --data-dir=/var/lib/etcd \
      --name=<control-plane-node-name> \
      --initial-cluster=<node-name>=https://<node-ip>:2380 \
      --initial-advertise-peer-urls=https://<node-ip>:2380
    
  7. Se déplacer etcd.yaml et kube-apiserver.yaml de retour dans /etc/kubernetes/manifests/. Dans les 30 secondes, kube-apiserver se reconnecte au restauré etcd store et chaque objet Namespace, Secret, ConfigMap et PersistentVolume supprimé réapparaît.

Phase 5 : Renforcement des volumes Docker et Kubernetes contre toute suppression accidentelle

Une fois votre base de données de production restaurée, implémentez ces quatre garde-fous architecturaux afin qu'une seule faute de frappe CLI ne puisse plus jamais supprimer un volume actif :

  • Modifiez chaque Kubernetes de production StorageClass de reclaimPolicy: Delete à reclaimPolicy: Retain : Par défaut, les StorageClasses cloud intégrées (gp2, gp3, standard-rwo) par défaut reclaimPolicy: Delete, ce qui signifie que la suppression d'un PVC détruit le disque cloud. Créer un StorageClass avec reclaimPolicy: Retain (ou patcher les PV existants avec kubectl patch pv <pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'), donc la suppression d'un PVC ou d'un espace de noms ne supprime jamais le volume de bloc sous-jacent.
  • Activez la corbeille AWS EBS/les planifications d'instantanés GCP/Velero avec les instantanés CSI : l'activation de la corbeille AWS EBS conserve tout volume EBS supprimé pendant 7 à 30 jours, même si le pilote CSI appelle DeleteVolume.
  • Ne jamais utiliser docker system prune --volumes dans les scripts de nettoyage automatisés ou les exécuteurs CI/CD : si un conteneur de base de données de production plante brièvement (Exited (1)) au moment précis où une tâche cron s'exécute docker system prune -a --volumes -f, Docker considère ses volumes anonymes « inutilisés » et les supprime définitivement. Bande --volumes de tous les scripts de nettoyage.
  • ** Utilisez des montages de liaison d'hôte explicites (/srv/prod_data/postgres:/var/lib/postgresql/data) ou des bases de données gérées externes pour les charges de travail de production avec état** : contrairement à /var/lib/docker/volumes/, héberge les répertoires de montage de liaison à l'extérieur /var/lib/docker/ ne sont jamais touchés par docker compose down -v, docker volume rm, ou docker system prune --volumes.

Numéros d'urgence régionaux et protocoles des agences

Lorsqu’une suppression d’un conteneur ou d’un stockage Kubernetes a un impact sur les opérations cliniques de l’hôpital, la sécurité publique ou les données personnelles réglementées, faites immédiatement remonter :

  • États-Unis et Canada : Composez 911 si une défaillance d'un cluster de conteneurs désactive la surveillance clinique des patients, les systèmes DSE ou la répartition d'urgence. Signalez l’effacement malveillant de l’infrastructure de conteneurs ou les cyberincidents à CISA (1-844-Say-CISA / cisa.gov/report) ou le Centre canadien pour la cybersécurité (1-833-CYBER-88).
  • Royaume-Uni : Composez 999 pour les menaces contre la vie ou les infrastructures critiques du NHS. En vertu du RGPD britannique, la destruction permanente ou la perte de disponibilité des données personnelles sans sauvegarde récupérable nécessite l'évaluation d'une notification de violation de 72 heures à l'ICO (0303 123 1113).
  • Union européenne : Composez 112 dans tous les États membres de l'UE. Les entités relevant de la Directive NIS2 doivent soumettre une alerte précoce à leur CSIRT national dans les 24 heures suivant une panne de service grave, et la perte permanente de données personnelles déclenche un rapport Article 33 du RGPD dans les 72 heures.
  • Australie et Nouvelle-Zélande : Composez 000 en Australie ou 111 en Nouvelle-Zélande ; signaler les incidents liés aux infrastructures critiques à l'ACSC (1300 CYBER1).
  • Inde et Asie-Pacifique : Composez 112 en Inde pour les interventions d'urgence ; signaler les incidents de sécurité du cloud ou des conteneurs à CERT-In (incident@cert-in.org.in) dans la fenêtre obligatoire de 6 heures.

Questions fréquemment posées

Fait docker compose down -v supprimer les montages de liaison d'hôte (./data:/var/lib/mysql) ou uniquement les volumes Docker nommés et anonymes ?

`docker compose down -v` Supprime UNIQUEMENT les volumes nommés déclarés dans le `volumes:` section de `docker-compose.yml` et volumes anonymes attachés aux conteneurs; il jamais supprime les fichiers à l'intérieur d'un montage de liaison hôte (tel que `- /opt/mysql_data:/var/lib/mysql` ou `- ./postgres_data:/var/lib/postgresql/data`). Si votre fichier de composition utilisait un chemin d'hôte commençant par `/` ou `./`, vérifiez ce dossier sur l'hôte dès maintenant : vos fichiers sont toujours intacts à 100 %.

Pourquoi docker system prune --volumes supprimer mon volume de base de données alors que je n'ai arrêté le conteneur que 2 minutes pour mettre à jour une variable d'environnement ?

Attendez attentivement la distinction entre `docker stop` et `docker rm`: si un conteneur est simplement `Stopped / Exited` (visible dans `docker ps -a`), `docker system prune --volumes` fait pas supprimez ses volumes car le conteneur arrêté les référence toujours. Cependant, si vous avez couru `docker rm ` (pour recréer le conteneur avec de nouveaux drapeaux) ou si vous avez passé `docker system prune -a --volumes` (qui supprime d'abord tous les conteneurs arrêtés et alors supprime tous les volumes qui ne sont plus attachés à aucun conteneur), le volume est devenu "pendant" à la milliseconde où le conteneur arrêté a été retiré et a été effacé immédiatement après.

Puis-je récupérer un volume Docker supprimé dans Docker Desktop sur un Mac (Apple Silicon / Intel) ou Windows (WSL2) ?

Oui, si vous quittez Docker Desktop immédiatement pour que la machine virtuelle cesse de fonctionner `fstrim` contre le disque virtuel. Sur macOS, Docker stocke tous les volumes Linux à l'intérieur `-/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw`; sous Windows WSL2, à l'intérieur `%LocalAppData%\Docker\wsl\disk\docker_data.vhdx`. Copie ça `.raw` ou `.vhdx` fichier sur un SSD externe immédiatement, attachez-le en lecture seule sous Linux (en utilisant `losetup -Pr` pour `.raw` ou `qemu-nbd -r` pour `.vhdx`), et exécutez `ext4magic` ou `PhotoRec` contre le virtuel `ext4` cloison à l'intérieur.

Et si je supprimais un StatefulSet Kubernetes avec kubectl delete statefulset postgres? Est-ce que cela a également supprimé mes PVC ?

Non. Par défaut dans Kubernetes (sauf si `persistentVolumeClaimRetentionPolicy.whenDeleted: Delete` a été explicitement configuré sur Kubernetes 1.27+), en cours d'exécution `kubectl delete statefulset` supprime le contrôleur StatefulSet et ses Pods, laissant tout `PersistentVolumeClaims` (`data-postgres-0`, `data-postgres-1`) et leurs données sous-jacentes 100 % intactes. Réappliquez simplement votre `StatefulSet` Manifeste YAML avec le même nom et `volumeClaimTemplates`, et les nouveaux pods se rattacheront automatiquement aux modules existants. `data-postgres-0` PVC.

Comment accéder aux fichiers dans un Docker overlay2 répertoire lorsque le conteneur refuse de démarrer (CrashLoopBackOff / Exited (1)) ?

Ne supprimez pas le conteneur en panne. Tant que le conteneur arrêté existe toujours dans `docker ps -a`, sa couche inscriptible et ses montages de volume sont complètement intacts sur le disque. Vous pouvez soit copier des fichiers directement hors du conteneur arrêté en utilisant `docker cp :/var/lib/postgresql/data /root/rescued_data`, ou trouver son hôte exact `overlay2` chemin en courant `docker inspect --format '{{.GraphDriver.Data.UpperDir}}'` et lire ce répertoire directement comme `root`.

Et si quelqu'un supprimait un Kubernetes Namespace (kubectl delete ns prod) et tous les PVC avaient reclaimPolicy: Delete sur AWS EBS ou GCP ?

Si le pilote cloud CSI (`ebs.csi.aws.com` ou `pd.csi.storage.gke.io`) déjà exécuté `DeleteVolume` parce que `reclaimPolicy` était `Delete`, vérifiez immédiatement trois filets de sécurité au niveau du cloud : (1) cochez **Corbeille AWS pour les volumes EBS** dans la console AWS EC2 (si une règle de conservation était active sur le compte/les balises, le volume EBS supprimé se trouve dans la corbeille et peut être restauré en 1 clic) ; (2) vérifiez **AWS Backup / DLM / GCP Snapshot Schedules** pour l'instantané de volume automatisé le plus récent ; et (3) vérifiez si votre base de données diffusait des WAL/binlogs (`WAL-G`, `pgBackRest`, `Litestream`) vers un compartiment S3/GCS.


Guides associés


Sources et directives officielles

  • Documentation officielle de Kubernetes (kubernetes.io / Cloud Native Computing Foundation) : * Protection des objets de stockage en cours d'utilisation (kubernetes.io/pvc-protection Finaliseurs), récupération des volumes persistants (Retain contre Delete) et Fonctionnement etcd Clusters pour Kubernetes (etcdctl snapshot restore)*.
  • Docker Inc. (docs.docker.com): Gérer les données dans Docker : Volumes, Lier les montages, overlay2 Architecture du pilote de stockage et référence Prune.
  • L'organisation du noyau Linux (kernel.org): Le /proc Système de fichiers (procfs Ouvrez la récupération du descripteur de fichier via /proc/<pid>/fd/) et Spécification du journal Ext4.
  • ext4magic Documentation du projet (ext4magic.sourceforge.net): Forensic Inode et récupération de transactions de journal sur les systèmes de fichiers Ext3/Ext4.
  • Institut national des normes et de la technologie (NIST) (États-Unis) : Publication spéciale 800-190 : Application Container Security Guide & Incident Recovery.