Снапшоти ZFS — це найближче до подорожі в часі, що є у зберігання даних і при цьому проходить аудит. Але подорож у часі корисна лише тоді, коли ви можете відповісти на питання, яке поставить ваш начальник, команда безпеки або ваш 3-годинний ранок: що змінилося?
zfs diff — це простий, чесний інструмент для цієї задачі. Він не розкішний, не GUI і не враховує ваших почуттів. Він показує, які шляхи були додані, видалені, змінені або перейменовані між двома снапшотами (або між снапшотом і «тепер»). Правильне використання перетворює лякаюче «щось сталося» на список, до якого можна вжити заходів.
Що таке zfs diff (і чого це не є)
zfs diff порівнює дві точки в часі в межах одного dataset’у (або zvol, хоча шляхи файлів — найпоширеніший випадок). Ці точки зазвичай — снапшоти, наприклад pool/ds@snapA і pool/ds@snapB, або снапшот і поточна жива файлсистема. Результат — потік змін на рівні шляхів: створені файли, видалені файли, змінені файли, перейменовані шляхи.
Це не диф на рівні вмісту, як diff -u. Він не скаже вам «рядок 83 змінився». Він скаже «цей файл змінився», що зазвичай саме те, що потрібно операціям і реагуванню на інциденти. Якщо потрібні дифи вмісту, змонтуйте снапшоти і запустіть власні інструменти (так, це повільніше, галасливіше і легше зіпсувати).
Це також не авторитетний запис чому щось змінилося або який процес це зробив. Це інструмент обліку на рівні файлової системи: ось множина шляхів, стан метаданих/вмісту яких відрізняється між двома транзакційними групами.
Жарт №1: Снапшоти не брешуть, а адміністратори — зазвичай самі собі, за п’ять хвилин до дзвінка по інциденту.
Факти та історичний контекст для нарад
Короткі, конкретні тези, які допоможуть пояснити, чому дифи снапшотів ZFS поводяться так, як вони поводяться — і чому це перевага, а не незручність.
- Снапшоти ZFS — це copy-on-write, а не «резервні копії». Снапшот — це консистентне посилання на існуючі блоки; нові записи йдуть в інше місце. Ось чому снапшоти дешеві і миттєві.
- «Перейменування» не дорівнює «скопіювати потім видалити» з точки зору семантики файлової системи. ZFS може виявляти перейменування як першокласну операцію, і
zfs diffможе їх показувати, коли можлива кореляція ідентичності об’єкта. - ZFS спроєктовано з end-to-end контрольними сумами за замовчуванням. Це означає, що «файл змінився» можна прив’язати до реальних змін блоків, а не лише до того, що timestamp змінився, бо додаток торкнувся метаданих.
- Реплікація на основі снапшотів (send/receive) з’явилася задовго до маркетингу «нізвідки змінити неможливо». ZFS роками робив інкрементні потоки снапшотів; «незмінність» приходить від політики і дозволів, а не нового формату файлу.
- FreeBSD і illumos давно ставлять ZFS у ряд першокласних технологій. Багато виробничих поведінок (включно з інструментами навколо снапшотів) були відточені там ще до того, як ZFS для Linux набув такого ж рівня експлуатаційного комфорту.
- Вивід
zfs diff— це погляд на метадані та стан об’єктів, а не на наміри додатку. Наприклад, чекпоінт бази даних може змінити багато файлів, навіть якщо логічні дані ледь зрушилися. - Датасети ZFS можуть мати різні mountpoint’и і бути відмонтованими.
zfs diffне потребує, щоб датасет був змонтований для порівняння снапшотів; він порівнює дерева снапшотів внутрішньо. - Клони — це записувані снапшоти. Диф між снапшотом і снапшотом клону може бути чистою історією «що відхилилося» — корисно в розробці/тесті або коли прод випадково запущено на клоні (таке трапляється).
Як zfs diff працює під капотом
В загальних рисах ZFS відстежує набори об’єктів. Датасет — це набір об’єктів; снапшот — це тільки для читання, «закріплена» версія цього набору. zfs diff обходить дві версії та порівнює записи директорій і метадані об’єктів, потім виводить набір змін шляхів.
Важливий операційний наслідок: диф базується на об’єктах файлової системи, а не на світорозумінні вашого додатку. Якщо додаток перезаписує файл на місці, ви побачите модифікацію. Якщо він створює тимчасовий файл і перейменовує його поверх оригіналу, ви можете побачити модифікацію плюс поведінку перейменування залежно від того, як операція потрапила в txg і чи можлива кореляція ідентичності об’єкта.
Ще один наслідок: звітність на основі шляхів реконструюється. ZFS має номери об’єктів і структури директорій; щоб надрукувати «/var/log/messages», інструмент повинен обійти директорії і відновити імена. На величезних деревах каталогів, особливо з високою зміною, це може бути дорого. «Дорого» тут не обов’язково означає «повільний диск»; це може означати «велика кількість обходів метаданих», що перетворюється на навантаження ARC або багато випадкових читань, якщо кеш пропускається.
Одна тонкість, яку варто пам’ятати: жива файлсистема («тепер») не є снапшотом. Якщо ви запускаєте zfs diff pool/ds@snap проти живого датасету, який активно змінюється, ви просите рухому ціль. ZFS робитиме все можливе, але ваш операційний висновок має бути «це індикативно», а не «це судовий протокол». Для стабільного порівняння виконуйте diff між снапшотами.
Читання виводу без самообману
Канонічний формат виводу — однобуквений код зміни, а потім шлях. Поширені коди:
+шлях додано-шлях видаленоMшлях змінено (зміна вмісту або метаданих)Rшлях перейменовано (часто показується як «від» і «до» шляхи залежно від реалізації)
Поради щодо інтерпретації від того, хто обпалювався:
«Modified» більше, ніж «змінено вміст»
Файл може бути «змінений» через права доступу, власника, ACL, xattr, timestamp, зміну кількості жорстких посилань або вміст. Якщо ви розбираєте інцидент, вас часто цікавить зміна вмісту; якщо це питання відповідності, метадані можуть бути важливішими.
Перейменування — ваш друг, поки ним не стане
Коли перейменування виявлено, це подарунок: ви можете відстежити переміщення без паніки через видалення+створення. Але виявлення перейменувань може зламатися при неоднозначній кореляції (масивна зміна, тимчасові файли або шаблони, що ламають відображення ідентичності об’єкта). Не сприймайте відсутність R як доказ, що перейменування не відбулося; сприймайте це як «інструмент не зміг надійно це довести».
Видалення часто найцінніший сигнал
Якщо ви налагоджуєте зламаний деплой, один видалений файл у /etc може пояснити більше, ніж 5 000 «змінених» файлів у /var. Коли читаєте дифи, фільтруйте за каталогами, які відповідають вашій зоні відмови.
Жарт №2: zfs diff схожий на code review: він не вирішує проблему, але позбавляє вас можливості вдавати, що нічого не сталося.
Практичні завдання: 14 реальних команд з інтерпретацією
Усі приклади припускають датасет на кшталт tank/app зі снапшотами @pre та @post. Підлаштуйте імена під своє середовище.
Завдання 1: Порівняти два снапшоти (бейслайн)
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post
M /etc/app/app.conf
+ /var/lib/app/new-index.db
- /var/lib/app/old-index.db
R /var/log/app/old.log -> /var/log/app/old.log.1
Інтерпретація: Конфіг змінився, індекс ротувався, один файл замінено, а лог перейменовано під час ротації. Типово для оновлення пакета або обслуговування додатку.
Завдання 2: Порівняти снапшот з поточною живою файловою системою
cr0x@server:~$ sudo zfs diff tank/app@pre
M /etc/app/app.conf
+ /var/tmp/app-build-9281.tmp
Інтерпретація: «З @pre до тепер що відрізняється?» Добре для швидких перевірок «що змінилося з моменту останнього відомо-хорошого стану». Бережіть високочастотну зміну: результати можуть змінюватися під час читання.
Завдання 3: Зменшити шум, grep’ом по піддереву
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | grep '^M' | grep '^M[[:space:]]\+/etc/'
M /etc/app/app.conf
M /etc/app/limits.conf
Інтерпретація: Зменшили шум «змінних логів». Під час аварій зазвичай спочатку потрібен короткий список змін конфігів і бінарників.
Завдання 4: Порахувати зміни за типом (швидка триаж)
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | awk '{print $1}' | sort | uniq -c
82 +
10 -
911 M
4 R
Інтерпретація: 911 змінених шляхів — багато. Якщо ви очікували тільки зміну конфігу, це тривожний сигнал. Якщо очікували оновлення пакета або міграцію БД, це може бути нормою.
Завдання 5: Знайти «топ каталоги», що постраждали
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post \
| awk '{print $2}' \
| awk -F/ 'NF>2 {print "/"$2"/"$3} NF==2 {print "/"$2} NF==1 {print "/"}' \
| sort | uniq -c | sort -nr | head
640 /var/lib
210 /var/log
95 /usr/local
12 /etc/app
Інтерпретація: Більшість змін під /var/lib і /var/log. Це вказує на рух даних додатку і логування — не випадкова деградація конфігів.
Завдання 6: Перевірити, що снапшоти існують і належать одній лінії датасетів
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation | grep '^tank/app@'
tank/app@pre Mon Dec 23 11:58 2025
tank/app@post Mon Dec 23 12:12 2025
Інтерпретація: Якщо снапшоти зроблені з різних датасетів (або після rollback/clone дивергенції), дифи можуть бути безглуздими або провалюватися.
Завдання 7: Підтвердити mountpoint датасету і чи він змонтований
cr0x@server:~$ zfs get -H -o property,value mountpoint,mounted tank/app
mountpoint /app
mounted yes
Інтерпретація: Для zfs diff це не обов’язково, але потрібно, якщо плануєте безпосередньо переглядати файли (наприклад, змонтувати снапшоти через .zfs/snapshot).
Завдання 8: Переглянути змінений файл у двох снапшотах (підтвердження вмісту)
cr0x@server:~$ sudo sed -n '1,120p' /app/.zfs/snapshot/pre/etc/app/app.conf
# app.conf - baseline
max_workers=32
log_level=info
cr0x@server:~$ sudo sed -n '1,120p' /app/.zfs/snapshot/post/etc/app/app.conf
# app.conf - after deploy
max_workers=64
log_level=debug
Інтерпретація: zfs diff сказав «змінено»; це показує «як саме». В інцидентах робіть це для кількох ключових файлів.
Завдання 9: Виявити підозрілі масові перейменування (рутинно при ransomware або скриптах очищення логів)
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | grep '^R' | head
R /var/lib/app/data/part-0001 -> /var/lib/app/data/part-0001.locked
R /var/lib/app/data/part-0002 -> /var/lib/app/data/part-0002.locked
R /var/lib/app/data/part-0003 -> /var/lib/app/data/part-0003.locked
Інтерпретація: Серія однорідних перейменувань з новими розширеннями — підозріло. Може бути законний архівний процес або «швидке шифрування та перейменування» зловмисника. Ескалюйте швидко.
Завдання 10: Перевірити, чи інкрементний send має включати очікувані зміни
cr0x@server:~$ sudo zfs diff tank/app@replica-base tank/app@replica-next | head -20
M /etc/app/app.conf
+ /var/lib/app/new-index.db
Інтерпретація: Якщо ціль реплікації «не отримала зміну конфігу», порівняйте точні снапшоти, які ви відправляєте. Багато «таємниць» реплікації — це просто «ми відправили не той базовий снапшот».
Завдання 11: Корелювати диф зі використанням простору (чи ця зміна дорога?)
cr0x@server:~$ zfs list -o name,used,refer,avail,mountpoint tank/app
NAME USED REFER AVAIL MOUNTPOINT
tank/app 412G 380G 2.1T /app
cr0x@server:~$ zfs get -o name,property,value -s local,received,default usedbysnapshots,usedbydataset,usedbychildren tank/app
tank/app usedbysnapshots 31.4G
tank/app usedbydataset 380G
tank/app usedbychildren 0B
Інтерпретація: Багато «змінених» файлів не завжди означає багато нових блоків, але часто корелює. Якщо usedbysnapshots швидко зростає, зміна фіксує старі блоки.
Завдання 12: Виявити «метадані-турбулентність», яка виглядає як зміну вмісту
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | grep '^M' | grep '^M[[:space:]]\+/var/log/' | head
M /var/log/app/access.log
M /var/log/app/error.log
M /var/log/app/metrics.log
Інтерпретація: Логи змінюються — це нормально; не дозволяйте їм заглушити сигнал. Якщо потрібно знати «що змінилося в коді/конфігах», відфільтруйте відомі каталоги шуму.
Завдання 13: Підтвердити імена та порядок снапшотів, щоб уникнути плутанини «зворотнього дифа»
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/app | tail -5
tank/app@daily-2025-12-21 Sun Dec 21 00:00 2025
tank/app@daily-2025-12-22 Mon Dec 22 00:00 2025
tank/app@daily-2025-12-23 Tue Dec 23 00:00 2025
tank/app@pre Tue Dec 23 11:58 2025
tank/app@post Tue Dec 23 12:12 2025
Інтерпретація: Коли ви дифите «новіший vs старіший», можна заплутатися щодо плюс/мінус. Завжди перевіряйте час створення.
Завдання 14: Використовувати вивід zfs diff як allowlist для цілеспрямованих відновлень
cr0x@server:~$ sudo zfs diff tank/app@good tank/app@bad | awk '$1 ~ /^M|^-$/ {print $2}' | head
/etc/app/app.conf
/usr/local/bin/app
/usr/local/lib/libapp.so
cr0x@server:~$ sudo cp -a /app/.zfs/snapshot/good/usr/local/bin/app /app/usr/local/bin/app
Інтерпретація: Іноді вам не потрібен повний rollback; потрібне відновлення невеликого набору відомо-хороших файлів. Перегляд снапшоту плюс ретельно відфільтрований диф дає план, який не знищить інші добрі дані.
Три історії з корпоративного світу (з болем)
Міні-історія 1: Інцидент через неправильне припущення (снапшоти як «резерви»)
Сценарій знайомий: бізнес-критичний датасет на ZFS, погодинні снапшоти і робота реплікації на вторинну машину. Усі спали спокійно, бо «у нас є снапшоти». Команда навіть мала сторінку у вікі з фразою «snapshots = backups», яка має супроводжуватися попередженням і вогнегасником.
Потім розробник запустив скрипт очищення проти продакшену. Це не було зловмисно; просто вказали неправильну змінну середовища. Пара директорій під /var/lib/app була рекурсивно видалена. За кілька хвилин моніторинг перетворився на крик. On-call сказав те, чого ніколи не хочеться чути: «Це ок, у нас є снапшоти, я просто відкатну.»
Відкат відновив видалені дані. Він також відкотив кілька легітимних записів, зроблених після снапшоту — записи, що включали стан, видимий клієнтам. Результат був некатастрофічний, але неприємний: повторні спроби, дублювання подій і кілька годин ручної взаємодії зі службою підтримки й операціями. Постмортем не був про те, що ZFS ризиковий; він був про неправильне припущення, що «найбезпечніше» — це найшвидше.
Що допомогло в наступний раз — нудна дисципліна: перед будь-яким відкатом вони запускали zfs diff між останнім відомо-хорошим снапшотом і поточним станом. Диф показував радіус ураження. Замість відкату всього датасету вони відновили лише видалені піддерева зі снапшоту. Легітимні записи збереглися. Наступний інцидент теж не був приємним, але був локалізований — і локалізація саме те, що означає «стійкість», коли дзвінок по інциденту гучний.
Міні-історія 2: Оптимізація, що відкотилася (агресивна частота снапшотів + diff у cron)
Інша організація хотіла «майже реального часу аудиту» для ініціативи відповідності. План: робити снапшоти кожні п’ять хвилин, запускати zfs diff між двома останніми, архівувати вивід і шипити його в центральну систему. На папері елегантно. На практиці — це була невелика DoS проти їхнього власного сховища.
Перша проблема: датасет був кешем збірки з мільйонами дрібних файлів. zfs diff мусив обходити гігантські дерева директорій і відновлювати шляхи. Кожні п’ять хвилин. Це перетворилося на безперервний тиск метаданих. ARC-показники падали. Латентність росла. Розробники скаржилися, що «ZFS повільний», що рівнозначно тому, щоб звинуватити дорогу у поганому водінні.
Друга проблема: вивід був гігантський і в основному шум. Системи збірки дуже змінюють структуру. Вони створюють тимчасові файли, перейменовують, видаляють, повторюють. Команда відповідності хотіла «що змінилося», а отримала «все завжди змінюється». S/N було настільки низьким, що ніхто не дивився звіти — секретна причина провалу відповідності: можна створити нескінченну кількість доказів, які ніхто не читає.
План відновлення був прагматичний. Вони зменшили частоту снапшотів до бізнес-необхідної (погодинно для більшості, частіше лише для кількох малих датасетів). Припинили запускати дифи на шумних кешах і зосередилися на конфігураційних та записах даних. Коли запускали дифи, фільтрували за значущими піддеревами і зберігали зведення, а не кожен шлях. Оптимізація не провалилася через те, що ZFS не справляється; вона провалилася, бо робоче навантаження не заслуговувало на такий рівень дослідження.
Міні-історія 3: Нудна, але правильна практика, яка врятувала день (diff перед cutover реплікації)
Ця історія не для конференцій — вона не гламурна. Команда планувала міграцію зберігання: нові сервери, новий пул, реплікація ZFS send/receive, потім вікно cutover. Звичайний страх: «Чи буде ціль ідентичною?» і «Що якщо ми щось пропустимо?»
Вони зробили нудну річ: написали runbook, який вимагав передcutover zfs diff на замороженій парі снапшотів — один на джерелі, інший на приймачі після receive. Не «довіряти задачі реплікації», не «порівнювати вивід zfs list», а явну перевірку списку змін на репрезентативних датасетах.
Під час репетиції diff показав кілька несподіваних змін під директорією, що «ніколи не мала змінюватися». Виявилося, що один сервіс на хості-приймачі автостартував і почав писати кеш-файли в mountpoint, який мав залишатися пасивним до cutover. Сама реплікація була нормальною; проблема була у середовищі.
Вони виправили порядок сервісів, повторили репетицію, і diff замовк. В ніч cutover усе пройшло буденно — в найкращий спосіб. Нудна практика — дифати снапшоти, що репрезентують «source-of-truth» та «received-as-truth» — зловила реальну відмінність до того, як вона стала полем бою за цілісність даних.
План швидкої діагностики
Коли потрібні швидкі відповіді, не починайте з тисяч рядків diff. Почніть з кількох перевірок, що звужують проблему до «очікувана зміна», «неочікувана зміна», «проблема інструменту» або «вузьке місце продуктивності».
Крок 1: Підтвердити, що ви порівнюєте правильні снапшоти
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/app | tail -10
Дивіться за: Чи правильні імена снапшотів? Чи в порядку, який ви думаєте? Хтось робив rollback і перегенерував снапшоти з плутаними іменами?
Крок 2: Визначити, чи це «чурн даних» чи «чурн контрольної площини»
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post | awk '{print $2}' | head
Потім негайно: підсумуйте, де це відбувається.
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@post \
| awk '{print $2}' \
| awk -F/ 'NF>2 {print "/"$2"/"$3} NF==2 {print "/"$2} NF==1 {print "/"}' \
| sort | uniq -c | sort -nr | head -15
Шукайте: Більшість під /var/log і /var/tmp (зазвичай шум) проти /etc, /usr і каталогів даних додатку (зазвичай значущі).
Крок 3: Якщо продуктивність — вузьке місце, перевірте, чи ви прив’язані до метаданих
cr0x@server:~$ arcstat 1 5
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:00:01 210 88 41 60 28 22 10 6 2 128G 192G
Інтерпретація: Високі показники пропусків під час запуску diff вказують, що метадані не в ARC і система виконує реальну роботу обходу директорій. Якщо у вас немає arcstat, використайте нативну телеметрію ОС по IO і пам’яті; шаблон той самий: CPU + випадкові читання + промахи кешу.
Крок 4: Перевірити властивості датасету, що змінюють значення «modified»
cr0x@server:~$ zfs get -o name,property,value atime,recordsize,compression,acltype,xattr,overlay,encryption tank/app
Дивіться за: atime=on може створювати метадані-турбулентність. ACL та поведінка xattr можуть породжувати хвилі «змін» по багатьох файлах.
Крок 5: Якщо диф величезний, вирішіть, чи потрібне зведення, чи хірургічна відповідь
На дзвінку по інциденту вам зазвичай не потрібні всі шляхи. Потрібно: «Чи щось змінилося під /etc?», «Чи змінилися бінарні файли під /usr/local/bin?», «Чи були файли видалені під директорією даних?» Це завдання фільтрації, а не повна інвентаризація.
Поширені помилки (симптоми та виправлення)
Помилка 1: Діф по неправильному датасету через схожі mountpoint’и
Симптом: zfs diff повідомляє зміни, що не відповідають тому, що ви бачили на диску, або ви не можете знайти шляхи у живій файловій системі.
Причина: Кілька датасетів змонтовані під схожими шляхами або було змінено legacy mountpoint. Ви зробили diff tank/app, а дивилися на tank/app/data (або навпаки).
Виправлення: Підтвердіть mountpoint’и і межі датасетів.
cr0x@server:~$ zfs list -o name,mountpoint -r tank/app
NAME MOUNTPOINT
tank/app /app
tank/app/data /app/data
Помилка 2: Сприймати diff «снапшот->живий» як стабільну істину під час активного запису
Симптом: Ви повторно запускаєте той самий diff і результати змінюються; бачите тимчасові файли, які з’являються/зникають; не можете звірити підрахунки.
Причина: Жива файлсистема змінюється під час порівняння зі фіксованим снапшотом.
Виправлення: Зробіть другий снапшот і порівняйте снапшот->снапшот.
cr0x@server:~$ sudo zfs snapshot tank/app@now
cr0x@server:~$ sudo zfs diff tank/app@pre tank/app@now | head
Помилка 3: Припускати, що «M» означає «змінено вміст файлу»
Симптом: Система безпеки сповіщає «тисячі змінених файлів» після скану, але поведінка додатку нормальна.
Причина: Метадані (ACL, xattr, timestamp) також вважаються змінами.
Виправлення: Перевірте контрольну суму вмісту на вибірковій вибірці або подивіться, які каталоги змінюються. Також перевірте, чи не змінилися політики ACL або розширені атрибути.
Помилка 4: Забувати, що видалення може бути замасковане пізнішим відтворенням
Симптом: Інцидент вказує, що файл був видалений, але поточна файлсистема має файл за тим шляхом.
Причина: Файл був видалений і пізніше відновлений (можливо з іншим вмістом/власником). Залежно від таймінгів і поведінки додатку, диф може показати модифікацію або delete+add замість чистої історії.
Виправлення: Використайте перегляд снапшоту, щоб інспектувати «історію inode» по вмісту і метаданих у обох точках часу. Розглядайте шлях як «змінений», а не «та сама назва означає той самий файл».
Помилка 5: Запускати величезні diff’и у проді в найгірший час
Симптом: Під час zfs diff відбуваються стрибки латентності, користувачі скаржаться, монітори горять червоним.
Причина: Метадантажевий обхід може конкурувати з навантаженням за ARC і IO. Для деяких датасетів це фактично read storm.
Виправлення: Запускайте diff у непіковий час, дифте менші піддерева (фільтруйте вивід) або виконуйте diff на хості-репліці, якщо можливо. Якщо потрібно робити це у проді — тримайте це коротким і цілеспрямованим.
Помилка 6: Плутати «відсутність виводу» з «відсутністю змін», коли права блокують видимість
Симптом: Ви отримуєте помилки, обрізаний вивід або несподівано порожні результати, коли ви знаєте, що зміни були.
Причина: Недостатні привілеї для обходу снапшотів чи внутрішніх структур датасету, особливо на захищених системах.
Виправлення: Запустіть як root (або з відповідними делегованими дозволами ZFS). Підтвердіть, що датасет доступний і що каталоги снапшотів не обмежені опціями монтування або рамками безпеки.
Чеклісти / покроковий план
Чекліст: «Що змінилося з моменту останнього відомо-хорошого деплою?»
- Визначте останній відомо-хороший снапшот (зазвичай зроблений перед деплоєм).
- Зробіть снапшот «now», якщо система все ще змінюється.
- Запустіть
zfs diffміж снапшотами. - Підсумуйте зміни за типом і по каталогах.
- Перегляньте короткий список важливих шляхів: конфігурації, бінарники, unit-файли сервісів і секрети.
- Прийміть рішення: відкат, селективне відновлення чи виправлення в майбутньому.
cr0x@server:~$ sudo zfs snapshot tank/app@now
cr0x@server:~$ sudo zfs diff tank/app@predeploy tank/app@now | awk '{print $1}' | sort | uniq -c
cr0x@server:~$ sudo zfs diff tank/app@predeploy tank/app@now | grep -E '^[M+-][[:space:]]+/(etc|usr|opt)/' | head -200
Порада для рішення: Якщо зміни концентровані в даних додатку і логах, відкат може знищити легітимний стан. Якщо зміни в бінарниках/конфігах — відкат безпечніший.
Чекліст: «Селективне відновлення без повного відкату»
- Диф між відомо-хорошим і поганим снапшотом і витягніть видалені/зміненні файли у критичних каталогах.
- Перевірте наявність і цілісність копій у снапшоті.
- Відновіть за допомогою
cp -a(абоrsync -aHAX, якщо доступно) з.zfs/snapshot. - Перезапустіть сервіс і перевірте знову.
- Документуйте точно, що відновлено (наступна людина обов’язково спитає).
cr0x@server:~$ sudo zfs diff tank/app@good tank/app@bad | grep -E '^[M-][[:space:]]+/(etc/app|usr/local/bin)/' | head -50
cr0x@server:~$ sudo cp -a /app/.zfs/snapshot/good/etc/app/app.conf /app/etc/app/app.conf
cr0x@server:~$ sudo cp -a /app/.zfs/snapshot/good/usr/local/bin/app /app/usr/local/bin/app
Чекліст: «Перевірка коректності реплікації перед cutover»
- Виберіть конкретне ім’я снапшоту, яке існує і на джерелі, і на призначенні після receive.
- Порівняйте diff репрезентативних датасетів: базовий снапшот джерела vs снапшот перед cutover; потім перевірте, що на приймачі є той самий снапшот і він лишається спокійним.
- Переконайтеся, що на приймачі ніякі процеси не записують у mountpoint’и до cutover.
cr0x@server:~$ zfs list -t snapshot -o name | grep '^tank/app@cutover$'
cr0x@server:~$ sudo zfs diff tank/app@baseline tank/app@cutover | head
Питання й відповіді
1) Чи показує zfs diff вміст файлів?
Ні. Він повідомляє змінені шляхи і тип зміни (додано/видалено/змінено/перейменовано). Щоб побачити вміст, перегляньте каталоги снапшотів і використайте текстові інструменти або обчисліть хеші обох версій.
2) Чи можна дифити снапшоти з різних датасетів?
Не в сенсі «порівняти довільні дерева». zfs diff призначений для снапшотів в межах однієї лінії датасетів. Якщо потрібне крос-дataset порівняння, змонтуйте обидва снапшоти і використайте зовнішні інструменти (з типовими застереженнями по продуктивності і коректності).
3) Чому після скану безпеки я бачу тисячі записів M?
Тому що «modified» включає метадані, і скани можуть торкатися atime або xattr залежно від конфігурації. Перевірте atime і чи сканер не записує розширені атрибути чи теги карантину.
4) Чому zfs diff повільний на цьому датасеті?
Найгірший випадок — великі дерева директорій з великою кількістю дрібних файлів і високою зміною. Інструмент мусить обходити і відновлювати шляхи, що дуже важко для метаданих. Якщо ARC холодний, він виконає реальний IO. Спочатку підсумуйте, відфільтруйте піддерева і розгляньте запуск дифів на хості-репліці.
5) Чи завжди перейменування показується як R?
Ні. Виявлення перейменування залежить від здатності інструмента корелювати ідентичність об’єкта і зміни структури директорій. Якщо довести перейменування не можна, ви можете побачити видалення плюс додавання. Сприймайте це як «щось перемістилося або було замінено», потім підтвердіть переглядом снапшотів.
6) Чи можна використовувати zfs diff для виявлення ransomware?
Це хороший ранній сигнал: масові модифікації, однорідні перейменування, раптові хвилі видалень. Але він не скаже, який процес це зробив. Поєднуйте з політиками незмінності снапшотів, контролем доступу і телеметрією на хості.
7) Що безпечніше в інциденті: відкат чи селективне відновлення?
Відкат швидкий і чистий, коли датасет переважно код/конфіг і система може терпіти відкат стану. Селективне відновлення безпечніше, коли датасет містить живі записи даних. Використовуйте zfs diff, щоб вирішити, замість здогадок.
8) Чи змінює шифрування принцип роботи дифів?
Концептуально — ні. Ви все ще дифите дерева снапшотів усередині датасету. Операційно — переконайтеся, що у вас завантажені ключі і є права для обходу датасету і снапшотів; інакше отримаєте помилки або неповну видимість.
9) Як уникнути шуму, коли цікавить тільки дрейф конфігурацій?
Фільтруйте вивід дифа по цікавих каталогах (/etc, unit-файли сервісів, конфіг додатку). Також розгляньте розділення датасетів: помістіть логи і кеші в окремі датасети, щоб дифи на «конфіг-датасеті» лишалися читабельними.
10) Чи можна автоматизувати zfs diff для трекінгу аудиту?
Так, але обережно: часті дифи на шумних датасетах можуть створити самонанесене навантаження і генерувати марний шум. Підсумовуйте і націлюйте вивід на значущі піддерева.
Висновок
zfs diff — інструмент, до якого ви звертаєтеся, коли важливий таймлайн і коли вгадування вичерпано. Він перетворює снапшоти з «ми можемо відкотитися» на «ми можемо точно пояснити, що сталося», а це зовсім інша, потужніша здатність.
Використовуйте його як оператор: переконайтеся, що ви дифите правильні снапшоти, підсумуйте перед тим, як заглиблюватись, фільтруйте агресивно і підтверджуйте шляхи із великим впливом, переглядаючи вміст снапшотів. І коли він повільний або шумний — сприймайте це як інформацію про дизайн датасету й рівень churn, а не як особисту образу від файлової системи.