Коли «очищувачі» спричинили хаос: довірені утиліти, що пішли не так

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

Диск досягає 92%. Тривоги починають пищати. Хтось створює «завдання на очищення», яке виглядає нешкідливо: ротувати логи, видаляти образи, очищувати тимчасові файли, вакуумити журнали. Та робота, яку виконують між зустрічами.

Через дві години ваша база даних — лише для читання, вузол евакуйовано, а постмортем має заголовок на кшталт «Інцидент видалення №7». Винна утиліта? Не шкідливе ПЗ. Не атака. Довірена утиліта, що робила точно те, що їй сказали.

Чому очищення особливо небезпечне в продакшні

Очищення — руйнівна дія, зазвичай незворотна, і часто виконується під тиском часу. Це триєдність ризику. Додайте четвертий фактор: роботу з очищення зазвичай делегують у найменш привілейований контекст, який усе ж має достатньо повноважень, щоби зіпсувати ваш день. Root, cluster-admin або роль «storage maint», яка тихо має доступ до всього, бо «треба».

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

Сучасні системи не зберігають просто «файли». Вони зберігають взаємозв’язки: контейнери, що посилаються на шари оверлею; бази даних, що посилаються на WAL-сегменти; сервіси, що посилаються на сокети й lock-файли; снапшоти, що посилаються на історію блоків; шіпери логів, що посилаються на позиції інодів; інструменти бекапу, що посилаються на контрольні суми. Коли «очищувач» видаляє об’єкт, він може порвати зв’язок, який ніколи не був явно зафіксований.

Один цитат, бо індустрія вивчила це дорогою ціною: «Перефразована ідея» від James Hamilton (reliability engineering): невеликі операційні зміни спричиняють несподівано багато відмов; ставтеся до них як до повноцінних релізів.

Є ще людський фактор. Коли диск повний, виникає відчуття терміновості. Терміновість породжує героїзм. Героїзм породжує --force. А --force — це доросла версія «Я впевнений, що це нормально».

Жарт №1: Скрипти очищення як коти — вони підкоряються лише коли це незручно, і завжди знають, де лежать дорогі дані.

Цікаві факти та історичний контекст (коротко, але корисно знати)

  • Ідея Unix «усе — файл» робила очищення оманливо простим. Але це також спростило випадкове видалення вузлів пристроїв, сокетів і файлів стану, які «не були даними», доки ними не стали.
  • Ранні системні адміністратори використовували ротацію логів задовго до появи стандартних інструментів; ad-hoc патерни «перемістити та обрізати» досі переслідують системи, де демони не перевідкривають логи коректно.
  • Журнальні файлові системи (ext3/ext4, XFS) покращили відновлення після збою, але не «відновлення після дурної помилки». Видалення — це все ще видалення; журнал допомагає консистентності, а не прощає помилки.
  • Перехід до шарів контейнерів створив нові збирачі сміття (image prune, layer GC). Тепер «очищення диска» може зламати планування потужностей по всьому кластеру, а не лише на одному хості.
  • Зберігання copy-on-write (ZFS, btrfs) зробило снапшоти повноцінним інструментом операцій. Це також ускладнило поняття «вільного простору»: видалення файлів може не звільнити блоки, якщо снапшоти їх посилаються.
  • Виснаження інодів — класичний «псевдо-повний диск»: у вас може бути багато вільних байтів, але нуль інодів, зазвичай через мільйони дрібних файлів у тимчасових чи логових директоріях.
  • POSIX‑семантика дозволяє процесам писати в файли, які вже видалені. Простір не буде звільнений, доки останній дескриптор не закриється, тому «я видалив великий файл» ≠ «диск звільнився».
  • Systemd ввів політики tmpfiles, які можуть очищати директорії, які ви вважали постійними, особливо якщо ви поклали стан у /tmp або некоректно задекларували runtime‑директорію.

Як «очищувачі» ламаються: найпоширеніші режими відмов

1) Ціль розширилась: glob, змінні та «корисні» налаштування за замовчуванням

Утиліта очищення рідко видаляє «річ». Вона видаляє «все, що підпадає під маску». Ця маска може розширюватися. Глоби розгортаються. Змінні оточення підставляються. Симлінки розгортаються. Монтовані файлові системи з’являються/зникають. І раптом ваше ретельно обмежене видалення перетворюється на загальноуніверсальне випалювання.

Типові винуватці: rm -rf $DIR/*, де $DIR порожній; find, якому бракує -xdev; симлінк, створений інсталяційним кроком; bind mount, що переніс вміст у «тимчасовий» шлях.

2) Звільнено простір? Не обов’язково: відкриті дескриптори й снапшоти

Ваш диск повний. Ви видаляєте 30 ГБ. Диск усе ще повний. Паніка зростає. Люди видаляють швидше. Реальна причина зазвичай така:

  • Відкриті, але видалені файли: дані залишаються алокованими, поки процес не закриє дескриптор.
  • Снапшоти: дані залишаються посиланнями у снапшоті, тому блоки не можна звільнити.

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

3) «Оптимізаційні» очищувачі, що конкурують з вашою роботою

Деякі інструменти продають очищення як пасивну дію. Це не так. Сканування директорій розбиває кеші. Хешування файлів спалює CPU. Проходи дедупаґу включають диски. Перебалансування метаданих спричиняє I/O шторми. Очищувач може стати найгарячішим навантаженням на боксі.

В термінах зберігання: ви щойно додали фонова випадкова операція читання з поганою локальністю. Якщо система вже обмежена по I/O, вітаю: ви побудували бенчмарк без дроселювання і спрямували його в продакшн.

4) Припущення про «безстанність», що видаляють стан

Багато систем кладуть стан у місця, які виглядають тимчасовими:
/var/tmp, /var/lib, /run, локальні кеші або «просто файл у /tmp», який став lock-файлом, чергою або спулом.

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

5) Логіка зберігання, що працює, поки рухається час

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

6) Інструменти, що самі по собі безпечні, разом — небезпечні

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

Більшість катастроф з очищення — не одна погана команда. Це збій оркестрації між добрими намірами інструментами.

7) Права та ідентичність: міф «він не може видалити те»

Люди вважають, що інструмент під сервісним обліком не може завдати серйозної шкоди. Потім хтось тимчасово додав обліковий запис до групи, або він працює в привілейованому контейнері, або файлову систему змонтовано з вільними правами, або ACL дає більше, ніж ви думаєте.

Інциденти з очищення люблять підвищення привілеїв. Це тихо. Це зручно. Це катастрофічно.

Жарт №2: «Я просто швидко виконаю очищення» — ось як у відмов з’являється кардіо.

План швидкої діагностики: перші/другі/треті перевірки

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

Перше: перевірте, який ресурс насправді вичерпано

  • Байти проти інодів: система може бути «повною» двома різними способами.
  • Файлова система проти thin pool проти резерву снапшота: «df каже 90%» — це не повна картина для LVM thin, ZFS або оверлеїв контейнерів.
  • Локальний вузол проти віддаленого сховища: у Kubernetes евакуації відбуваються через тиск на файлову систему вузла, а не через ваш дорогий SAN.

Друге: знайдіть найбільших споживачів (і чи звільнить видалення місце)

  • Найважчі директорії та файли.
  • Відкриті, але видалені файли.
  • Посилання снапшотів або утримання в CoW‑сховищі.

Третє: оцініть радіус ураження і зупиніть кровотечу

  • Відключіть або поставте на паузу задачу очищення (cron, systemd timers, CI runner).
  • Заморозьте подальші ротування/видалення, що можуть знищити форензичні артефакти.
  • Стабілізуйте систему: безпечно звільніть деякий простір (навіть 2–5%) для відновлення нормальної роботи (journald, пакетні менеджери, бази даних).

Правило прийняття рішень, з яким можна жити

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

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

Ось завдання, до яких я звертаюся, коли «очищення» пішло не так. Кожне включає: команду, що типовий вивід означає, і рішення, яке ви приймаєте далі. Розглядайте їх як блоки побудови, а не як скрипт для сліпого копіювання.

Завдання 1: Перевірити використання байтів по файловій системі (швидка триаж)

cr0x@server:~$ df -hT
Filesystem     Type   Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4   220G  214G  1.8G 100% /
tmpfs          tmpfs   32G  120M   32G   1% /run
/dev/sdb1      xfs    3.6T  2.1T  1.5T  59% /srv

Значення: Корінь практично заповнений. /srv у порядку, але це не допоможе, якщо навантаження пише в /.

Рішення: Спочатку зосередьтеся на звільненні кількох ГБ на /, щоб відновити стабільність. Не «чистіть /srv» тільки тому, що там багато місця.

Завдання 2: Перевірити виснаження інодів (момент, коли df «бреше»)

cr0x@server:~$ df -ih
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p2   14M   14M     0  100% /

Значення: У вас закінчилися іноди. Видалення кількох великих файлів не допоможе, якщо проблема — мільйони дрібних.

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

Завдання 3: Знайти директорії, що споживають байти

cr0x@server:~$ sudo du -xhd1 /var | sort -h
120M    /var/cache
3.2G    /var/log
14G     /var/lib
18G     /var

Значення: /var/lib — «важковик». Зазвичай це стан додатка (бази даних, рантайми контейнерів), а не «сміття».

Рішення: Розбирайтеся з /var/lib обережно; розгляньте очищення з урахуванням додатка, а не грубе видалення.

Завдання 4: Знайти, які директорії споживають іноди (підрахунок файлів)

cr0x@server:~$ sudo find /var -xdev -type f -printf '.' | wc -c
12984217

Значення: ~13 мільйонів файлів під /var. Це багато. Ймовірно, у вас runaway тимчасові файли, фрагментовані кеші або зламана схема ротації.

Рішення: Наступним кроком ідентифікуйте «гарячі» директорії (не видаляйте наосліп).

Завдання 5: Виявити «гарячі» директорії за інодами

cr0x@server:~$ sudo find /var -xdev -mindepth 1 -maxdepth 3 -type f -printf '%h\n' | sort | uniq -c | sort -nr | head
8420000 /var/lib/app/spool
1960000 /var/log/nginx
510000  /var/tmp/session-cache

Значення: /var/lib/app/spool вибухає. Спули — зазвичай «бізнес-логіка», а не сміття.

Рішення: Трактуйте це як інцидент у пайплайні додатка; очищення може бути пластирем, а не рішенням.

Завдання 6: Перевірити відкриті, але видалені файли (простір не звільнений)

cr0x@server:~$ sudo lsof +L1 | head
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NLINK NODE NAME
java     2310 app    12w  REG  259,2  8.0G     0  9123 /var/log/app/app.log (deleted)
nginx    1882 www     5w  REG  259,2  1.2G     0  7742 /var/log/nginx/access.log (deleted)

Значення: Ці процеси все ще тримають дескриптори до видалених логів. Байти залишаються алокованими.

Рішення: Перезапустіть або відправте сигнал процесам, щоб вони перевідкрили логи (наприклад, systemctl restart або kill -HUP), потім перевірте df ще раз.

Завдання 7: Підтвердити використання journald перед вакуумом

cr0x@server:~$ sudo journalctl --disk-usage
Archived and active journals take up 4.1G in the file system.

Значення: Журнали займають істотний простір. Вакуумування може швидко звільнити місце, але ви втратите форензичні логи.

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

Завдання 8: Безпечно вакуумити journald до цільового розміру

cr0x@server:~$ sudo journalctl --vacuum-size=800M
Vacuuming done, freed 3.3G of archived journals from /var/log/journal.

Значення: Ви звільнили 3.3G з журналів.

Рішення: Перевірте стан системи. Якщо це було лише тимчасове рішення, виправте корінь, що заповнював диск.

Завдання 9: Валідувати конфігурацію logrotate без запуску

cr0x@server:~$ sudo logrotate -d /etc/logrotate.conf
reading config file /etc/logrotate.conf
including /etc/logrotate.d
reading config file nginx
error: nginx:12 duplicate log entry for /var/log/nginx/access.log

Значення: Logrotate поводився б непередбачувано або зазнав би помилки, лишаючи логи рости без обмеження.

Рішення: Виправте конфігурацію і запустіть logrotate вручну один раз (обережно) після валідації.

Завдання 10: Запустити logrotate один раз у вериозному режимі і слідкувати за змінами

cr0x@server:~$ sudo logrotate -vf /etc/logrotate.conf
rotating pattern: /var/log/nginx/*.log  after 1 days (14 rotations)
renaming /var/log/nginx/access.log to /var/log/nginx/access.log.1
compressing log with: /bin/gzip

Значення: Відбулася ротація; стиснення стартувало. Якщо демон не перевідкрив логи, тепер у вас можуть бути відкриті, але видалені файли.

Рішення: Переконайтеся, що postrotate дії сигналізують сервісам коректно; перевірте через lsof +L1.

Завдання 11: Перевірити використання диска рантаймом контейнерів (приклад Docker)

cr0x@server:~$ sudo docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          48        12        38.2GB    24.7GB (64%)
Containers      21        6         3.1GB     1.0GB (32%)
Local Volumes   16        10        220GB     0B (0%)
Build Cache     12        0         5.6GB     5.6GB

Значення: Велика цифра — це локальні томи. Prune образів не вирішить тиск диска; це станові томи.

Рішення: Проведіть аудит томів та власників. Розгляньте очищення на рівні додатка або переміщення томів на більший монтувальний диск.

Завдання 12: Прюнуйте безпечно (не знищуйте об’єкти в користуванні)

cr0x@server:~$ sudo docker image prune -a --filter "until=168h"
Deleted Images:
deleted: sha256:3d2b...
Total reclaimed space: 12.4GB

Значення: Ви звільнили 12.4GB від образів старших за 7 днів.

Рішення: Якщо це продакшн‑вузол, координуйте з циклом деплою; переконайтеся, що ви не прюните образи, необхідні для швидкого відкату.

Завдання 13: Перевірити симптоми «disk pressure» у вузлі Kubernetes

cr0x@server:~$ kubectl describe node worker-3 | sed -n '/Conditions:/,/Addresses:/p'
Conditions:
  Type             Status  LastHeartbeatTime                 Reason              Message
  DiskPressure     True    2026-01-22T10:11:02Z              KubeletHasDiskPressure  kubelet has disk pressure
  Ready            True    2026-01-22T10:11:02Z              KubeletReady         kubelet is posting ready status

Значення: Вузол «Ready», але під DiskPressure; евакуації почнуться і навантаження буде скакати.

Рішення: Звільніть місце на файловій системі вузла, яку використовує kubelet/container runtime; не «чистіть усередині подів» як перший крок.

Завдання 14: Реальність ZFS‑снапшотів (чому видалення не звільняє місце)

cr0x@server:~$ sudo zfs list -o name,used,avail,refer,mountpoint tank/app
NAME      USED  AVAIL  REFER  MOUNTPOINT
tank/app  980G  120G   240G   /srv/app

Значення: Датасет «USED» — 980G, але «REFER» — 240G. Дельта зазвичай — це снапшоти або дочірні датасети.

Рішення: Перегляньте снапшоти перед видаленням чого-небудь; очищення може вимагати зміни політики зберігання снапшотів.

Завдання 15: Перелічити снапшоти і подивитися, що тримає простір

cr0x@server:~$ sudo zfs list -t snapshot -o name,used,refer,creation -s used | tail
tank/app@daily-2026-01-15   22G  240G  Mon Jan 15 02:00 2026
tank/app@daily-2026-01-16   27G  240G  Tue Jan 16 02:00 2026
tank/app@daily-2026-01-17   31G  240G  Wed Jan 17 02:00 2026
tank/app@daily-2026-01-18   35G  240G  Thu Jan 18 02:00 2026
tank/app@daily-2026-01-19   39G  240G  Fri Jan 19 02:00 2026
tank/app@daily-2026-01-20   44G  240G  Sat Jan 20 02:00 2026
tank/app@daily-2026-01-21   48G  240G  Sun Jan 21 02:00 2026

Значення: Снапшоти займають помітний простір. Видалення файлів із /srv/app не зменшить USED значно, поки вони залишаються.

Рішення: Налаштуйте політику зберігання або реплікуйте снапшоти кудись ще перед прунингом; робіть це обдумано, а не в паніці.

Завдання 16: Визначити, чи очищення перейшло межі файлових систем

cr0x@server:~$ sudo find / -xdev -maxdepth 2 -type d -name 'tmp' -print
/tmp
/var/tmp

Значення: -xdev тримає вас на одній файловій системі. Без нього очищувач може пройти в змонтовані томи, включно з бекапами.

Рішення: Для будь-якого find‑базованого видалення додавайте -xdev, якщо ви не можете обґрунтувати перетин файлових систем письмово.

Три корпоративні міні-історії: неправильне припущення, невдала оптимізація, нудна перемога

Міні-історія 1: Інцидент через неправильне припущення («/tmp завжди безпечний»)

Середня компанія мала платіжний пайплайн з Java‑сервісом і сайдкаром для шифрування. Сайдкар писав короткоживучі артефакти у /tmp. Це мав бути тимчасовий потік: зашифрувати, передати, видалити. Просто.

Згодом «тимчасове» стало «операційним». Сайдкар також використовував /tmp як чергу відновлення: якщо upstream API лімітував, він тимчасово зберігав payloadи та повторював спроби. Ніхто цього не документував, бо це не була задумана фіча; це був прагматичний патч, доданий під час минулого інциденту і ніколи не переглянутий.

Потім інженер систем увімкнув systemd tmpfiles політику для очищення записів у /tmp, старіших за день. Повністю нормальна дія. Це зменшило churn інодів і тримало хости чистими. Наступного вікенду трафік різко виріс, сайдкар частіше зазнавав rate-limit, черга retry зросла. Вона перетнула одноденний поріг. Очищувач зробив свою роботу.

В понеділок — «зниклі транзакції». Не втрачені в мережі, не відхилені — тихенько видалені з шляху повтору. Логи сервісу теж були малопомічними, бо логи посилалися на ID запитів, але payloadи вже зникли.

Технічне виправлення було нудним: перенести чергу retry у виділену директорію під /var/lib, керувати її зберіганням явно і додати метрики глибини черги. Культурне виправлення було важливішим: будь‑яке «очищення», що зачіпає дефолтні політики ОС для temp, тепер вимагає погодження з власником додатка. Бо фраза «це просто /tmp» — ось як зникають гроші.

Міні-історія 2: Оптимізація, що відбилася бумерангом (агресивний pruning образів на CI раннерах)

Інша організація запускала self-hosted CI раннери на потужних машинах. Використання диска повільно росло, бо білди вантажили багато контейнерних образів. Хтось став кмітливим: нічна задача, що prun’ить усе старше за 24 години. Мета благородна — припинити дзвінки через «диск 90%».

Це працювало тиждень. Потім часи збірки погіршилися. Не трошки. Стопці настільки погані, що розробники почали повторювати джоби, що збільшило навантаження. Завдання prune запускалося вночі, але шкода була не «нічна». Кожного ранку перша хвиля білдів повторно вантажила образи, завантажуючи регістр і насичуючи мережеві лінки, які використовувалися продакшном.

Режим відмови був не в тому, що вони видалили потрібні речі. Він полягав у тому, що вони стерли локальність. Кеші існують, бо мережа і сховище не безкоштовні. Оптимізуючи диск, вони створили розподілений DoS проти власного регістру та WAN.

Виправлення: перейти від часового нукінгу до retention на основі ємності з нижнім порогом для часто використовуваних базових образів. Тримати «теплий» набір. Прунити, коли диск переходить поріг, а не по календарю. А також: прив’язати задачу prune до cgroup з обмеженнями I/O та CPU, бо фонові роботи не повинні стати найгучнішим процесом на хості.

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

SaaS‑платформа мала класичну проблему: зростання логів на вузлах, що обробляють стрибкоподібний трафік. Інженер запропонував видаляти старі логи прямо з /var/log. Інший інженер настояв на «карантинній» директорії: переміщувати кандидати у /var/log/.trash на тій же файловій системі, чекати 24 години, потім видаляти.

Це звучало марнотратно — навіщо зберігати сміття? Але крок карантину був дешевим. Операції перейменування швидкі. Це також зберігало можливість відновлення після помилки без бекапів, тікетів або незручних розмов.

Одного дня сервіс оновив формат логів і почав писати у нове ім’я файлу, яке співпадало з маскою очищення. Завдання очищення перемістило активний лог у карантин. Сервіс продовжував писати, але тепер він писав у знову відкритий файл на оригінальному шляху. Тим часом лог-шипер зламався, бо його курсор іноду пішов за переміщеним файлом. Алерти спрацювали швидко через падіння інгестії.

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

Типові помилки: симптом → корінь проблеми → виправлення

Диск повний, ви видалили великі файли, але df не змінився

Симптом: df все ще показує 95–100% після видалення.

Корінь: Відкриті, але видалені файли (процес все ще тримає дескриптор) або снапшоти, що утримують блоки.

Виправлення: Перевірте lsof +L1 і перезапустіть/перезавантажте сервіси; для ZFS/btrfs, перевірте снапшоти і коригуйте збереження свідомо.

Сервіс падає після очищення /tmp, але диск начебто став кращим

Симптом: Після очищення /tmp або /var/tmp демон не стартує, завдання зникають, або сплески навантаження.

Корінь: Додаток неправильно використовував тимчасові директорії як стан (черги, локи, сокети, кеші потрібні в рантаймі).

Виправлення: Перемістіть стан у явні постійні шляхи; закодуйте правила очищення з урахуванням додатка; додайте тести політик tmpfiles у стейджингу.

Ротація логів «працює», але ви втратили логи або з’явилися розриви в шипінгу

Симптом: Існують стиснуті логи, але є розриви інгестії або відсутні рядки.

Корінь: Ротовані/обрізані логи без сигналу процесу; шипер слідує за інодами і плутається через переміщення/обрізку.

Виправлення: Використовуйте коректні postrotate дії (HUP/reload), і узгодьте конфігурацію шипера з методом ротації (copytruncate vs rename).

Задача очищення підвищує I/O і латентність по вузлу

Симптом: Латентність підскакує коли запускається очищення; iowait росте; бази даних скаржаться.

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

Виправлення: Обмежте швидкість через ionice/nice, плануйте в не пікові години, обмежте область або переробіть у інкрементальне очищення з метриками.

«Ми прюннули образи» і тепер відкати повільні або не вдаються

Симптом: Відкат потребує підвантаження образів і таймаутиться; вузли тримаються.

Корінь: Агресивне прюнення видалило образи, які вважалися наявними в кеші.

Виправлення: Тримайте захищений теплий набір; прюньте за ємністю з мінімальним збереженням; узгодьте з частотою деплоїв і політикою відкатів.

Страх корупції файлової системи після масового видалення

Симптом: Додатки помиляться, директорії виглядають дивно, хтось каже «можливо корупція».

Корінь: Зазвичай не корупція; це відсутній стан, зміни прав, або видалені сокети/lock‑файли. Реальна корупція трапляється рідше, ніж здається.

Виправлення: Перевірте монтовані точки, права та стан додатків; подивіться kernel logs; запускайте перевірки файлової системи тільки з планом і вікном простою.

Очищення запустили на невірному хості або неправильному монту

Симптом: Вузол, не пов’язаний із тривогою, «почистили», або монту для бекапу було спорожнено.

Корінь: Відсутні захисні перевірки: немає перевірки імені хоста, перевірки монтів, -xdev пропущено, автоматизація вказана на невірну групу інвентарю.

Виправлення: Додайте жорсткі засоби безпеки (очікувані UUID монту, маркери середовища), і вимагайте інтерактивного підтвердження для руйнівних дій поза вікнами обслуговування.

Чеклісти / покроковий план: безпечне очищення без жалю

Крок 0: Перестаньте робити гірше (5 хвилин)

  1. Поставте задачу очищення на паузу: тимчасово відключіть cron/systemd timer/CI job.
  2. Зберіть докази: поточне використання диска/інодів, топ директорій, lsof +L1, і останні фрагменти syslog/journal.
  3. Дайте системі дихнути: безпечно звільніть трохи місця (vacuum journald або перемістити логи в карантин).

Крок 1: Доведіть, що тримає простір (15–30 хвилин)

  1. Байти проти інодів: запустіть df -hT і df -ih.
  2. Знайдіть споживачів: du -xhd1 на повній файловій системі; для інодів підрахуйте файли за директоріями.
  3. Перевірте відкриті видалені файли: lsof +L1.
  4. Якщо використовується CoW‑сховище: перевірте снапшоти і використання датасетів (ZFS/btrfs).

Крок 2: Оберіть найменш ризиковий шлях звільнення

  • Переважно видаляти відтворювані дані: білд‑кеші, кеші пакетних менеджерів, тимчасові артефакти, які можна відновити.
  • Переважно очищення з урахуванням додатка: vacuum бази даних через штатні інструменти, prune контейнерів з фільтрацією ретеншну, logrotate з коректними сигналами.
  • Уникайте видалення невідомого: усе в /var/lib без знання власника — пастка.

Крок 3: Впровадьте захисні механізми перед повторним увімкненням автоматизації

Задача очищення без засобів безпеки — це не «автоматизація». Це просто запланований ризик.

  • Карантин, потім видалити: переміщуйте кандидати в приховану директорію на тій же файловій системі; видаляйте після затримки.
  • Перевірка монтажів: перевіряйте очікувані точки монтування і типи файлових систем перед запуском.
  • Обмеження області: використовуйте -xdev, явні шляхи і максимальну глибину.
  • Сухі прогони: логуйте, що б видалило. Завжди.
  • Обмеження швидкості: використовуйте nice і ionice для фонових задач.
  • Метрики: алерт на тренди зростання, а не лише на пороги, і відслідковуйте дії очищення як події.

Крок 4: Зробіть це нудним навмисно

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

Питання та відповіді

1) Чому видалення лог‑файлу іноді не звільняє місце на диску?

Тому що процес може тримати файл відкритим і продовжувати писати в нього навіть після unlink. Простір звільняється тільки коли останній файловий дескриптор закриється. Використовуйте lsof +L1, щоб знайти такі файли, і перезапустіть/перезавантажте процес.

2) Чи завжди погана ідея використовувати rm -rf?

Це гострий інструмент. Проблема не в rm, а в неоднозначності. Якщо ви не можете точно визначити ціль і довести її правильність — не використовуйте рекурсивне насильницьке видалення в продакшні. Віддавайте перевагу переміщенню в карантин і очищенню з урахуванням додатка.

3) Яке найбезпечніше «аварійне» місце для швидкого звільнення простору?

Зазвичай архіви journald, кеші пакетного менеджера або відомі білд‑кеші — речі, які відтворюються. Уникайте видалення всього, що нагадує стан (/var/lib, каталоги баз даних, змонтовані томи), поки не підтвердите власника і можливість відновлення.

4) Чому очищення /tmp зламало додаток?

Бо додаток використав тимчасовий шлях як місце зберігання стану: сокети, локи, черги або кеші, потрібні в рантаймі. Вирішіть, перемістивши стан у явну постійну директорію і оголосивши runtime‑директорії (особливо при systemd).

5) Чому ZFS все ще показує велике використання після видалення файлів?

Снапшоти утримують посилання на старі блоки. Видалення поточних файлів може не звільнити простір, доки не видалити снапшоти. Перевірте zfs list -t snapshot і коригуйте ретеншн обережно — снапшоти часто — ваш єдиний швидкий відкат.

6) Чи варто агресивно прюнути контейнерні образи, щоб тримати диски чистими?

Не агресивно — стратегічно. Прунінг може стерти локальність і сповільнити деплої/відкати. Використовуйте пороги ємності, зберігайте теплий набір і координуйте з циклом релізів.

7) Як запобігти перетинанню очищення в змонтовані томи?

Використовуйте захист меж файлової системи, як-от find -xdev, і валідуйте точки монтування перед запуском. В автоматизації додавайте перевірки типу файлової системи та очікуваних ідентифікаторів пристрою.

8) Чи надійне «видалити старіше за N днів»?

Це надійно лише якщо парсинг часу та іменування файлів надійні. DST, зміни часових поясів і перейменування ламають логіку зберігання. Віддавайте перевагу видаленню за mtime з явною областю і сухими прогонками, і моніторте кількість видалень.

9) Який найбільший культурний крок для запобігання катастрофам очищення?

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

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

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

  1. Зробіть інвентарізацію механізмів очищення: cron jobs, systemd timers, CI runner maintenance, container GC, ретеншн снапшотів. Запишіть власників.
  2. Додайте патерн карантину для всього файлового підходу. Спочатку перейменування/переміщення, потім видалення.
  3. Інструментуйте тиск на диск: байти і іноди плюс швидкість зростання. Трендові аларми кращі за «92% о 3 ранку».
  4. Закодьте «швидку діагностику» у ваші руни: байти vs іноди, відкриті видалені файли, снапшоти, використання рантайму контейнерів.
  5. Обмежте фонове очищення: ваш очищувач ніколи не повинен бути головним споживачем на хості.
  6. Визначте, що можна видаляти і що має керуватися інструментами з урахуванням додатка. Якщо це стан — ставтесь до нього як до стану.

Чистота продакшну — не про видалення більше. Це про видалення з наміром, із захисними засобами та з можливістю повернутися назад, коли намір зустрічає реальність.

← Попередня
Інтегровані контролери пам’яті: зміна, яку ви відчуваєте й досі
Наступна →
ZFS atime: маленький перемикач, що може виправити «повільні записи»

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