«rm -rf /» — історії: команда, що стала жанром IT-жахів

Було корисно?

У кожної опс-команди є своя страшилка. Не типу «серверна кімната переселена духами» — це здебільшого про погану вентиляцію та незачинені стійки.
Я маю на увазі історію, яка починається з мирного вікна змін і закінчується консоллю, що дивиться на тебе, як порожній холодильник.

rm -rf / — звісно, бука, але справжній лиходій завжди один: людська впевненість, застосована до невизначеної системи.
Ось як ця команда перетворилася на жанр, що насправді ламається, коли її запускають (або ледь не запускають), і що вам робити, щоб ваше ім’я ніколи не стало частиною чиєїсь фольклорної історії.

Що насправді означає rm -rf / (і чому це гірше, ніж здається)

На папері rm видаляє записи каталогу. На живій системі фактично воно видаляє шляхи, потрібні вашій ОС, щоб залишатися ОС.
Прапорці — те, що робить це легендою:

  • -r (рекурсивно): проходить дерево і видаляє все, до чого може дістатися.
  • -f (force): без запитань; пригнічує багато помилок; продовжує роботу.
  • /: починає з кореневого каталогу, вершини майже всього, що вам важливо.

«Майже» тут має велике значення. Linux — це не один великий купа файлів. Це купа монтувань: коренева файлова система, окремий /boot,
/var, /home, епhemeral /run, мережеві монтування, bind-монти, overlay-монти контейнерів і все інше,
що ваша платформа налаштувала під час інциденту три роки тому.

rm -rf / намагається пройти цю топологію. Наскільки далеко воно дійде — залежить від меж монтувань, прав доступу, незмінних прапорців,
чи ви root, чи в контейнері, і чи дистрибутив має захисні обмеження. Але навіть «частково» — катастрофа: видалення достатньої частини /lib або /usr
може перетворити кожен запущений процес на приреченого туриста — живого деякий час, але нездатного підвантажити наступну бібліотеку, виконати бінарник або перезапустити сервіс, який ви намагалися полагодити.

Практичний спосіб думати про це: ви не «видаляєте ОС», ви видаляєте припущення, які дозволяють ОС самостійно зцілюватися.
Більшість продакшн-аутеджів не є драматичними вибухами. Це системи, що втрачають здатність відновлюватися після дрібних збоїв.

Жарт №1: Найшвидший спосіб вивчити відновлення після катастрофи — один раз набрати rm -rf /. Другий найшвидший — подивитися, як це робить ваш колега.

Є ще поворот: на сучасних системах команда, яку ви набрали, не завжди та, що виконається. Оболонкові псевдоніми, обгортки (хороші або погані)
та автоматика можуть змінювати семантику. Якщо ви в контейнері, / може бути файловою системою контейнера, а не хоста — якщо ви не примонтували хоста.
У Kubernetes можна видалити deployment і відновити його; видалити невірний PersistentVolumeClaim — і ви починаєте практикувати акцептацію.

Глибша загроза: видаляти «імена», поки процеси ще працюють

Unix дозволяє процесу тримати файл відкритим навіть після того, як він був unlink-нутий. Це фіча — поки не перестає бути такою.
Коли ви видаляєте лог-файл під працюючим процесом, використання диска може не впасти, бо inode все ще зайнятий. Коли ви видаляєте спільні бібліотеки під сервісом,
сервіс може продовжувати працювати, поки не відбудеться наступне перезавантаження, rolling deploy, креш або fork/exec. Ось чому деякі інциденти з rm -rf
виглядають «нормальними» кілька хвилин чи годин, а потім розсипаються у найгірший момент: при наступному рестарті, під час фейловеру або після перезавантаження вузла.

Як це стається в корпоративному житті

Більшість команд уявляє інцидент «rm -rf /» як нудьгуючого адміністратора, що робить щось карикатурно безрозсудне. Реальність нудніша і небезпечніша:
це втомлений інженер, стислий дедлайн, копіпаст, продакшн-шелл, що виглядає як стаджинг, і команда, яка «завжди працювала раніше».

Жанр живе, бо це ідеальний шторм операційних антипатернів:

  • Неоднозначна мета: «Очистити диск» — це не завдання; це симптом.
  • Команди за звичкою: rm -rf стає рефлексом замість рішення.
  • Дрейф привілеїв: «тимчасово» дали sudo — і він лишився.
  • Плутанина середовищ: прод проти стаджингу відрізняються одним заголовком вкладки.
  • Автоматизація без гальм: команда була всередині скрипта, інструмента або джоба.

Я маю думку: якщо система вимагає, щоб люди регулярно видаляли файли під тиском, то системі бракує захисного шару. Люди не є захистом.
Люди — причина, через яку нам потрібні захисні шари.

Факти та історія: як ми опинилися тут

Ця команда не стала мемом випадково. Конкретна історія допомагає передбачити, як ваше середовище поводитиметься:

  1. Ранні Unix робили видалення навмисно простим. Філософія віддавала перевагу маленьким інструментам і композиційності; обмеження були культурними, а не технічними.
  2. rm видаляє записи каталогу, а не «безпечне стирання». Дані можуть зберігатися на диску до перезапису; тому інструменти відновлення іноді працюють.
  3. Захист кореневого каталогу еволюціонував з часом. GNU coreutils ввів за замовчуванням --preserve-root у багатьох дистрибутивах, щоб запобігти rm -rf /.
  4. BusyBox і вбудовані системи відрізняються. Деякі середовища мають менші або інші реалізації rm; припущення із серверів не завжди переносяться.
  5. Простори імен монтів змінили зону ураження. Контейнери та chroot можуть зробити «/» чимось іншим — поки ви не примонтуєте хост всередину.
  6. systemd підвищив залежність від /run та генерованого стану. Видалення під /run може миттєво ламати сервіси несподіваними способами.
  7. Файлові системи copy-on-write змінили математику відновлення. Снапшоти ZFS/Btrfs можуть зробити «ой» відновним — якщо снапшоти існують і збереження адекватне.
  8. Автоматизація опс перетворила одиничні помилки на події флоту. Поганий rm у запуску конфіг-менеджменту може швидко поширитися.

Помітно: кожна ера додає потужність, а потім додає нові способи масштабувати ті можливості. Ось чому жанр отримує нові продовження.

Режими відмов: що ламається першим, другим і дивно пізніше

1) Миттєве руйнування: зникають бінарі та бібліотеки

Видаліть досить /bin, /sbin, /usr/bin, /lib, /lib64 — і ви втрачаєте здатність запускати команди,
перезапускати демони або навіть автентифікуватися. SSH-сесії можуть лишатися, але нові входи можуть не пройти, якщо PAM-модулі чи оболонки відсутні.

2) Повільне руйнування: система працює… поки не потрібно exec

Запущені процеси можуть далі виконувати код, що вже завантажено в пам’ять. Ось чому перший графік може бути «усе зелене».
Потім відбувається reload сервісу. Новий воркер намагається стартувати. Хелсчек викликає рестарт. І раптом машина не може породити процес,
який би виправив сервіс.

3) Плутанина між data-plane і control-plane

У сучасних системах control-plane (орchestration, агенти, менеджери пакетів, конфігурація) — це те, що повертає data-plane.
rm -rf часто вбиває control-plane першим: бінарі агентів зникають, системні сервіси зупиняються, конфіги DNS зникають, сертифікати відсутні.
Тепер «переінсталювати пакет» перетворюється на «як запустити інсталятор?»

4) Біль зі зберігання: часткові видалення, неконсистентний стан додатка

Файлові системи не гарантують консистентність на рівні додатків. Якщо ви видалили частини каталогу бази даних, отримаєте гірше, ніж «вниз»:
«працює, але бреше». Деякі бази відмовляються стартувати, якщо файли відсутні (добре). Інші стартують і повертають часткові дані (погано).
На мережевому сховищі видалення можуть бути асинхронними або відкладеними через кешування.

5) Віртуалізація та нюанси контейнерів

На хості видалення / зазвичай фатальне. У контейнері це може бути відновлювана шарова операція — якщо контейнер не має привілейованих монтувань або не пише у томи.
Трагічніший патерн інцидентів у 2026 році — не «знищили файлову систему контейнера», а «знищили змонтований персистентний том, бо він здавався тимчасовим каталогом».

Цитата (парафраз): Усе ламається, і стійкість приходить від проєктування для відновлення, а не від віри, що можна запобігти всім помилкам. — Вернер Фогельс (парафраз)

Жарт №2: Єдина річ більш постійна, ніж хмарний ресурс — це команда delete, яку ви виконали з -f.

Швидкий план діагностики

Це порядок триажу, який я використовую, коли хтось каже «я думаю, я щось видалив» або «коробка поводиться, наче її переселили духи», а логи підозріло тихі.
Ви намагаєтеся швидко відповісти на три питання: (1) чи можна довіряти хосту, (2) що відсутнє, (3) відновлюємо через ремонт, відкат чи перебудову?

По-перше: підтвердьте межі та зупиніть кровотечу

  • Заморозьте автоматизацію: зупиніть запуск конфігураційних засобів, cron, CI/CD деплої та авто-виправлення, які можуть продовжувати видаляти або «виправляти» не те.
  • Збережіть сесію: тримайте наявний root-шелл живим; не виходьте. Рестарт часто — точка неповернення.
  • Визначте, хост чи контейнер: контейнер можна замінити; у хості може бути унікальна інформація.

По-друге: перевірте, чи система ще може виконувати базові інструменти

  • Чи можна запустити /bin/ls? Якщо ні — час на перебудову.
  • Чи цілий /lib для динамічного лінкування? Якщо спільні бібліотеки зникли, багато команд повернуть «No such file or directory», хоча бінарник існує.
  • Чи працює пакетний менеджер? Якщо так — можливо, можна перевстановити відсутні пакети.

По-третє: оберіть шлях відновлення залежно від важливості

  • Якщо дані цілі й ОС відтворювана: перебудуйте хост і підключіть томи даних.
  • Якщо ОС ціла, а відсутні обмежені файли: відновіть зі снапшоту/резервних копій або перевстановіть пакети, а потім перевірте цілісність.
  • Якщо цілісність даних під сумнівом: зупиніть сервіси, снапшотуйте пошкоджений стан (якщо можливо) і відновіть у чистому середовищі для валідації.

Швидкий пошукач вузьких місць (коли система «повільна» після промаху)

Іноді інцидент — це промах: видалення перервали, але система кульгає — блокування БД пакетів, сплеск дискового IO, відтворення журналу,
виснаження інодів або процес, що шалено сканує файлову систему. Ось найкоротший шлях до вузького місця:

  1. Насичення дискового IO? Перевірте iostat/pidstat та підказки про затримки файлової системи.
  2. Файлова система повна або закінчилися іноди? Перевірте df та df -i.
  3. Видалення ще виконується? Знайдіть процеси rm та обходи каталогів через lsof і ps.
  4. Плутанина з монтуваннями? Перевірте, що змонтовано де за допомогою findmnt.
  5. Спіраль логування або journald? Перевірте помилки в journalctl і використання диска.

Практичні завдання: команди, виводи та рішення (12+)

Це реальні команди, що можна виконати. Кожна містить, що означає вивід і яке рішення вона має підштовхнути.
Використовуйте їх від найменш руйнівних до найбільш інвазивних.

Завдання 1: Підтвердити, куди «/» фактично вказує (хост чи контейнер)

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

Значення: Якщо PID 1 — systemd на хості, ви побачите хостові слайси. У контейнерах часто видно docker/kubepods-шляхи.
Рішення: Якщо це контейнер, заміна може бути кращою за відновлення — хіба що вражені персистентні томи.

Завдання 2: Перевірити, що змонтовано і де могли перейти видалення

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

Значення: Видалення «/» могло зачепити /var та /mnt/data залежно від обходу та прав.
Рішення: Якщо критичні дані на окремих монтах, пріоритет — збереження та створення снапшотів цих монтувань перед будь-якими діями.

Завдання 3: Перевірити, чи видалення все ще виконується (зупиніть кровотечу)

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

Значення: Провина може ще обходити файлову систему.
Рішення: Якщо вона цілиться в неправильний шлях — зупиніть негайно (kill або ізолюйте хост). Якщо це потрібний шлях, подумайте про обмеження швидкості замість вбивства.

Завдання 4: Підтвердити, що коренева файлова система не заповнена або іноди не вичерпані

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

Значення: Ви на відстані одного встановлення пакета від відмови, і тимчасові файли не створюються надійно.
Рішення: Якщо для відновлення потрібно писати на диск (перевстановлення пакетів, відновлення файлів) — звільніть місце виважено і цілеспрямовано.

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

Значення: Виснаження інодів. Можна мати «вільні ГБ», але не створювати файли.
Рішення: Шукайте вибух дрібних файлів (кеші, тимчасові каталоги). Не запускайте «скрипти очищення», що можуть вийти за межі безпечного шляху.

Завдання 5: Швидко помітити відсутні ключові каталоги

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

Значення: Якщо каталоги відсутні цілком, система вже в поганому стані; якщо присутні — їх вміст може бути знищений.
Рішення: Якщо основні шляхи відсутні, схильні до перебудови і відновлення, а не до латання по частинах.

Завдання 6: Перевірити, чи динамічне лінкування пошкоджене

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

Значення: Бінарник існує, але потрібні спільні бібліотеки відсутні.
Рішення: Не марнуйте час на «почуйну» фіксацію одного сервісу. Якщо базові бібліотеки відсутні — потрібно перевстановлення пакетів з відомого джерела або перебудова.

Завдання 7: Визначити, який пакет володіє відсутнім файлом (приклад RPM)

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

Значення: Пакет, що має цей файл.
Рішення: Якщо пакетний менеджер працює і репозиторії доступні — перевстановіть набір пакетів для відсутніх бінарів, потім перевірте цілісність.

Завдання 8: Перевірити сигнали цілісності файлової системи (приклад ext4)

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

Значення: Можуть бути проблеми з індексами каталогів, inode-структурами або патологічною кількістю файлів.
Рішення: Якщо ядро попереджає про структури файлової системи — заплануйте офлайн fsck і готуйтеся до перебудови; не продовжуйте штурмувати диск.

Завдання 9: Виявити «видалені, але ще відкриті» файли, що споживають диск

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

Значення: Місце на диску не буде звільнене, поки процес не закриє файловий дескриптор.
Рішення: Обережно перезапустіть сервіс або надішліть сигнал, щоб він відкрив логи заново. Класична пастка: видалили логи, а диск все ще повний.

Завдання 10: Підтвердити, що змінилися нещодавно (скан mtime з обережністю)

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

Значення: Показує файли, змінені за останню годину — корисно для кореляції з поганим скриптом або деплоєм.
Рішення: Якщо основні конфіги змінилися несподівано — розглядайте це як потенційну помилку автоматики; відкотіть конфіг через GitOps або відновіть відомі робочі версії.

Завдання 11: Перевірити стан снапшотів ZFS перед «лікуванням»

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

Значення: Снапшоти існують. Це ваша страхувальна сітка, якщо ви не знищите її командами «очищення».
Рішення: Якщо підозрюється втрата даних — клонувати снапшот для розслідування замість відкату на місці.

Завдання 12: Відновити один каталог зі снапшоту ZFS (через клон + rsync)

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

Значення: Ви відновили лише потрібне, зберігаючи власника і hardlink-и.
Рішення: Віддавайте перевагу хірургічному відновленню замість повного відкату, коли важливий час роботи і ви не впевнені в межах видалення.

Завдання 13: Перелік снапшотів Btrfs і цілеспрямоване відновлення

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

Значення: Можна використовувати снапшоти як readonly-джерела для відновлення.
Рішення: Якщо нема снапшотів — припиніть сперечатися, що «нам вони не потрібні», і почніть закладати бюджет на них.

Завдання 14: Виявити небезпечні псевдоніми та опції оболонки, що приховують ризик

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

Значення: Інтерактивний запит може врятувати в інтерактивній оболонці — але не скрипти, cron або неінтерактивні сесії.
Рішення: Не покладайтеся на псевдоніми як на захист. Використовуйте межі прав, снапшоти та захисні обмеження в інструментах.

Завдання 15: Підтвердити налаштування GNU rm preserve-root

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

Значення: На цій системі rm за замовчуванням відмовляється видаляти /.
Рішення: Добре, але недостатньо: скрипти все ще можуть цілитися в критичні монти, і хтось може передати --no-preserve-root.

Завдання 16: Аудит підозрілого скрипта без його запуску

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

Значення: Статичний аналіз виявив класичну небезпеку розгортання.
Рішення: Якщо скрипт очищення може розгорнутися до /*, ставтеся до нього як до зарядженої зброї. Виправте, додайте обмеження і тести.

Три корпоративні міні-історії (анонімні, болісно правдоподібні)

Міні-історія 1: Аутедж через хибне припущення

Команда підтримувала флот хостів Linux, що запускали мікс спадкових сервісів і контейнеризованих робочих навантажень. Вони мали «стандартне розташування»:
дані застосунку жили в /srv/app, а ОС — на кореневому томі. Бігбук на чергуванні говорив: «Якщо диск заповнений, очистіть старі файли в /srv/app/tmp».

На новому образі хоста з’явився тихо новий хід. Там ще був /srv/app/tmp, але тепер це був симлінк на /var/tmp/app, щоб уніфікувати логування і тимчасові файли.
Цю зміну ніхто не задокументував, бо вона здавалася «внутрішнім рефакторингом», і сервіси не звертали уваги.

Однієї ночі використання диска перевищило поріг. На чергуванні підключилися, запустили звичну команду для очищення тимчасових файлів і помітили, що вона йде довше звичайного.
Додавши -f, інженер відійшов відповісти на інший пейдж. Видалення почало повільно обходити /var, а не вузький тимчасовий каталог,
і почало їсти не тільки кеш: обернені логи, runtime-стан і частини бази пакетів.

Сервіс не впав одразу. Він деградував. Потім вузол перезавантажився через розклад оновлення ядра, і справжня шкода проявилася:
системні сервіси не стартували, DNS зламався, і вузол не міг забрати образи контейнерів, бо сертифікати та CA-бандли були відсутні.
Оркестратор позначив його як нездоровий і переселив навантаження, що сховало інцидент, поки масштабна подія не вичерпала залишкові ресурси.

Постмортем не був про «не видаляти файли». Фікс був структурним: прибрати сюрпризи зі симлінками, зробити очищення тимчасових файлів операцією на рівні сервісу
і ставити питання «куди насправді вказує цей шлях?» як перший крок у рунебуках. Також: перестати ставити «стандартне розташування» як догму.
Стандартне розташування — це чутка, якщо ви її не валідуєте постійно.

Міні-історія 2: Оптимізація, що обернулася проти

Платформна команда захотіла швидших деплоїв. Вони додали крок очищення в пайплайн, щоб видаляти старі каталоги релізів:
/opt/app/releases/*, залишаючи останні три, видаляючи решту. Розумно. Потім хтось помітив, що очищення іноді займає хвилини на зайнятих хостах.
Він «оптимізував» це паралельним видаленням: знайти старі релізи і видаляти одночасно.

Оптимізація працювала в стаджингу. У продакшні вона створила новий режим відмов: релізи містили bind-монти для профілювання продуктивності та епhemeral-кеші.
Паралельні видалення викликали бурю файлових операцій, наситивши IO. Затримки зросли не тільки для додатка, а й для всього вузла.
Хелсчекі провалювалися. Сервіси перезапускалися. Рестарти виконувалися з частково видалених директорій.

Потім справжній трап: у одному деплої змінна, що вказувала на каталог релізів, була пуста, бо попередній крок впав.
Скрипт все одно запустився. Умова «якщо каталог існує» пройшла, бо скрипт впав до /opt/app.
Під паралельним видаленням він видалив набагато більше, ніж треба, включно із спільними бібліотеками, що постачалися з додатком.

Команда швидко відновилася деплоєм, але інцидент був дорогим у часі та довірі. Урок був нудний і непомітний:
не оптимізуйте руйнівні операції без вимірювання системних ефектів, і ніколи не дозволяйте шляхам видалення обчислюватися без жорсткої валідації.
Якщо вам потрібна швидкість — використовуйте снапшоти й атомарні переключення, а не швидше видалення.

Міні-історія 3: Нудна, але правильна практика, що врятувала день

Сервіс, суміжний з фінансами, зберігав критичні дані на ZFS dataset-ах з погодинними снапшотами, збереженими 72 години, і добовими — 30 днів.
Це не було розкішно. Це була політика: «Кожний dataset має снапшоти. Без винятків. Збереження контролюється. Відпрацювання відновлення — щоквартально».
Люди скаржилися, бо це займало місце і вимагало планування.

Під час вікна обслуговування інженер виконав команду очищення, призначену для стаджингового монту. Шлях здавався правильним, і автодоповнення табом «допомогло».
Це був продакшн-монт. Вони зрозуміли це за кілька хвилин, бо моніторинг був налаштований на файлову активність і сплески записів у dataset ZFS, а не тільки на CPU.

Вони зробили дві розумні речі негайно: спочатку зупинили сервіс, щоб уникнути записів у напіввидалений каталог. Потім створили новий снапшот пошкодженого dataset (так, снапшотуйте безлад),
щоб зберегти судово-розслідувальний стан. Після цього вони клонували останній чистий снапшот і відновили тільки відсутні підкаталоги.

Сервіс повернувся в робочий стан за розумний час, і їм не довелося відкотити весь dataset, уникнувши втрати даних за хвилини після снапшоту.
Постмортем теж був нудний: без героїчних вчинків, просто нагадування, що снапшоти — не «театральна дія резервного копіювання», якщо ви дійсно вмієте швидко відновлювати.
Відпрацювання відновлень означало, що нікому не довелося вигадувати команди під тиском.

Поширені помилки: симптом → корінна причина → виправлення

1) «Диск все ще повний після видалення логів»

Симптом: df -h показує відсутність вільного місця навіть після видалення великих файлів.

Корінна причина: Файли були видалені, але залишаються відкритими процесами (unlink-нуті inode-и).

Виправлення: Використайте lsof +L1 для пошуку винуватців; перезапустіть процес або надішліть сигнал, щоб він заново відкрив логи. Розгляньте logrotate з copytruncate тільки коли необхідно; віддавайте перевагу коректному reopen.

2) «Команди кажуть ‘No such file or directory’, але бінарник існує»

Симптом: Запуск /bin/ls повертає помилку, хоча ls присутній.

Корінна причина: Динамічний лоадер або спільні бібліотеки видалені (наприклад, /lib64/ld-linux-x86-64.so.2 або залежності).

Виправлення: Припиніть безцільні рестарти сервісів. Відновіть/перевстановіть відсутні основні бібліотеки через пакетний менеджер або перебудуйте образ. Якщо пакетний менеджер зламаний — використовуйте rescue-media або підключіть диск до іншого хоста.

3) «Система завантажується, але сервіси не стартують»

Симптом: Після перезавантаження багато unit-ів не стартують; journald скаржиться; мережа може бути зламаною.

Корінна причина: Часткове видалення під /etc, /usr, /var або відсутні unit-файли systemd і залежності.

Виправлення: Трактуйте це як відмову цілісності. Якщо є снапшоти — відновіть конфіги і unit-и; інакше перебудуйте і підключіть дані. Перевіряйте з rpm -Va на RPM-системах, якщо доступно.

4) «Kubernetes pod-и продовжують рестартувати після очищення»

Симптом: Pods у crashloop; вузли виглядають нормально; помилки додатка включають відсутні файли під монтуваними шляхами.

Корінна причина: Очищення цілиться в змонтований PersistentVolume, а не в шар контейнера.

Виправлення: Зупиніть джоб/pod, що видаляє. Відновіть PVC зі снапшоту/резервної копії сховища. Додайте admission controls і runAsNonRoot; видаліть hostPath-монти, якщо вони не критичні.

5) «Автоматизація видалила невірний каталог на багатьох хостах»

Симптом: Багато хостів одночасно деградують; відсутні ті самі шляхи.

Корінна причина: Конфіг менеджменту або CI job виконав руйнівне завдання з поганим розгортанням змінної або неправильним таргетингом інвентарю.

Виправлення: Заморозьте пайплайн. Відкотіть зміну. Додайте умови-захисти: вимагайте allowlist шляхів, відкидайте порожні змінні і запускайте руйнівні задачі тільки з ручним погодженням + dry-run.

6) «Скрипт очищення працював місяцями, а потім щось знищив»

Симптом: Давно існуючий скрипт раптово став руйнівним.

Корінна причина: Середовище змінилося: цілі симлінків, точки монтувань, bind-монти, зміни образу контейнера або шлях тепер вказує на іншу файлову систему.

Виправлення: Нехай скрипти перевіряють інваріанти: упевніться, що шлях на очікуваній файловій системі (findmnt), що він відповідає точному шаблону, що це не / або порожній, і що це не симлінк, якщо це явно не дозволено.

7) «Ми відновили з бекапу, але додаток неконсистентний»

Симптом: Додаток стартує, але дані пошкоджені або відсутні недавні записи.

Корінна причина: Відновлення файлового бекапу без консистентності на рівні додатка; WAL/транзакції не узгоджені.

Виправлення: Використовуйте бекапи з консистентністю додатка (вбудовані інструменти БД) або зупиняйте додаток перед снапшотом. Після відновлення запускайте перевірки цілісності і звіряйтеся з логами/репліками.

Чеклісти / покроковий план

Профілактичний чекліст: зробіть так, щоб «rm -rf /» була історією для інших команд

  1. Снапшоти для всього важливого. Якщо ви не можете знімати снапшоти — потрібен бекап з протестованим відновленням. Перевага обома підходами.
  2. Принцип найменших привілеїв за замовчуванням. Приберіть широкі sudo-права; використовуйте підвищення прав за потреби з аудитом.
  3. Зробіть небезпечні шляхи важкодоступними. Окремі монти для даних; розгляньте read-only root для аплайянсів; використовуйте immutable-прапорці за потреби.
  4. Захисти в скриптах: вимагайте ненульових змінних (${VAR:?}), забороняйте /, уникайте несподіваного глоббінгу, явно розв’язуйте симлінки.
  5. Культура dry-run: використовуйте find, щоб надрукувати кандидатів перед видаленням; зберігайте вивід у нотатках інциденту.
  6. Обсервабіліті для файл-чурну: налаштуйте алерти на незвичні темпи видалення на критичних датасетах, а не тільки CPU/пам’ять.
  7. Проводьте відпрацювання відновлення. Перший раз відновлювати не під час аутеджу.

Операційний чекліст: безпечне видалення під тиском

  1. Доведіть шлях. Використайте readlink -f і findmnt, щоб підтвердити межі монтувань і симлінки.
  2. Списувати, а не видаляти. Почніть з: «що саме буде видалено?»
  3. Краще перемістити в карантин. Перейменуйте каталог у карантин, коли можливо, а потім видаліть пізніше.
  4. Троттл і спостереження. Якщо видалення велике, воно може спричинити IO-аутедж. Розгляньте батчування в непіковий час.
  5. Зупиніть сервіси перед видаленням стану зберігання. Особливо бази даних і черги.
  6. Мати шлях відкату. Снапшот перед видаленням, якщо ФС підтримує; якщо ні — зробіть бекап цільового каталогу.

Чекліст інциденту: підозра на випадкове видалення

  1. Заморозьте автоматизацію (CI/CD, Ansible, cron cleanup jobs).
  2. Зберіть докази: поточні монти, запущені процеси, статистика диска/інодів, останні команди якщо доступні.
  3. Оцініть масштаб: тільки ОС проти монту даних; контейнер проти хоста; один вузол проти флоту.
  4. Оберіть стратегію відновлення: rebuild+reattach, відновлення зі снапшоту, перевстановлення пакетів або інструменти відновлення файлів.
  5. Підтвердіть: здоров’я сервісів, перевірки цілісності даних і валідацію залежностей.
  6. Постмортем: лагодьте захисні обмеження, а не людину.

Поширені запитання

1) Чи працює rm -rf / на сучасному Linux?

Часто ні, бо GNU rm зазвичай за замовчуванням має --preserve-root. Але не розслабляйтеся: люди можуть передати --no-preserve-root,
використовувати інші інструменти (find -delete, rsync --delete) або видаляти критичні монти під /, не цілуючи корінь.

2) Чому деякі системи продовжують працювати після великих видалень?

Бо запущені процеси вже завантажили код і мають відкриті файлові дескриптори. Вони можуть кульгати доти, поки не потрібно exec-нути новий бінарник,
підвантажити спільну бібліотеку, ротейтнути логи або перезапуститися.

3) Чи безпечно видаляти всередині контейнера?

Безпечніше лише якщо ви видаляєте шар контейнера, а не змонтовані томи. Небезпечна частина — зазвичай том персистентних даних.
Якщо контейнер бачить шляхи хоста або має привілейовані монтування, «контейнер» перестає бути корисною межею.

4) Яка найбезпечніша альтернатива rm -rf для очищення?

Коли можливо: перейменуйте/перемістіть у карантинний каталог спочатку, потім видаліть пізніше. Коли треба видаляти: використовуйте find з явними обмеженнями
(межі файлової системи, глибина, вік, власник) і логуванням того, що видаляєте. І обов’язково зробіть снапшот перед дією на ФС зі снапшотами.

5) Чи можна відновити видалені файли на ext4/xfs?

Іноді так, але не розраховуйте на це. Відновлення залежить від того, чи блоки перезаписані, чи виконувався TRIM на SSD і як швидко ви зупинили записи.
Снапшоти та резервні копії — надійний шлях; судове відновлення — останній шанс.

6) Чому rm -rf іноді так повільний?

Видалення багатьох дрібних файлів — метадантично затратна операція: обхід каталогів, оновлення inode-ів, журнальні записи. На мережевому сховищі може бути гірше.
Також видалення може наситити IO і загальмувати інші робочі навантаження. «Очищення» може стати аутеджем.

7) Чи варто робити псевдонім rmrm -i глобально?

Підійде для інтерактивних шеллів, але майже марно для автоматизації. Це також привчає людей бездумно натискати «y» тисячу разів.
Краще: впровадьте найменші привілеї, allowlist шляхів і покладіться на снапшоти/бекапи для справжньої безпеки.

8) Який найкращий захист проти флотного руйнівного виконання команд?

Захист у глибину: погодження для руйнівної автоматики, скопування середовищ, immutable інфраструктура з процесами перебудови,
і снапшоти на рівні зберігання. Також: стаджинг, що справді репрезентативний, щоб скрипти ламалися голосно ще до продакшну.

9) Що робити, якщо в нас сьогодні немає снапшотів?

Тоді перший крок — не новий інструмент, а політика. Визначте, які дані мають бути відновлюваними, задайте RPO/RTO, впровадьте бекапи
і відпрацювання відновлення. Снапшоти потужні, але тільки якщо є політика збереження і процедури відновлення.

10) Як безпечно зупинити runaway-видалення?

Якщо ціль неправильна — зупиніть швидко: вбийте процес, відмонтуйте уражену ФС якщо можливо, або ізолюйте хост.
Потім створіть снапшот пошкодженого dataset (якщо підтримується) перед спробою ремонту, щоб не втратити судові докази.

Висновок: наступні кроки, які можна зробити цього тижня

«rm -rf /» знаменитий, бо простий, незворотний і завжди чекає ваш найгірший день. Але історії насправді не про команду.
Вони про відсутні гальма: немає снапшотів, неохайні привілеї, скрипти, що приймають порожні змінні, і runbook-и, що вважають файлову структуру статичною.

Практичні наступні кроки:

  • Зробіть інвентар критичних датасетів і розмістіть їх на сховищі зі снапшотами (або бекапом з перевіреними відновленнями).
  • Аудитуйте скрипти очищення на предмет загроз від порожніх змінних та сюрпризів зі симлінками/монтуваннями; додайте allowlist-и і жорсткі стопи.
  • Проведіть одне відпрацювання відновлення цього місяця. Заміряйте час. Напишіть runbook з урахуванням реального досвіду.
  • Зменшіть постійні привілеї і вимагайте явного погодження для руйнівної автоматики в масштабі.
  • Оновіть runbook на чергуванні «диск заповнений» — починайте з діагностики, а не з видалення.

Якщо ви це зробите, то не лише уникнете інциденту, що визначає жанр. Ви також зробите щоденну роботу спокійнішою — менше паніки, менше сюрпризів
і менше міфів «він працював минулого разу», які трактують як інженерію.

← Попередня
ZFS: використання NVMe як L2ARC — коли ARC замало
Наступна →
P-ядра та E-ядра: гібридні CPU без маркетингу

Залишити коментар