Хтось рано чи пізно запускає zfs destroy у поспіху. Не тому, що він недбалий — бо продакшн шумний, диски заповнюються о 2:00 ночі, а імена датасетів виглядають так, ніби їх генерувала комісія. ZFS потужний, але він не ваш нянь. Він охоче видалить саме те, що ви попросили, а не те, що ви мали на увазі.
Це практичний посібник, щоб не впасти в кратер «не той датасет». Ми розберемо реальні запобіжники, які надає ZFS, пастки, яких немає, і повторювані перевірки, які роблять видалення нудним і безпечним.
Що zfs destroy насправді робить (і від чого відмовляється)
zfs destroy видаляє ZFS-датасет: файлову систему, том (zvol), снапшот або букмарк. Це видалення керується метаданими; ZFS не «витирає блоки» в старому розумінні. Він просто видаляє посилання, і простір стає доступним, коли ніхто більше не посилається на ці блоки.
Це звучить як щось відновлюване. В основному — ні. ZFS не має вбудованого «кошика» для датасетів. Якщо ви не зробили снапшот або не реплікували кудись ще, «відмінити» — це машина часу, яку ви не побудували.
Ціль видалення та прапорці, які потрібно враховувати
- Файлова система:
tank/app— має mountpoint і може містити дочірні датасети. - Снапшот:
tank/app@2025-12-26— незмінний стан; видалення звільняє блоки, якщо жоден інший снапшот/клон їх не тримає. - Том (zvol):
tank/vm01— блочний пристрій під/dev/zvol; часто використовується гіпервізорами. - Букмарк:
tank/app#bk1— оптимізаційна вказівка для send/receive; маленький, але має значення залежності.
Прапорці — це місце, де безпека або існує, або гине:
-rвидаляє дочірні (файлові системи, снапшоти під датасетом) рекурсивно. Чудово, коли це навмисно. Катастрофічно, коли ви помилилися.-Rвидаляє залежні, включно з клоні. Це кнопка «я дійсно маю на увазі» — і одночасно кнопка «я не знав, що існують клоні».-fпримусово вивішує перед видаленням файлову систему (де підтримується). Якщо ви використовуєте-fневимушено, ви вже відійшли від безпечного шляху.-n(dry-run) є на деяких платформах/версіях для деяких операцій, але не покладайтеся на нього скрізь. Ваша безпечна робоча процедура не повинна залежати від наявності одного прапорця у всіх системах.
Ось неприємна правда: zfs destroy небезпечний не тому, що він непередбачуваний. Він небезпечний тому, що цілком передбачуваний. Якщо ви неакуратно виберете ціль, ZFS сумлінно виконає вашу неуважність на швидкості проводу.
Короткий жарт, бо нам усім потрібен: ZFS не має «кошика» — у нього є «скоріше шкода від кошика».
Чому «не той датасет» трапляється в реальному житті
Більшість інцидентів із неправильним видаленням — це не одна помилка при наборі. Це ланцюжок дрібних припущень:
- Ви припускаєте, що mountpoint = ідентичність датасету. Це не так (mountpoint може бути успадкований, змінений або встановлений у legacy).
- Ви припускаєте, що «цей хост» володіє датасетом. Можливо, він імпортований в іншому місці, або реплікований, або керується HA.
- Ви припускаєте, що «ніхто ним не користується», бо ніхто не казав. Тим часом контейнер, гіпервізор чи агент бекапу тихо його використовують.
- Ви припускаєте, що діти — безпечні. Потім
-rзітре десять датасетів, про які ви забули. - Ви припускаєте, що снапшоти — це бекапи. Вони такими не є, якщо у вас немає другої копії.
Вбудовані запобіжники: клоні, холди, зайняті монти та права
ZFS надає реальні запобіжники. Вони не завжди доступні саме тоді, коли вам потрібно, і не покривають категорію «я вказав не на те». Але розуміння їх змінює вашу безпеку одразу.
1) Залежності клонів блокують видалення снапшота
Якщо у снапшота є клон, ZFS не дозволить видалити снапшот, доки ви не вирішите проблему з клонуванням (або не використаєте операцію залежного видалення). Це один з рідкісних випадків, коли ZFS рятує вас від себе.
Але це також пастка: ви можете думати, що видаляєте «старий снапшот», щоб звільнити простір. ZFS відмовляє, ви додаєте -R, щоб «зробити так», і раптом ви також видалили клон, який хтось використовував для тестування, аналітики або — мій улюблений випадок — «тимчасових» даних, що стали постійними кілька місяців тому.
2) Холди: найпростіший запобіжник
Холд на снапшот забороняє його видалення, поки його явно не зняли. Холди прості, дешеві та дуже ефективні для безпеки. Їх також рідко використовують, бо здається «занадто» додатковим. У продакшні «занадто» — це головне.
3) Зайняті датасети й монти можуть протистояти видаленню
Змонтувана файлова система, що використовується, може не відмонтуватися чисто. Залежно від платформи й опцій, ZFS може відмовити в видаленні, або ви можете «виправити» це за допомогою -f і відмонтувати щось, що все ще потрібно додатку. Обидва результати — інформативні.
Якщо destroy не вдається через зайнятість, це не те, що ZFS дратує. Це ZFS каже: «Гей, процес підключений; можливо варто перевірити, чи ви не збираєтеся видалити робоче навантаження». Прислухайтеся.
4) Делеговані права можуть врятувати вас від себе (і також уповільнити)
ZFS підтримує делегацію: можна дозволити ролі робити снапшоти, але не видаляти; або видаляти лише в межах піддерева; або вимагати підвищених привілеїв для «гострих ножів». Організації, які ставляться до zfs destroy як до rm -rf / — тобто не всі мають право це робити — зазвичай рідше зустрічають кар’єрні обмеження.
5) Іменування, походження та «сюрприз дітей»
ZFS-датасети ієрархічні. Люди — ні. У стресі люди бачать tank/app і не помічають tank/app/cache, tank/app/log, tank/app/old та tank/app/jenkins. Потім -r робить чистий підміт. ZFS робить саме те, що ви попросили.
Факти та історія, що пояснюють сучасну поведінку
Кілька контекстуальних пунктів, які роблять поведінку zfs destroy менш загадковою і більш передбачуваною:
- ZFS походить від Sun Microsystems у середині 2000-х, розроблений, щоб зробити управління сховищем більше схожим на програмне забезпечення, ніж на ритуал.
- Copy-on-write — основний механізм: ZFS ніколи не перезаписує живі блоки на місці. Це робить снапшоти дешевими, а видалення — в основному про лічильники посилань.
- Снапшоти — не окрема сховище. Вони — знімок у часі; простір звільняється тільки тоді, коли блоки залишаються без посилань від усіх снапшотів/клонів.
- Клони створені для швидкого надання (подумайте dev/test, шаблони VM). Наслідок для безпеки: снапшоти можуть стати «невидаленими», поки не розберетеся з залежностями.
- Ранні версії ZFS робили акцент на адміністративній прозорості через властивості та успадкування, що добре — поки успадковані властивості не роблять два датасети однаковими на перший погляд.
- zfs destroy швидкий, бо він маніпулює метаданими. Швидке видалення — це фіча. Податок за безпеку — ви повинні сповільнитися.
- OpenZFS розвивався на різних ОС. Деякі прапорці/поведінки відрізняються тонко за платформою та версією; переносні рукописи не повинні припускати однієї точної CLI-можливості.
- Розділення «zpool/zfs» (операції пулу vs датасету) відображає архітектуру: операції пулу — фізичніші, операції датасету — логічніші. Інциденти «не той датасет» зазвичай відбуваються на логічному рівні.
Інженерія надійності має свій світогляд для цього. Ось переказана ідея, часто приписувана James Hamilton (AWS): Працюйте з припущенням, що відмова — нормальна; будьте готові її витримувати.
Це включає помилки оператора.
План швидкої діагностики (коли потрібен простір негайно)
Це послідовність «я на виклику, пул 95% заповнений, і хтось скоро запропонує щось видалити». Мета: знайти реального споживача простору й підтвердити ідентичність датасету перед будь-якою руйнівною дією.
Спочатку: підтвердьте стан пулу і реальний тиск
- Перевірте стан пулу (помилки, degraded, resilvering можуть спотворити очікування).
- Перевірте логічне проти фізичного використання (сжаття, снапшоти, special vdevs можуть змінити картину).
- Визначте топ-датасети за використаним простором і розділіть «живі дані» від «даних, утримуваних снапшотами».
По-друге: знайдіть «простір, утримуваний снапшотами» проти «простору поточної голівки»
- Використовуйте
usedbysnapshotsна рівні датасету. - Перерахуйте снапшоти, впорядковані за used, якщо це доступно.
- Перевірте клоні/холди, які блокуватимуть видалення або зроблять його ризиковим.
По-третє: підтвердьте, що датасет — це те, що ви маєте на увазі
- Підтвердіть mountpoint і де він змонтований (включно з legacy-монтуваннями).
- Підтвердіть, що це не zvol, що обслуговує VM (шукайте споживачів).
- Підтвердіть, що це не ціль реплікації (видалення цілі receive посеред процесу — легкий шлях до довгої ночі).
Якщо ви дотримуєтесь лише одного правила: ніколи не вирішуйте «що видаляти» лише на основі шляху на кшталт /srv/app. Вирішуйте на основі імені датасету і властивостей, потім зіставляйте з шляхами.
Практичні завдання: команди, виходи та рішення
Це реальні завдання, які ви можете запускати в продакшн. Кожне містить приклад виходу та рішення, яке з нього випливає. Налаштуйте імена пулів/датасетів під своє середовище.
Завдання 1: Перевірте здоров’я пулу перед будь-якими діями
cr0x@server:~$ zpool status -x
all pools are healthy
Що це означає: Наразі немає відомих помилок на рівні пулу.
Рішення: Продовжуйте діагностику як зазвичай. Якщо тут показано degraded/faulted, зупиніться і спочатку вирішіть апаратні питання/resilvering; видалення даних під час проблем з пулом перетворює «напружено» на «невідновлювано».
Завдання 2: Швидкий перегляд «хто використовує простір» між датасетами
cr0x@server:~$ zfs list -o name,used,available,refer,mountpoint -S used tank
NAME USED AVAIL REFER MOUNTPOINT
tank/backup 7.12T 1.80T 7.12T /tank/backup
tank/app 1.04T 1.80T 120G /srv/app
tank/app/log 320G 1.80T 320G /srv/app/log
tank/app/cache 210G 1.80T 210G /srv/app/cache
tank/home 96G 1.80T 96G /home
Що це означає: USED включає снапшоти/дітей; REFER — це поточна голівка датасету (без дітей).
Рішення: Якщо USED великий, а REFER малий — ймовірно справа в снапшотах/дочірніх. Не видаляйте «датасет», щоб вирішити «роздування снапшотів».
Завдання 3: Відокремте простір, утримуваний снапшотами, від живих даних
cr0x@server:~$ zfs get -o name,property,value -H used,usedbysnapshots,usedbychildren tank/app
tank/app used 1.04T
tank/app usedbysnapshots 880G
tank/app usedbychildren 40G
Що це означає: Більшість простору утримують снапшоти (usedbysnapshots), а не жива файлова система.
Рішення: Перегляньте політику снапшотів і видаліть конкретні снапшоти (обережно), замість руйнування датасету. Якщо ви видалите датасет, можна втратити живі дані та нащадків. Надмірне вирішення — все одно вбивство.
Завдання 4: Перелічіть снапшоти і подивіться, до чого ви торкнетеся
cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -S used tank/app
NAME USED REFER CREATION
tank/app@hourly-2025-12-26 22G 120G Fri Dec 26 02:00 2025
tank/app@hourly-2025-12-25 21G 118G Thu Dec 25 23:00 2025
tank/app@daily-2025-12-20 19G 110G Sat Dec 20 01:00 2025
Що це означає: USED снапшота — це унікальний простір, утримуваний цим снапшотом.
Рішення: Видаляйте снапшоти згідно документованої політики збереження. Якщо ви не можете пояснити, навіщо існує снапшот — припускайте, що він потрібен, і з’ясуйте причину перед видаленням.
Завдання 5: Перевірте холди на снапшоті (ваш «не видаляти» тег)
cr0x@server:~$ zfs holds tank/app@daily-2025-12-20
NAME TAG TIMESTAMP
tank/app@daily-2025-12-20 legal Wed Dec 24 10:13 2025
Що це означає: Холд з іменем legal перешкоджає видаленню цього снапшота.
Рішення: Зупиніться. Це управлінське або операційне рішення, зроблене явно. Знайдіть власника і отримайте погодження перед зняттям холду.
Завдання 6: Перевірте на клоні, які роблять видалення снапшота ризиковим
cr0x@server:~$ zfs get -H -o value clones tank/app@daily-2025-12-20
tank/devclone
Що це означає: У снапшота є залежний клон tank/devclone.
Рішення: Не застосовуйте -R рефлекторно. Підтвердіть, чи tank/devclone використовується, і чи можна його промотнути або зробити снапшот перед будь-яким ланцюговим видаленням.
Завдання 7: Підтвердіть ідентичність датасету та походження перед видаленням
cr0x@server:~$ zfs list -r -o name,mountpoint,canmount,readonly tank/app
NAME MOUNTPOINT CANMOUNT RDONLY
tank/app /srv/app on off
tank/app/cache /srv/app/cache on off
tank/app/log /srv/app/log on off
Що це означає: Це точне піддерево, на яке вплине -r. Жодних домислів.
Рішення: Якщо ви маєте намір видалити лише логи, таргетуйте tank/app/log, а не tank/app. Якщо ви збираєтеся видалити весь додаток, упевніться, що кожна дитина очікувана.
Завдання 8: Відобразіть mountpoint назад у датасет (припиніть видаляти за шляхом)
cr0x@server:~$ findmnt -T /srv/app -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET SOURCE FSTYPE OPTIONS
/srv/app tank/app zfs rw,xattr,noacl
Що це означає: Файлова система, змонтована в /srv/app, — це tank/app.
Рішення: Використовуйте ім’я датасету в усіх командах і погодженнях. Якщо SOURCE відрізняється від очікуваного — зупиніться і розслідуйте. Шляхи брешуть; імена ZFS — ні.
Завдання 9: Перевірте, чи датасет активний (перед примусовим відмонтуванням)
cr0x@server:~$ lsof +f -- /srv/app | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 1421 root cwd DIR 0,105 4096 2 /srv/app
java 1880 app txt REG 0,105 12345678 7 /srv/app/bin/app.jar
Що це означає: Процеси використовують файли під цим mountpoint.
Рішення: Не видаляйте і не примусово не відмонтовуйте. Узгодьте зупинку додатку або таргетуйте снапшоти замість живої файлової системи.
Завдання 10: Підтвердіть, чи маєте справу з zvol (ризик для VM)
cr0x@server:~$ zfs list -t volume -o name,used,volsize,readonly tank | head
NAME USED VOLSIZE RDONLY
tank/vm01 220G 256G off
tank/vm02 180G 256G off
Що це означає: Ці датасети — блочні пристрої. Їхнє видалення — миттєва ампутація VM.
Рішення: Перш ніж видаляти, вимагайте явної перевірки власності VM. Трактуйте томи як більш ризикові, ніж файлові системи, бо споживач часто — гіпервізор, а не людина.
Завдання 11: Перевірте властивості датасету, що змінюють його «очевидність»
cr0x@server:~$ zfs get -o name,property,value -H mountpoint,canmount,origin,receive_resume_token tank/app
tank/app mountpoint /srv/app
tank/app canmount on
tank/app origin -
tank/app receive_resume_token -
Що це означає: Не клон (origin — -), і не в проміжку відновлення receive.
Рішення: Якщо origin встановлено, зрозумійте родовід клонів перед видаленням. Якщо присутній receive_resume_token, реплікація відбувається/відбувалась — видалення може ускладнити відновлення або майбутні інкрементальні send-повідомлення.
Завдання 12: Використовуйте zfs destroy для снапшота (вузько), а не для датасету (широко)
cr0x@server:~$ zfs destroy tank/app@hourly-2025-12-25
Що це означає: Снапшот видалено (якщо немає холдів/клонів, що блокують). Відсутність виводу при успіху — типова поведінка.
Рішення: Надавайте перевагу видаленню конкретних снапшотів, щоб звільнити простір, замість видалення цілих датасетів. Ви точите, а не відрубуєте голову.
Завдання 13: Переконайтеся, що видалення фактично повернуло простір (і чи могло це зробити)
cr0x@server:~$ zfs get -o name,property,value -H usedbysnapshots tank/app
tank/app usedbysnapshots 840G
Що це означає: Простір, утримуваний снапшотами, впав з 880G до 840G у нашому прикладі, отже простір звільняється як очікувалося.
Рішення: Якщо простір не зменшується, ви, ймовірно, видалили снапшоти, які не утримували багато унікальних даних, або клоні/інші снапшоти все ще посилаються на блоки. Продовжуйте діагностику, а не «спробуйте ще видалення».
Завдання 14: Перевірте, які саме снапшоти утримують простір (огляд на рівні датасету)
cr0x@server:~$ zfs list -t snapshot -o name,used -S used -r tank/app | head
NAME USED
tank/app@hourly-2025-12-26 22G
tank/app@hourly-2025-12-24 22G
tank/app@hourly-2025-12-23 21G
tank/app@daily-2025-12-20 19G
Що це означає: Найбільші унікальні дельти снапшотів вгорі списку.
Рішення: Видаляйте у порядку спадання used лише якщо це відповідає політиці та бізнес-потребам. Якщо снапшот великий, можливо, він зафіксував важливе розгортання.
Завдання 15: Знайдіть «приховані» датасети через legacy-монти
cr0x@server:~$ zfs get -o name,property,value -H mountpoint tank | grep legacy
tank/oldapps mountpoint legacy
Що це означає: Mountpoint цього датасету не керується ZFS; він, ймовірно, монтується через /etc/fstab або юніт сервісу.
Рішення: Не припускайте, що він не використовується, бо не змонтований там, де ви очікуєте. Перевірте системні монти та споживачів перед видаленням.
Завдання 16: Підтвердіть точний рядок датасету, який збираєтеся видалити (захист від людської помилки)
cr0x@server:~$ zfs list -H -o name tank/app
tank/app
Що це означає: Датасет існує, і у вас є канонічне ім’я без форматувального шуму.
Рішення: Скопіюйте-вставте цей точний вивід у запис про зміну та у командний рядок. Набір з клавіатури — це якраз те, що створює альтернативні реальності.
Другий короткий жарт (і далі — до роботи): Єдина річ, що швидше за zfs destroy, — це нарада, яку вам призначать після нього.
Три корпоративні міні-історії з полів видалень
Міні-історія 1: Інцидент через хибне припущення
Команда мала стандартну модель: файли додатку жили під /srv/app, логи під /srv/app/log, кеш під /srv/app/cache. Хтось прийшов на чергування і успадкував ментальну модель: «Якщо шлях існує, то це має бути датасет». Це припущення справджувалося роками — аж поки не відбулася міграція.
Під час міграції інженер зі сховищ перемістив tank/app/log на окремий пул для ізоляції I/O і використав bind mount, щоб зберегти шляхи. Ім’я датасету змінилося; mountpoint — ні. Інженера на чергуванні викликали через мало місця, і він дотримався старого рукопису: «видалити старий датасет логів». Він виконав zfs destroy -r tank/app, вважаючи, що це вплине лише на піддерево логів, яке його цікавило.
Команда отримала те, що команда просила. tank/app був живим датасетом додатку, а -r пройшов по дітях. Bind-mounted датасет логів вижив (інший пул), але бінарники додатка, конфіги та завантажені файли клієнтів — ні. Моніторинг показав флапінг додатка; балансувальник зняв його; оголошено інцидент.
Postmortem не був про «помилку оператора». Він був про організацію, яка дозволила рукописам на основі шляхів віддалятись від реальності датасетів. Виправлення було нудне: кожен крок рукопису, що згадував шлях, мав включати перевірку імені датасету через findmnt і zfs list. Також ввели правило: «жодного -r без переліку дітей у тікеті». Наступний черговий це ненавидів — поки не настав наступний майже-промах.
Міні-історія 2: Оптимізація, що зіграла злий жарт
Платформна команда хотіла прискорити CI-середовища. Клони здавались очевидним рішенням: зробити золотий снапшот датасету кешу збірки, клонувати для кожної роботи, видаляти після завершення. Це було елегантно. Це також стало повільною течією втрати простору під видом успіху.
Початковий дизайн клонував з tank/ci/cache@golden і встановив короткий TTL. Але джоб очистки був прив’язаний до хука «job finished» планувальника CI. Коли планувальник мав поганий день (розрив мережі, рестарт контрольної площини), очищення не відбувалося. Клони накопичувалися. Усі ще мали швидкий CI, що означало — ніхто пильно не дивився на зростання сховища.
Потім пул досяг високої завантаженості, і продуктивність почала дивно поводитися. Алокація почала фрагментуватись; синхронні запити сповільнились; затримки з’явилися в інших робочих навантаженнях. Черговий побачив найбільшого споживача: tank/ci/cache. Спроба видалити старі снапшоти не допомогла. ZFS відмовив. Снапшот мав клоні. «Виправити» стало «використати -R».
-R звільнив простір. Він також видалив активні клони, що належали поточним задачам, спричинивши збої збірок і ланцюгову реакцію повторів. Пул відновився; CI став бурею; контрольна площина знову впала. Оптимізація перетворилася на петлю зворотного зв’язку.
Довгострокове виправлення полягало не в «забороні клонів». Воно полягало в «ставленні до життєвого циклу клонів як до продакшн-даних». Додали холди для золотого снапшота, періодичний реконсилер, що знищує прострочені клони за властивістю ZFS, і запобіжник: ніхто не міг запускати zfs destroy -R у CI-неймспейсах без другої перевірки.
Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію
Сервіс, що працював із фінансами, зберігав рахунки на ZFS. Команда зробила одну непривабливу, але правильну річ: використовували холди на снапшотах для відповідних снапшотів і реплікували їх за межі хоста. Кожен місячний снапшот отримував тег холду і посилання на тікет. Це було бюрократично. Це також працювало.
В одному кварталі розгортання випадково записало потік некоректних даних — дублікатів, пошкоджених PDF тощо. Інцидент-респонс спочатку зосередився на відкаті коду, але дані вже були забруднені. Хтось запропонував: «Видалити датасет і відновити з бекапу». Це звучить рішуче — аж поки не зрозумієш, що «бекап» — це процес, а не іменник.
Натомість вони використали утримуваний місячний снапшот як довірену точку. Створили клон цього снапшота для судово-аналітичного аналізу, зберігши оригінал незмінним, і відновили чистий датасет реплікацією в новий неймспейс. Старий забруднений датасет лишився досить довго, щоб витягти те, що ще було корисним, а потім його цілеспрямовано видалили з підписом.
Без героїки. Без паніки -R. Ключовим було те, що «нудний» запобіжник — холди + реплікація за межами хоста — дозволив команді діяти повільно, навіть коли інцидент вимагав швидких рішень.
Типові помилки: симптом → корінна причина → виправлення
1) «Я видалив снапшоти, але пул не звільнив простір»
Симптом: Ви видаляєте кілька снапшотів; zpool list ледь змінюється.
Корінна причина: Блоки все ще посилаються інші снапшоти, клоні або голова датасету; видалені снапшоти не тримали унікальних даних.
Виправлення: Перевірте USED снапшотів і залежності клонів. Використовуйте zfs list -t snapshot -o name,used -S used і перевірте zfs get clones на великих/старих снапшотах. Видаляйте снапшоти з великою унікальною зайнятістю згідно політики, а не випадкові.
2) «Destroy не вдався: датасет зайнятий»
Симптом: Помилки cannot unmount / dataset is busy.
Корінна причина: Процеси тримають відкриті файли; експортування через NFS; рантайми контейнерів; залежності systemd на монтування.
Виправлення: Знайдіть споживачів за допомогою lsof/fuser, коректно зупиніть сервіси і лише потім видаляйте. Якщо вас тягне до -f, розглядайте це як запит на зміну, а не як імпульс у шеллі.
3) «Я видалив датасет, але директорія все ще існує»
Симптом: Шлях усе ще на місці; ви думаєте, що видалення не спрацювало.
Корінна причина: Каталог mountpoint — просто каталог; датасет надавав змонтовану файлову систему над ним. Після відмонтування/видалення підлягаючий каталог залишається.
Виправлення: Перевірте за допомогою findmnt -T і zfs list. Видаліть або переважно використайте каталог свідомо; не сприймайте його як доказ невдачі.
4) «Я видалив снапшот і тепер інкрементальна реплікація зламалась»
Симптом: Наступний інкрементальний send не вдається, бо очікуваного базового снапшота немає.
Корінна причина: Інструменти реплікації залежать від лінійки імен снапшотів; видалення порвало ланцюг.
Виправлення: Узгодьте збереження снапшотів з вимогами реплікації. Захищайте опорні снапшоти реплікації через холди або окремі категорії збереження. Не видаляйте «випадкові старі» снапшоти на реплікованих датасетах.
5) «Я запустив destroy -r і видалив більше, ніж планувалося»
Симптом: Зникли неочікувані датасети; монти пропали; сервіси впали.
Корінна причина: Ви не оприбуткували дітей, або припустили, що діти — «лише каталоги». Насправді вони були датасетами.
Виправлення: Завжди запускайте zfs list -r і вставляйте вивід у запис про зміну перед використанням -r. Якщо піддерево вас дивує — зупиніться і перерахуйте обсяг робіт.
6) «Destroy пройшов, але користувачі все ще бачать дані»
Симптом: Після видалення датасету шлях все ще повертає контент.
Корінна причина: Ви видалили датасет з тим самим mountpoint, як інший датасет, або у вас є автомонтери/ремонти, або інший хост його обслуговує (NFS/SMB/кластер).
Виправлення: Підтвердіть джерела монтування (findmnt), перевірте експорти і переконайтеся, що ви знаходитесь на хості, який обслуговує шлях. Імена ZFS локальні для хоста; досвід користувача може надходити з іншого місця.
Чеклісти / покроковий план для безпечного видалення
Чекліст A: Перед тим, як щось видаляти (перевірки ідентичності)
- Отримайте ім’я датасету зі системи, а не з пам’яті. Використовуйте
zfs list -H -o nameабо відображення черезfindmnt. - Підтвердіть піддерево. Запустіть
zfs list -rі перегляньте дітей. - Підтвердіть поведінку mount. Перевірте
mountpoint,canmount,readonlyта статусlegacy. - Підтвердіть споживачів. Використовуйте
lsofна mountpoint; для zvol перевірте власників VM/гіпервізора. - Перевірте холди та клоні. Холди означають «зупинитись». Клони означають «зрозумійте залежних».
- Підтвердіть стан реплікації/receive. Шукайте receive resume tokens або відомі розклади реплікації; не порвіть інкрементальні ланцюги необережно.
Чекліст B: Якщо мета — «звільнити простір», віддавайте перевагу діям у такому порядку
- Видаліть очевидний сміття всередині файлової системи (очищення на рівні додатку), якщо це безпечно.
- Видаліть снапшоти відповідно до документованої політики збереження, починаючи з тих, що мають найвищий унікальний
USED. - Перемістіть дані (реплікація, архів) і потім видаліть тепер порожній датасет.
- Видаляйте цілий датасет тільки коли він справді виведений з експлуатації, а не просто «великий».
Чекліст C: Якщо змушені видаляти датасет у продакшні
- Зробіть фінальний снапшот (і реплікуйте його за межі хоста, якщо можете). Якщо датасет уже відомо пошкоджений (корупція на рівні додатку), все одно зробіть снапшот для судово-аналітичного відкату.
- Поставте короткочасний холд на той фінальний снапшот, щоб ніхто «з корисності» не видалив його під час вікна змін.
- Вимкніть автомонтери/сервіси, які можуть перемонтувати або створити шлях датасету знову.
- Видаляйте найвужчу ціль. Не використовуйте
-r, якщо не маєте наміру зачистити все піддерево. Не використовуйте-R, якщо не плануєте вбити клонів. - Перевірте видалення за допомогою
zfs list, перевірте монти та поведінку додатку. - Слідкуйте за простором пулу та помилками принаймні протягом одного інтервалу моніторингу після зміни.
Запобіжники для автоматизації, що не гальмують процес
Поведінка людей необхідна. Вона не достатня. Продакшн-видалення рано чи пізно відбуваються через автоматизацію: пайплайни де-провіжнінгу, очищення орендарів, завершення CI, скидання середовищ. Вам потрібні рейки, що припускають: оператор втомлений, скрипт буквальний.
1) Вимагайте явного allowlist префіксу датасетів
Автоматизація повинна видаляти датасети лише в відомому простірі імен, наприклад tank/ci/* або tank/ephemeral/*. Якщо ім’я датасету виходить за межі цього префіксу, скрипт має відмовитись.
2) Примусьте «перелічити піддерево перед рекурсивним видаленням»
Перед будь-яким -r скрипти повинні вивести zfs list -r і вимагати підтвердження людини в інтерактивному режимі, або зберегти його як артефакт у неінтерактивному. Це дає судовий доказ пізніше і запобігає тихим очищенням.
3) Використовуйте холди як політичну межу
Автоматизація повинна відмовитися від видалення будь-якого снапшота з холдом і бути обережною з датасетами, що містять утримувані снапшоти. Холди — дешевий вбудований «стоп-сигнал». Так ставтесь до них.
4) Тегуйте датасети властивостями і приймайте рішення з них
Встановіть кастомну властивість на кшталт com.example:purpose=ci або com.example:ttl=2025-12-27T00:00Z (іменування залежить від організації). Тоді ваш джоб очистки видалятиме лише датасети, властивості яких вказують на їхню відпрацьованість. Імена допомагають; властивості — примусові.
5) Обмежте, хто може видаляти взагалі
Використовуйте делегацію, щоб більшість ролей могла робити снапшоти/клонувати, але не видаляти поза своїм піддеревом. Це не про довіру; це про зменшення потенційного збитку. На практиці це також спрямовує операції видалення у переглядні робочі процеси.
FAQ
1) Чи є у ZFS вбудований undelete для видалених датасетів?
Ні. Якщо ви видалили датасет і у вас немає снапшотів і немає реплікованої копії, відновлення — те, на що не варто розраховувати. Розглядайте destroy як остаточний.
2) Чи безпечніше видаляти снапшот порівняно з датасетом?
Так, безпечніше, бо це більш вузька дія. Але це все ще не автоматично безпечно: снапшоти можуть бути опорними для реплікації, регуляторними артефактами або потрібні для відкату. Перевіряйте холди, залежності клонів і процеси бекапу/реплікації.
3) У чому різниця між -r і -R у zfs destroy?
-r видаляє дочірні датасети і снапшоти під цільовим датасетом. -R видаляє залежні, включаючи клоні, і передбачає набагато більш руйнівну рекурсію. Використовуйте -R тільки коли ви явним чином перерахували, що воно знищить.
4) Чому ZFS іноді відмовляє в видаленні снапшота?
Зазвичай тому, що: на снапшоті є холд, у нього є залежні клоні, або у вас немає дозволів. ZFS відмовляє, бо видалення порушило б правила залежностей або політику.
5) Чи можна покладатися на mountpoint для ідентифікації датасетів?
Не надійно. Mountpoint може бути успадкований, змінений, встановлений у legacy або перекритий іншими монтуваннями. Завжди зіставляйте шляхи з датасетами за допомогою інструментів інспекції монтувань, потім оперуйте іменами датасетів.
6) Якщо я видалю датасет, чи зникнуть його снапшоти?
Так, якщо ви видаляєте датасет (особливо рекурсивно), ви зазвичай видаляєте датасет і його снапшоти у відповідному обсязі. Якщо хочете зберегти точку відновлення — зробіть і реплікуйте снапшот кудись ще перед видаленням.
7) Чому видалення великого снапшота не звільнило стільки простору, скільки його розмір?
Розмір снапшота — не просте число. USED снапшота — це унікальний простір, який він утримує, а не загальна обсягова картина. Якщо інші снапшоти або клоні посилаються на ті ж блоки, простір не звільниться, поки всі посилання не зникнуть.
8) Чи можна використовувати zfs destroy -f щоб примусити процес?
Лише коли ви підтвердили, що датасет справді має бути видалений, і ви з’ясували, чому він зайнятий. Примусовий відмонтування може зламати запущені додатки і приховати помилку вибору неправильної цілі. Розглядайте -f як етап ескалації з явною верифікацією.
9) Який найбезпечніший операційний шаблон для виведення датасету з експлуатації?
Снапшот → реплікація (або інший оф-хост копіювальний механізм) → тимчасовий холд на фінальний снапшот → відключення сервісів/монтувань → вузьке видалення → перевірка. Якщо не можете реплікувати, хоча б зробіть снапшот і поставте холд на визначений проміжок.
10) Як запобігти скрипту від видалення неправильного датасету?
Використовуйте строгий allowlist неймспейсів, перевіряйте існування датасету і піддерево, відмовляйте цілям з холдами, і вимагаєте властивостей, які маркують датасет як видимий для знищення. Зробіть скрипт «дратівливим» у корисних місцях.
Наступні кроки, які можна реалізувати цього тижня
Якщо ви працюєте з ZFS у продакшні, ви можете зробити випадкові видалення «не тих датасетів» рідшими, не гальмуючи команду до повного блокування.
- Оновіть ваші рукописи: кожен руйнівний крок має включати «відобразити шлях у датасет» і «перелічити піддерево» перевірки.
- Впровадьте холди на снапшоти для «обов’язково зберегти» випадків: відповідність, кінець місяця, перед міграцією, перед оновленням. Холди — дешеве страхування.
- Встановіть конвенцію іменування та простору імен: відпрацьовані датасети живуть під префіксом, який автоматизація може примусити.
- Обмежте привілеї на видалення: більшості людей вони не потрібні. Делегуйте масово снапшоти/клони; обмежте видалення вузько.
- Попрактикуйте план роботи зі звільнення простору: навчіть чергових відрізняти
referвідusedbysnapshots, щоб вони перестали видаляти «великий датасет», щоб вирішити «великі снапшоти». - Зробіть
-Rсоціально дорогим: вимагайте переліку залежностей клонів і другої перевірки. Це самостійно запобігатиме багатьом уникненим аваріям.
ZFS — це скальпель. Він також може бути бензопилою, але тільки якщо ви наполегливо тримаєте його за неправильний кінець. Запобіжники існують; ваше завдання — користуватися ними свідомо.