Skip to content

נפח הפקה של Docker או Kubernetes נמחק: הצלה docker system prune --volumes, overlay2 אינודס, ו etcd תצלומים

מספרי חירום שונים לפי מדינה. דף זה משתמש ב-911, המספר של ארצות הברית וקנדה. מדינות רבות אחרות משתמשות ב-112, 999 או מספר אחר. מצא את המספר עבור המדינה שלך.

ריצה docker compose down -v, docker system prune -a --volumes, docker volume rm, או kubectl delete pvc בכרטיסיית הטרמינל הלא נכונה בייצור היא אחת הדרכים המהירות ביותר למחוק נפח מסד נתונים חי של PostgreSQL, MySQL, MariaDB, Redis, MongoDB או SQLite. בניגוד לצילומי מצב של מכונות וירטואליות בענן שעוברות לפח מיחזור של 7 ימים, מנהל התקן הנפח המקומי של Docker (/var/lib/docker/volumes/<name>/_data) ו-Kubernetes local-path / hostPath ספקי אספקה מנפיקים מיד את התקן POSIX unlink() ו rmdir() שיחות ישירות מול מערכת הקבצים המארח הבסיסית של לינוקס (ext4, XFS, או Btrfs). כל כתיבה שמתרחשת באותו מארח לינוקס לאחר סיום הפקודה יכולה לדרוס את בלוקי מסד הנתונים המשוחררים בדיסק. אם דיסק השרת שלך התמלא עד 100 אחוז (0 bytes free) לפני שמישהו רץ docker system prune --volumes בבהלה, התייעצו דיסק שרת מלא ב-100%, התנפחות יומן WAL של מסד הנתונים ושחזור שטח אפס; למחיקת קבצי Linux ממתכת חשופה מחוץ לקונטיינרים, ראה rm -rf בשוגג או Shift-Delete ב-ext4, XFS, APFS ו-NTFS: רכיבה מחדש לקריאה בלבד וגילוף אינוד ו מכונה וירטואלית VMDK, VHDX ו-qcow2 שחיתות שרשרת צילומי מצב והצלת hypervisor. אם הפסקת ייצור זו משפיעה על טיפול בחולים בבית החולים, על שיגור חירום או על מערכות בטיחות של שירותים ציבוריים, התקשר למספר החירום המקומי שלך (911 בארצות הברית ובקנדה, 112 ברחבי האיחוד האירופי, 999 בבריטניה) או עיין במדריך שלנו של מספרי חירום.

תעשה את זה עכשיו

  1. לא לרוץ docker compose up -d, systemctl restart docker, או לפרוס מחדש את הפוד של Kubernetes: יצירה מחדש של המיכל או הפעלה מחדש של הדמון Docker כותב מגה-בייט של חדש overlay2 מטא נתונים, יומני JSON של מיכל וקבצי מסד נתונים ריקים שזה עתה אתחולו (initdb) ישירות מעל המדויק ext4 או XFS חוסם היכן עוצמת הקול שנמחקה שלך ישבה לפני שניות.
  2. בדוק תוך 5 שניות אם תהליך המכולה (postgres, mysqld, redis-server, node, python) עדיין פועל בזיכרון (ps aux ו sudo lsof +L1): אם מישהו מחק קבצים בתוך אמצעי אחסון מותקן או ביטל קישור של אמצעי אחסון אנונימי בזמן שהמכולה עדיין פועל, ליבת לינוקס שומר 100 אחוז מקבצי מסד הנתונים הלא מקושרים בחיים בדיסק כל עוד מזהה התהליך המארח של המארח (PID) מכיל מתאר קובץ פתוח (FD). אתה יכול להעתיק את הקבצים האלה ישירות החוצה /proc/<PID>/fd/ או /proc/<PID>/root/ עם אפס אובדן נתונים לפני שהמכולה נעצרת.
  3. אם המכולה כבר נעצרה ועוצמת הקול נמחקה (docker compose down -v או docker system prune --volumes), הקפאת דיסק מארח כותב מיד: עצור את דמון ה-Docker (sudo systemctl stop docker.socket docker.service containerd) כך שמיכלי רקע ובדיקות בריאות מפסיקים לכתוב לתוכו יומנים /var/lib/docker, ואז או טען מחדש /var/lib/docker (או השורש / מחיצה) לקריאה בלבד (sudo mount -o remount,ro /) או צלם תמונת מצב מיידית של עוצמת הקול בענן ברמת הבלוק (AWS EBS Snapshot, GCP Persistent Disk Snapshot, DigitalOcean Volume Snapshot) לפני שנוגעים במשהו.
  4. אם אתה ב-Kubernetes (kubectl delete pvc או kubectl delete namespace), בדוק את ה-PeristentVolume (PV) ReclaimPolicy (kubectl get pv) מיד:
  5. אם ה PV היה persistentVolumeReclaimPolicy: Retain, הנתונים שלך לא נמחקו: ה PV פשוט עבר ל Released סטטוס ודיסק הענן שלך (EBS, Azure Disk, Ceph RBD, NFS) הוא 100 אחוז שלם.
  6. גם אם kubectl delete pvc תקוע בTerminating, Kubernetes מסיימים (kubernetes.io/pvc-protection) חוסם את מנהל ההתקן של ה-CSI ממחיקת האחסון הבסיסי כל עוד כל Pod עדיין מפנה לאותו PVC. אל תמחק את הפוד עד שתעתיק את הנתונים מה-Pod הפועל.
  7. תמונה את מחיצת הבלוק הבסיסית (dd / ddrescue מעל SSH) לדיסק חיצוני או אמצעי אחסון נפרד בענן לפני ההפעלה ext4magic, extundelete, או PhotoRec: לעולם אל תפעיל חוצבי קבצים שכותבים קבצי פלט על אותה מחיצת דיסק שממנה אתה מתאושש /var/lib/docker/volumes.
  8. עבור מצב אשכול Kubernetes פגום או שנמחק בטעות (kubectl delete crd / namespace), לעצור kube-apiserver ולשחזר את הגרסה האחרונה שלך etcd תמונת מצב (etcdctl snapshot restore): אם האשכול מופיע ב etcd נמחק בזמן שנפחי האחסון הבסיסיים בענן עדיין קיימים, ומשחזר etcd משחזר הכל PV, PVC, Secret, ו ConfigMap חפצים בו זמנית.

Danger

לעולם אל תסיר את kubernetes.io/pvc-protection או kubernetes.io/pv-protection מסיים עם kubectl patch ... -p '{"metadata":{"finalizers":null}}' כאשר PVC תקוע פנימה Terminating: הגמר הזה הוא הדבר היחיד ששומר על מנהל התקן CSI בענן (aws-ebs-csi-driver, pd.csi.storage.gke.io, Longhorn, Rook-Ceph) מהנפקת חומרה DeleteVolume קריאת API להרוס את דיסק הייצור שלך. בעוד ה-PVC תקוע פנימה Terminating, הפוד עדיין פועל ועוצמת הקול עדיין מותקנת: הפעל kubectl exec או kubectl cp (או pg_dump / mysqldump) מיד כדי להציל 100 אחוז ממסד הנתונים שלך לפני שה-Pod יסתיים.


עץ ההחלטות: נמחק כרך Docker, overlay2 שכבה, או משולש PVC של Kubernetes

השתמש בתרשים זרימה זה כדי לבחור את הנתיב המהיר ביותר לשחזור אפס אובדן בהתבסס על אם תהליך המכולה עדיין חי, אם אמצעי האחסון היה מגובה על ידי דיסק מקומי או אחסון CSI בענן, ואיזו מערכת קבצים מארח /var/lib/docker:

flowchart TD
    Start["נתוני הפקה חסרים לאחר פקודת המחיקה של Docker או Kubernetes"] --> WhichEnv{"איזו פלטפורמה ופיקוד גרמו להפסד?"}

    WhichEnv -->|"Docker: מיכל עדיין פועל (קבצים לא מקושרים בתוך אמצעי אחסון/מיכל)"| ProcRescue["הצלת מתארי קבצים לא מקושרים באמצעות sudo lsof +L1 ו-/proc/PID/fd/N או /proc/PID/root/"]

    WhichEnv -->|"Docker: Container Stop & Volume Deleted (compose down -v / prune --volumes)"| StopDocker["הפעל מיד: sudo systemctl stop docker.socket docker containerd"]

    WhichEnv -->|"Kubernetes: kubectl מחק pvc / pv / statefulset / מרחב שמות"| K8sCheck{"האם הפוד עדיין פועל או ש-PVC תקוע בסיומה?"}

    K8sCheck -->|"כן: הפוד עדיין פועל (הגמר חוסם מחיקת CSI)"| K8sExec["אל תמחק Pod -> הפעל את kubectl exec / pg_dump / tar על stdout לדיסק המקומי באופן מיידי"]
    K8sCheck -->|"לא: Pod Gone -> בדוק kubectl get pv"| ReclaimCheck{"מה הייתה מדיניות PV Reclaim?"}

    ReclaimCheck -->|"שמור (סטטוס PV = פורסם)"| ClearClaimRef["100% נתונים שלמים -> ערוך PV כדי להסיר spec.claimRef.uid -> התחבר מחדש ל-PVC חדש"]
    ReclaimCheck -->|"מחק (ענן EBS / PD / Longhorn / Local-Path)"| CloudOrLocal{"נפח CSI בענן או דיסק מארח מקומי?"}

    CloudOrLocal -->|"Cloud CSI (AWS EBS / GCP / Azure / Ceph)"| CloudSnap["בדוק את סל המיחזור של קונסולת הענן / תמונות Snapshot אוטומטיות של EBS / אשפה של Ceph RBD (rbd trash ls)"]
    CloudOrLocal -->|"דיסק צומת מקומי (local-path / hostPath)"| StopDocker

    StopDocker --> RemountRO["התקן מחדש מחיצת מארח לקריאה בלבד (mount -o remount,ro) או הזרם תמונת בלוק על SSH"]
    RemountRO --> HostFS{"איזה מערכת קבצים מארח /var/lib/docer?"}
    HostFS -->|"ext4"| Ext4Rec["השתמש ב-debugfs / ext4magic Journal Inode Rollback Transaction (-חותמת זמן)"]
    HostFS -->|"XFS / Btrfs"| CarveRec["השתמש ב-Btrfs Roots / xfs_irecover / גילוף חתימות מותאם אישית עבור SQLite, Postgres Heap או InnoDB .ibd"]

שלב 1: כיצד Docker ו-Kubernetes למעשה מוחקים אמצעי אחסון בדיסק

לפני הפעלת פקודת שחזור כלשהי, הבן היכן הנתונים שלך חיים פיזית במארח לינוקס ובמה בעצם נגעה פקודת המחיקה:

סוג אחסון ופקודת מחיקה נתיב מערכת קבצים מארח ב- Linux Node מה בעצם עשתה פקודת המחיקה שיטת שחזור מיידית
בשם Docker Volume (docker volume rm או docker compose down -v) /var/lib/docker/volumes/<vol_name>/_data ביטל את הקישור של הקבצים בפנים _data/ והסיר את ערך הספרייה מ /var/lib/docker/volumes/metadata.db (boltdb). עצור את דוקר מיד, עלה מחדש /var/lib/docker לקריאה בלבד, ושחזור אינודות לא מקושרות באמצעות ext4magic / debugfs או גילוף חתימה.
** נפח דוקר אנונימי (docker run -v /var/lib/mysql + docker rm -v או docker system prune --volumes)** /var/lib/docker/volumes/<64-char-hex-id>/_data docker system prune --volumes מוחק כל כרך אנונימי ועם שם שאין לו הפניה כרגע על ידי מיכל קיים אחד לפחות. עצור את Docker מיד; אם היו לך מכולות אחרות עצורות שנפחן לא גזום, סמן את השאריות /var/lib/docker/volumes/*/_data תחילה תיקיות לפני גילוף בלוקים לא מוקצים.
** שכבה לכתיבה של מיכל (docker rm <container> כאשר הנתונים נכתבו מחוץ לנפח)** /var/lib/docker/overlay2/<layer-id>/diff/ ביטל את הקישור העליון של המכולה diff/ ספרייה בתוך overlay2 מנהל התקן אחסון. עצור את Docker מיד ושחזר את עץ הספריות הלא מקושר מה- ext4 יומן או XFS בלוקים.
Docker Desktop ב-macOS או Windows (docker system prune --volumes) בתוך תמונת דיסק של מכונה וירטואלית אחת: -/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw (macOS) או %LocalAppData%\Docker\wsl\disk\docker_data.vhdx (Windows WSL2). נשלח unlink() בתוך ה-Linux VM, ואם discard/TRIM פעיל ב Docker.raw / docker_data.vhdx, נקבו חורים דלילים בקובץ המארח. צא מ-Docker Desktop תוך 5 שניות, העתק Docker.raw או docker_data.vhdx לכונן חיצוני, ולהפעיל ext4magic / PhotoRec כנגד תמונת הדיסק הוירטואלית.
Kubernetes PVC עם Delete ReclaimPolicy על Ceph RBD (Rook-Ceph) או לונגהורן Ceph OSD בריכת (rbd) או /var/lib/longhorn/replicas/. אם csi-rbdplugin יש trash מופעל (rbd trash), תמונת RBD מועברת לפח האשפה של Ceph; אחרת בלוקים אינם ממופים. רוץ rbd trash ls --pool <pool> בתוך ה rook-ceph-tools תרמיל ולשחזר עם rbd trash restore.

שלב 2: הצלת קבצי מסד נתונים פתוחים ממיכל שעדיין פועל (/proc/<pid>/fd/)

רגע: האם המכולה עדיין פועלת עכשיו? לעתים קרובות, מהנדס מפעיל סקריפט העברת יישומים, עבודת cron ניקוי או מדריך rm -rf /var/lib/postgresql/data/* או rm /app/data/production.sqlite3 בתוך מיכל פועל, או מוחק את תיקיית ה-bind-mount המארח הבסיסית /opt/app/data בעוד המיכל עצמו (postgres, mysqld, mariadbd, redis-server, mongod, gunicorn, node) עדיין פועל.

בלינוקס, קובץ לא נמחק מהדיסק כאשר rm או unlink() נקרא. בלוקי הדיסק והאינוד שלו נשארים 100 אחוז הוקצו וקריא עד לתהליך האחרון המחזיק מתאר קובץ פתוח (FD) לאינוד זה סוגר אותו או יוצא.

שלב 1: מצא את מזהה התהליך המארח (PID) של תהליך המכולה

בצומת המארח של לינוקס (לא בתוך הקונטיינר), מצא את המארח PID של מסד הנתונים או תהליך הבקשה שלך:

sudo lsof +L1 | grep -E "postgres|mysqld|mariadbd|sqlite|redis|mongo|node|python|java"
תסתכל על הפלט:
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)
תסתכל בעמודה NLINK: כתוב 0, ושם הקובץ מסתיים ב-(deleted). הקובץ נעלם לחלוטין ls /var/lib/docker/volumes/..., ובכל זאת כל בייט בודד (482 MB ב users.ibd, 89 MB ב production.sqlite3) עדיין חי בפנים /proc/<PID>/fd/<FD>.

שלב 2: העתק את קבצי מסד הנתונים הלא מקושרים ישר החוצה /proc/<PID>/fd/

אל תפסיק או תפעיל מחדש את המיכל. בזמן שהתהליך עדיין פועל, העתק את מתארי הקובץ הגולמי ישירות לתיקיה בטוחה במארח שלך:

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

שלב 3: אפילו טוב יותר: הפעל dump לוגי חי (pg_dump / mysqldump / .backup) לפני שהמכל סוגר את ה-FDs

אם postgres או mysqld עדיין פועל עם קבצי הנתונים שלו פתוחים בזיכרון ו /proc/<PID>/fd/, נסה להריץ תחילה dump לוגי חי מעל שקע ה-Unix או חיבור 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
(הערה: PostgreSQL נפתח ונסגר .1, .2 לפלח קבצים על פני תהליכי עבודה באופן דינמי, כך pg_dump עלול להיכשל בטבלאות לא מאוחסנות במטמון; שילוב שאילתת SQL חיה עם העתקת כל פתיחה /proc/<pid>/fd/* על פני הכל postgres PIDs backend של ילדים שומר את נתוני ערימת הטבלה המקסימלית האפשרית.)


שלב 3: שחזור אמצעי אחסון של Docker שנמחק מופעל ext4 או XFS לאחר שהמיכל נעצר

מה אם אתה רץ docker compose down -v או docker system prune --volumes, אז המכולה כבר נעצרה והכל /proc/<pid>/fd/ המתארים סגורים? עכשיו אתה במרוץ נגד כתיבת דיסק ברקע על מארח לינוקס.

שלב 1: הקפיא את מערכת הקבצים המארח של לינוקס תוך 10 שניות

  1. עצור מיד את Docker, containerd, kubelet ו-cron כך שאף מיכל, בדיקת בריאות או מסובב יומנים לא כותב בית נוסף ל /var/lib/docker:
    sudo systemctl stop docker.socket docker.service containerd.service cron.service
    
  2. בדוק איזה מכשיר חסימה ומערכת קבצים מחזיקים /var/lib/docker:
    df -Th /var/lib/docker
    
    Filesystem     Type  Size  Used Avail Use% Mounted on
    /dev/nvme0n1p1 ext4  100G   42G   58G  42% /
    
  3. התקן מחדש את המחיצה לקריאה בלבד (או הזרמת תמונת מחיצה גולמית על גבי SSH למחשב אחר):
  4. אם /var/lib/docker נמצא על מחיצה ייעודית משלו או אמצעי אחסון LVM (לדוגמה /dev/nvme0n1p2 או /dev/mapper/vg0-docker), התקן אותו מיד לקריאה בלבד:
    sudo mount -o remount,ro /var/lib/docker
    
  5. אם /var/lib/docker נמצא על השורש / מחיצה (/), נסה לאלץ את מחיצת השורש לקריאה בלבד באמצעות הטריגר של הליבה Magic SysRq (echo u | sudo tee /proc/sysrq-trigger) או sudo mount -o remount,ro /.
  6. אם אתה נמצא ב-VPS בענן (AWS EC2, GCP, DigitalOcean, Hetzner, Linode): עבור מייד לקונסולת האינטרנט בענן שלך ולחץ על צור תמונת מצב בנפח החסימה של השרת (או הזרם את התקן החסימה הגולמית דרך SSH לשרת שני: sudo dd if=/dev/nvme0n1p1 bs=4M status=progress | gzip -1 | ssh user@backup-server "cat > /mnt/storage/docker_host_raw.img.gz").

שלב 2: בדוק אם הנתונים שלך עדיין נמצאים בנפח אחר לא גזום או overlay2 שכבה

לפני גילוף בלוקים של דיסקים לא מוקצים, ודא שמסד הנתונים שלך לא היה מאוחסן בפועל ב-bind mount או באמצעי אחסון בעל שם אחר ששרד:

# 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
מדי שבוע, מנהלי מערכת נכנסים לפאניקה לאחר ריצה docker volume rm app_db_data, רק כדי לגלות עם find /var/lib/docker זאת docker-compose.yml יצר למעשה projectname_app_db_data (שעדיין שלם ב-100 אחוז בדיסק) בעוד app_db_data היה כרך ישן שאינו בשימוש מלפני שישה חודשים.

שלב 3: שחזור ספריות אמצעי אחסון לא מקושרות של Docker ext4 באמצעות ext4 יומן (ext4magic ו debugfs)

מתי docker volume rm מוחק /var/lib/docker/volumes/<vol_name>/_data על א ext4 מערכת קבצים, ext4 מאפס את מצביעי הבלוק הישירים (i_block / שורש עץ במידה) בטבלת האינדה החיה. עם זאת, הext4 יומן (inode <8>, בדרך כלל 128 MB ל 1024 MB חיץ טבעות מעגלי) עדיין מחזיק עותקים היסטוריים של טבלאות האינוד המדויקות ובלוקי הספריות ממש לפני docker compose down -v הוצא להורג.

+-------------------------------------------------------------------------+
| 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.        |
+-------------------------------------------------------------------------+

רוץ ext4magic כנגד המחיצה לקריאה בלבד (או ה .img עותק תמונת מצב בשרת שני), תוך ציון חותמת זמן (-a) מ5 דקות לפני רצתם docker compose down -v או 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: קורא את תמונת היומן ששמרת ב-RAM מיד לאחר הפסקת Docker. - -f var/lib/docker/volumes: ממקד לעץ ספריות הכרכים המדויק של Docker (הערה: השמט את הקוד המוביל / ב ext4magic נתיבים יחסיים). - -a $(date -d "-15 minutes" +%s): מספר ext4magic לשחזר את עץ הספריות באמצעות עותקי inode שתקפו לפני 15 דקות (ממש לפני המחיקה בשוגג). - -r: משחזר ספריות שלמות שבהן לא הוחלפו בלוקים; אם -r מפספס קבצים שהוחלפו חלקית, הפעל מעבר שני להחליף -r עם -m (גילוף קסם + מצב היברידי יומן).

שלב 4: גילוף קבצי SQLite, PostgreSQL או MySQL InnoDB גולמיים כאשר היומן עטוף (XFS או ext4)

Warning

למה XFS אינו תומך ext4magic ודורש ביטול קריאה בלבד מיידית: לא דומה ext4, שכותבת עותקי אינוד מלאים של 256 בתים ביומן שלו, XFS רושם דלתות של כוונת מטא נתונים ומשתמש חוזר באגרסיביות בעצי האינוד המשוחררים (agi). אם /var/lib/docker יושב על א XFS מחיצה (ברירת מחדל ב-RHEL, Rocky Linux, AlmaLinux ואמזון לינוקס), ביטול הרכבה /var/lib/docker או עלייה מחדש / קריאה בלבד תוך שניות הוא השלב החשוב ביותר לפני הגילוף.

אם המארח משתמש בXFS או אם ה ext4 יומן כבר עטוף על מצביעי האינודה, השתמש בחתימה ובגילוף מבנה כנגד תמונת הדיסק הגולמית (docker_host_raw.img):

  1. עבור מסדי נתונים של SQLite3 (.sqlite, .db - למשל, Vaultwarden, Nextcloud, Home Assistant, Gitea, Grafana): כל מסד נתונים של SQLite3 מתחיל עם כותרת ASCII של 16 בתים שאין לטעות בה בבתים 0 של הדף הראשון של 4 קילובייט: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 ("SQLite format 3\0"), ומאחסן את גודל עמוד מסד הנתונים המדויק (Bytes 16..17, בדרך כלל 4096) וגודל מסד הנתונים הכולל בדפים (Bytes 28..31, מספר שלם של 32 סיביות גדול) ממש בתוך אותה כותרת.
  2. רוץ PhotoRec עם [File Opt] -> [x] sqlite מופעלת, או סרוק את המחיצה ישירות באמצעות grep -ab "SQLite format 3" כדי למצוא את היסט הבתים המדויק של קובץ SQLite שנמחק ולחלץ אותו באמצעותו dd:
    # Find the exact byte offsets of every "SQLite format 3" header on the partition:
    sudo grep -ab "SQLite format 3" /dev/nvme0n1p1
    
    לאחר החילוץ, הרץ sqlite3 carved.db ".recover" | sqlite3 repaired.db לשחזר כל דף עלה עץ B שלם.

Tip

איך לחשב את המדויק dd גודל בתים של קובץ SQLite3 לא מקושר מהכותרת שלו: פעם אחת grep -ab "SQLite format 3" נותן לך את היסט הבתים ההתחלתי OFFSET של מסד הנתונים של SQLite שנמחק, קרא בתים 16..17 (גודל עמוד uint16 big-endian, למשל, 0x1000 = 4096 בתים) ובייטים 28..31 (Uint32 big-endian Page Count, למשל, 25000 דפים) באמצעות hexdump -C -s OFFSET -n 32. הכפלה Page Size x Page Count נותן לך את אורך הבתים המדויק לעבור אליו dd (iflag=skip_bytes,count_bytes) כאשר הקובץ רציף בדיסק.

  1. עבור MySQL / MariaDB InnoDB (.ibd קבצי טבלה): כל InnoDB .ibd הטבלה מורכבת מרצף 16 KB (16,384 byte) דפים המכילים את FIL_PAGE_INDEX (0x45BF) הכותרת והטבלה הייחודית space_id. השתמש ב-Percona / TwinDB undrop-for-innodb (stream_parser + c_parser) ערכת כלים לסריקה /dev/nvme0n1p1 עבור כולם 16 KB אינדקס דפי InnoDB ותשליך כל שורה ישירות לקבצי TSV/SQL לייבוא מחדש.
  2. עבור קבצי PostgreSQL Heap ($PGDATA/base/<db_oid>/<relfilenode>): PostgreSQL מאחסן כל שולחן כרצף 8 KB (8,192 byte) ערימת דפים המכילים PageHeaderData (pd_lower, pd_upper, pd_special). השתמש בpg_filedump או pglazarus / pdu לסריקת אזורי דיסק לא מוקצים עבורם 8 KB דפים התואמים את פריסת העמודות של הטבלה שלך (HeapTupleHeaderData) ובנה מחדש את השורות.

שלב 4: Kubernetes PVC, PV, ו etcd שחזור חירום של תמונת מצב

ב-Kubernetes (EKS, GKE, AKS, k3s, RKE2, kubeadm, OpenShift), מחיקת בטעות PersistentVolumeClaim (kubectl delete pvc), StatefulSet או מרחב שמות שלם (kubectl delete ns prod) עוקב אחר ארכיטקטורה שונה מאוד מזו של Docker העצמאי.

תרחיש א': ה-PVC מראה Terminating (מציל הגמר)

הרץ:

kubectl get pvc -n <namespace>
אם ה STATUS בעמודה כתוב Terminating, נשמו לרווחה: הנתונים שלך עדיין לא נמחקו. - מַדוּעַ? כל PVC של Kubernetes שנוצר מאז Kubernetes 1.9 כולל אוטומטית finalizers: [kubernetes.io/pvc-protection]. - כל עוד Pod עדיין מתקין את ה-PVC הזה, בקר Kubernetes מסרב להשלים את מחיקת ה-PVC ולעולם לא קורא לדרייבר ה-CSI DeleteVolume RPC. - פעולה מיידית: האם לא מחק או הפעל מחדש את הפוד, ועשה לא מתקן את הגמר. העתק מיד את כל הנתונים מה-Pod הפועל למחשב המקומי שלך או לדלי 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

תרחיש ב': ה-PVC נמחק, ו kubectl get pv מציג את ה-PeristentVolume ב Released מדינה (ReclaimPolicy: Retain)

הרץ:

kubectl get pv
אם הנפח המתמשך שלך (pv-prod-postgres) עדיין מופיע עם STATUS: Released (בגלל שהשימוש ב- StorageClass שלו reclaimPolicy: Retain), 100 אחוז מהנתונים שלך עדיין לא נגועים בדיסק הבסיסי. עם זאת, Kubernetes מסרב לתת ל-PVC חדש להיקשר ל-a Released PV כי ה-PV עדיין מכיל א spec.claimRef מצביע על ה-PVC הישנים שנמחקו UID.

איך מכינים א Released PV Available שוב תוך 10 שניות עם אפס אובדן נתונים: 1. ערוך את האובייקט PersistentVolume ומחק את ה- spec.claimRef חסום:

kubectl patch pv <your-pv-name> --type json -p '[{"op": "remove", "path": "/spec/claimRef"}]'
2. רוץ kubectl get pv שוב: הסטטוס משתנה מיד מReleased עד Available. 3. צור מחדש את שלך PersistentVolumeClaim (מפרט volumeName: <your-pv-name> והתאמה של קיבולת/storageClassName). זה ייקשר ל-PV הקיים באופן מיידי עם כל הקבצים שלמים.

תרחיש C: שחזור מצב אשכול Kubernetes שנמחק מ-an etcd תמונת מצב (etcdctl snapshot restore)

מה אם מישהו רץ kubectl delete namespace prod או helm uninstall ומחק 200 מניפסטים Kubernetes, סודות, ConfigMaps והגדרות PV בניהול עצמי kubeadm, k3s, או RKE2 מטוס שליטה?

  1. אתר את האחרון שלך etcd תמונת מצב (כברירת מחדל ב /var/lib/rancher/k3s/server/db/snapshots/, /var/lib/rancher/rke2/server/db/snapshots/, או המתוכנן שלך /var/backups/etcd/snapshot.db).
  2. אמת את תקינות תמונת המצב לפני נגיעה באשכול החי:
    ETCDCTL_API=3 etcdctl snapshot status /path/to/snapshot.db --write-out=table
    
  3. עצור kube-apiserver ו etcd בצמתים במישור הבקרה:
  4. ב-kubeadm (תרמילים סטטיים): הזז /etc/kubernetes/manifests/kube-apiserver.yaml ו /etc/kubernetes/manifests/etcd.yaml זמנית ל /root/manifests_hold/ כך kubelet עוצר את שני המיכלים בצורה נקייה, ואז מגבה /var/lib/etcd ל /var/lib/etcd.bak.
  5. ב-k3s: רוץ sudo systemctl stop k3s ו sudo k3s server --cluster-reset --cluster-reset-restore-path=/path/to/snapshot.
  6. שחזר את etcd ספריית הנתונים פועלת 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. זז etcd.yaml ו kube-apiserver.yaml חזרה לתוך /etc/kubernetes/manifests/. תוך 30 שניות, kube-apiserver מתחבר מחדש למשוחזר etcd store וכל אובייקט Namespace, Secret, ConfigMap ו-PersistentVolume שנמחק מופיעים שוב.

שלב 5: הקשחת נפחי Docker ו-Kubernetes מפני מחיקה בשוגג

לאחר שחזור מסד הנתונים של הייצור שלך, יישם את ארבעת מעקות הבטיחות הארכיטקטוניים האלה כך ששגיאת הקלדה אחת של CLI לא תוכל למחוק שוב כרך חי:

  • שנה כל ייצור Kubernetes StorageClass מ reclaimPolicy: Delete ל reclaimPolicy: Retain: כברירת מחדל, StorageClasses מובנות בענן (gp2, gp3, standard-rwo) ברירת מחדל ל reclaimPolicy: Delete, כלומר מחיקת PVC הורסת את דיסק הענן. צור א StorageClass עם reclaimPolicy: Retain (או תיקון PVs קיימים עם kubectl patch pv <pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}') כך שמחיקת PVC או מרחב שמות לעולם לא מוחקת את נפח הבלוק הבסיסי.
  • הפעל את סל המיחזור של AWS EBS / לוחות זמנים של תמונת מצב של GCP / Velero עם צילומי CSI: הפעלת סל המיחזור של AWS EBS שומרת על כל אמצעי אחסון EBS שנמחק למשך 7 עד 30 ימים גם אם מנהל ההתקן של CSI מתקשר DeleteVolume.
  • לעולם אל תשתמש docker system prune --volumes בסקריפטים אוטומטיים של ניקוי או ברצי CI/CD: אם מיכל מסד נתונים ייצור קורס לזמן קצר (Exited (1)) ברגע המדויק של עבודת cron פועלת docker system prune -a --volumes -f, Docker מחשיב את הכרכים האנונימיים שלה "לא בשימוש" ומוחק אותם לצמיתות. רצועה --volumes מכל תסריטי הניקוי.
  • השתמש ברכיבי חיבור מארח מפורשים (/srv/prod_data/postgres:/var/lib/postgresql/data) או מסדי נתונים מנוהלים חיצוניים לעומסי עבודה של ייצור סטטיסטיים: לא דומה /var/lib/docker/volumes/, מארח ספריות חיבור לחיבור בחוץ /var/lib/docker/ מעולם לא נגעו בהם docker compose down -v, docker volume rm, או docker system prune --volumes.

מספרי חירום אזוריים ופרוטוקולי סוכנות

כאשר מחיקת מיכל או אחסון Kubernetes משפיעה על הפעילות הקלינית של בית החולים, על שליחת בטיחות הציבור או על נתונים אישיים מוסדרים, הסלמה מיד:

  • ארצות הברית וקנדה: חייגו 911 אם כשל באשכול מיכל משבית ניטור מטופל קליני, מערכות EHR או שיגור חירום. דווח על מחיקת תשתית מכולה זדונית או תקריות סייבר ל-CISA (1-844-Say-CISA / cisa.gov/report) או המרכז הקנדי לאבטחת סייבר (1-833-CYBER-88).
  • בריטניה: חייגו 999 לאיומי חיים או תשתית NHS קריטית. תחת ה-GDPR של בריטניה, הרס קבוע או אובדן זמינות של נתונים אישיים ללא גיבוי הניתן לשחזור מחייב הערכה של הודעת הפרה של 72 שעות ל-ICO (0303 123 1113).
  • האיחוד האירופי: חייגו 112 בכל המדינות החברות באיחוד האירופי. ישויות תחת הדירקטיבה NIS2 חייבות להגיש אזהרה מוקדמת ל-CSIRT הלאומי שלהם בתוך 24 שעות מהפסקת שירות חמורה, ואובדן נתונים אישיים לצמיתות גורם לדיווח של GDPR סעיף 33 תוך 72 שעות.
  • אוסטרליה וניו זילנד: חייגו 000 באוסטרליה או 111 בניו זילנד; דווח על תקריות תשתית קריטיות ל-ACSC (1300 CYBER1).
  • הודו ואסיה-פסיפיק: חייגו 112 בהודו לתגובת חירום; דווח על אירועי אבטחה בענן או מיכל ל-CERT-In (incident@cert-in.org.in) בתוך חלון החובה של 6 שעות.

שאלות נפוצות

עושה docker compose down -v מחק מארח חיבור mounts (./data:/var/lib/mysql) או רק כרכים Named and Anonymous Docker?

`docker compose down -v` מוחק רק כרכים בעלי שם שהוצהר ב- `volumes:` סעיף של `docker-compose.yml` וכרכים אנונימיים המצורפים למכולות; זה לעולם לא מוחק קבצים בתוך חיבור מארח (כגון `- /opt/mysql_data:/var/lib/mysql` או `- ./postgres_data:/var/lib/postgresql/data`). אם קובץ הכתיבה שלך השתמש בנתיב מארח שמתחיל ב `/` או `./`, בדוק את התיקיה במארח עכשיו: הקבצים שלך עדיין שלמים ב-100 אחוז.

למה עשה docker system prune --volumes למחוק את נפח מסד הנתונים שלי כאשר עצרתי את המיכל רק ל-2 דקות כדי לעדכן משתנה סביבה?

המתן בזהירות להבחנה בין `docker stop` ו `docker rm`: אם מיכל הוא רק `Stopped / Exited` (נראה ב `docker ps -a`), `docker system prune --volumes` עושה לא מחק את אמצעי האחסון שלו מכיוון שהמכל שנעצר עדיין מפנה אליהם. עם זאת, אם רצתם `docker rm ` (כדי ליצור מחדש את המכולה עם דגלים חדשים) או אם עברת `docker system prune -a --volumes` (אשר מוחק תחילה את כל המכולות שהופסקו ו לאחר מכן מוחק את כל הכרכים שכבר לא מחוברים לאף מיכל), הנפח הפך ל"מתנדנד" באלפית השנייה שבה הוסר המיכל שנעצר ונמחק מיד לאחר מכן.

האם אוכל לשחזר נפח Docker שנמחק בתוך Docker Desktop ב-Mac (Apple Silicon / Intel) או Windows (WSL2)?

כן, אם תעזוב את Docker Desktop מיד כדי שהמכונה הוירטואלית תפסיק לפעול `fstrim` כנגד הדיסק הוירטואלי. ב-macOS, Docker מאחסן את כל אמצעי האחסון של לינוקס בפנים `-/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw`; ב-Windows WSL2, בפנים `%LocalAppData%\Docker\wsl\disk\docker_data.vhdx`. תעתיק את זה `.raw` או `.vhdx` קובץ ל-SSD חיצוני מיד, צרף אותו לקריאה בלבד בלינוקס (באמצעות `losetup -Pr` עבור `.raw` או `qemu-nbd -r` עבור `.vhdx`), ורוץ `ext4magic` או `PhotoRec` נגד הוירטואלי `ext4` מחיצה בפנים.

מה אם מחקתי Kubernetes StatefulSet עם kubectl delete statefulset postgres? זה מחק גם את ה-PVC שלי?

לא. כברירת מחדל ב-Kubernetes (אלא אם כן `persistentVolumeClaimRetentionPolicy.whenDeleted: Delete` הוגדר במפורש ב-Kubernetes 1.27+), פועל `kubectl delete statefulset` מוחק את בקר ה-StatefulSet וה-Pods שלו, עוזב את הכל `PersistentVolumeClaims` (`data-postgres-0`, `data-postgres-1`) והנתונים הבסיסיים שלהם 100 אחוז שלמים. פשוט החל מחדש את שלך `StatefulSet` מניפסט YAML עם אותו שם ו `volumeClaimTemplates`, וה-Pods החדשים יתחברו אוטומטית מחדש לקיים `data-postgres-0` PVCs.

כיצד אוכל לגשת לקבצים בתוך Docker overlay2 ספרייה כאשר המיכל מסרב להתחיל (CrashLoopBackOff / Exited (1))?

אל תמחק את המכולה שהתרסקה. כל עוד המיכל שנעצר עדיין קיים ב `docker ps -a`, השכבה הניתנת לכתיבה ורכיבי הנפח שלו שלמים לחלוטין בדיסק. אתה יכול להעתיק קבצים ישירות מתוך המכולה שהופסקה באמצעות `docker cp :/var/lib/postgresql/data /root/rescued_data`, או מצא את המארח המדויק שלו `overlay2` נתיב בריצה `docker inspect --format '{{.GraphDriver.Data.UpperDir}}'` וקורא את הספרייה הזו ישירות כמו `root`.

מה אם מישהו מחק Kubernetes Namespace (kubectl delete ns prod) ולכל PVC היה reclaimPolicy: Delete ב-AWS EBS או GCP?

אם מנהל התקן CSI בענן (`ebs.csi.aws.com` או `pd.csi.storage.gke.io`) כבר בוצע `DeleteVolume` כי `reclaimPolicy` היה `Delete`, בדוק מיד שלוש רשתות ביטחון ברמת הענן: (1) סמן את **סל המיחזור AWS עבור נפחי EBS** בקונסולת AWS EC2 (אם כלל שמירה היה פעיל בחשבון/תגיות, אמצעי האחסון של EBS שנמחק יושב בסל המיחזור וניתן לשחזר אותו בלחיצה אחת); (2) בדוק את **AWS Backup / DLM / GCP Snapshot Schedules** עבור תמונת המצב האוטומטית האחרונה של עוצמת הקול; ו (3) בדוק אם מסד הנתונים שלך הזרם WAL/binlogs (`WAL-G`, `pgBackRest`, `Litestream`) לדלי S3/GCS.


מדריכים קשורים


מקורות והדרכה רשמית

  • תיעוד רשמי של Kubernetes (kubernetes.io / Cloud Native Computing Foundation): הגנה על אובייקט אחסון בשימוש (kubernetes.io/pvc-protection מסיימים), Reclaiming PersistentVolumes (Retain לעומת Delete), והפעלה etcd אשכולות עבור Kubernetes (etcdctl snapshot restore).
  • Docker Inc. (docs.docker.com): נהל נתונים ב-Docker: נפחים, חיבורי חיבור, overlay2 ארכיטקטורת מנהלי התקן לאחסון, והפניה לגזם.
  • ארגון ליבת לינוקס (kernel.org): ה /proc מערכת קבצים (procfs פתח את שחזור מתאר קבצים באמצעות /proc/<pid>/fd/) ומפרט יומן Ext4.
  • ext4magic תיעוד הפרויקט (ext4magic.sourceforge.net): שחזור עסקאות אינודות ויומן משפטי במערכות קבצים Ext3/Ext4.
  • המכון הלאומי לתקנים וטכנולוגיה (NIST) (ארצות הברית): פרסום מיוחד 800-190: Application Container Security Guide & Incident Recovery.