ZFS mountpoint: пастка монту, що змушує датасети «зникати»

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

ZFS насправді не «втрачає» ваші датасети. Він просто дуже вправно змушує вас відчувати, що це сталося. Однієї миті ваші дані під /srv/app, наступної — вони «зникли», сервіс порожній, а ви намагаєтесь згадати, чи не розгнівали ви богів сховища.

Це і є пастка монту: дивовижно звичайний набір поведінок — перекриття монту, legacy mountpoints, налаштування canmount, порядок завантаження та кілька корисних, але підступних засобів автоматизації — які можуть сховати цілком здоровий датасет за іншим файловим системним шаром. У продакшні це може виглядати цілком як втрата даних, доки ви не пригадаєте одне правило: у Unix останній mount перемагає.

Що таке пастка монту (і чому вона обманює розумних людей)

Пастка монту виникає, коли ZFS датасет змонтований у місці, де ви його не очікували, — або коли він не може змонтуватися там, де ви очікуєте, — тому що шлях монту вже зайнято. Інша файлова система (інший ZFS датасет, tmpfs, старий розділ ext4, bind-монт контейнера, systemd unit — будь-хто) змонтована «на верху» директорії, де ви думали, що розташований ваш датасет.

З терміналу це виглядає, ніби ваші дані зникли:

  • ls показує порожню директорію.
  • Додатки починають створювати нові директорії та файли, щасливо, не там, де треба.
  • «Відсутні» дані з’являються знову, якщо ви відмонтуєте накриваючу файлову систему — або зникають знову, коли щось монтується при старті.

Ось чому пастка така переконлива: це не баг ZFS. Це ядро робить саме те, що має робити. Датасет все ще існує, далі коректний, далі прив’язаний до пулу. Він просто наразі невидимий за шляхом, на який ви дивитесь.

Перша жартівлива ремарка (обов’язкова, коротка і заслужена): ZFS не з’їв ваші дані; він просто накрив їх ковдрою і поспостерігав, як ви панікуєте.

Що на практиці зазвичай означає «зникнення»

Здебільшого одне з цього є правдою:

  • Датасет змонтований, але не там, де ви думаєте (mountpoint змінився або успадкований).
  • Датасет не змонтований, бо ZFS було наказано не монтувати його (canmount=off або noauto).
  • Датасет має mountpoint=legacy, тому ZFS не буде його монтувати, якщо це не зробить /etc/fstab (або еквівалент дистрибутива).
  • Датасет прагне змонтуватися в шлях, який вже є mountpoint для чогось іншого (перекриття).
  • Пул імпортувався, але монтування не вдалося через відсутність ключів (шифрування), відсутність директорій для монту або порядок завантаження.

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

Як насправді працює монтування ZFS

ZFS датасети — це файлові системи з властивостями. Властивість, що у центрі нашої драми, — це mountpoint, у парі з canmount. Розуміння взаємодії — це половина битви; інша половина — пам’ятати, що ZFS живе в ширшому ОС, який може монтувати інші речі коли йому заманеться.

Три стовпи: mountpoint, canmount і «хто монтує»

mountpoint — це шлях, куди ZFS змонтує датасет, якщо його монтує ZFS. Поширені значення:

  • Реальний шлях, наприклад /srv/db
  • none (ніколи не монтувати)
  • legacy (ZFS делегує традиційним механізмам монтування, як-от /etc/fstab)

canmount контролює, чи може датасет бути змонтований:

  • on: дозволено монтування (за замовчуванням)
  • off: ніколи не монтувати (навіть якщо вказано mountpoint)
  • noauto: не монтувати автоматично при завантаженні, але дозволяти ручне zfs mount

Хто монтує залежить від інтеграції з ОС. На багатьох системах монтування ZFS керують init-скрипти або systemd-сервіси, які запускаються після імпорту пулу. Для датасетів з legacy це роблять системні mount-юніти або mount -a. В платформах з контейнерами простори імен монту й bind-монти можуть додати другий шар «він змонтований, просто не там, де ви дивитесь».

Перекриття: закон Unix, що спричиняє більшість «фокусів на зникнення»

Коли ви монтуєте файлову систему B у директорію /srv/app, те, що раніше було видно в /srv/app, ховається доти, доки ви не відмонтуєте B. Це включає:

  • файли, створені в цій директорії на root-файловій системі,
  • або попередній mount (наприклад ваш ZFS датасет),
  • або bind-монт з іншого місця.

Це не специфічно для ZFS; це поведінка VFS. ZFS просто полегшує створення багатьох монтуваних файлових систем, тому випадкове їх наслаювання відбувається частіше.

Друга жартівлива ремарка (також обов’язкова, коротка): якби монти мали додаток для знайомств, в їхньому описі було б «Я ховаю речі».

Успадкування: тихий підступ

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

  • pool/services змонтовано в /srv
  • pool/services/app змонтовано в /srv/app
  • pool/services/app/logs змонтовано в /srv/app/logs

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

legacy mountpoints: старий контроль, нова плутанина

mountpoint=legacy означає: «ZFS, не монтуй автоматично. Я все зроблю через системний механізм монтування». Це іноді використовується для строгого контролю, спецічного порядку або сумісності з інструментами управління.

Пастка: якщо ви покладаєтесь на legacy, але запис у /etc/fstab відсутній, некоректний або затримується під час завантаження, датасет буде існувати, але не змонтований. Тим часом директорія — просто директорія, тож ваш додаток починає писати туди, ніби нічого не сталося.

Цікаві факти та історичний контекст

Трохи контексту допомагає, бо поведінка монтування ZFS не випадкова — це результат рішень, що приймалися десятиліттями.

  1. ZFS з’явився в Sun у середині 2000-х з ідеєю, що «файлові системи дешеві» і їх слід керувати як датасетами, а не як розділами.
  2. На відміну від традиційних файлових систем, ZFS заохочує багато mountpoint’ів (по одному на датасет), що збільшує площу для помилок у порядку монтування.
  3. legacy mountpoint існує здебільшого для сумісності зі старими Unix-інструментами монтування і послідовностями завантаження, де ZFS не був менеджером файлової системи за замовчуванням.
  4. canmount=noauto стало популярним у boot-середовищах, щоб кілька датасетів могли співіснувати без одночасного монтування всіх.
  5. Перекриття монту існує задовго до ZFS; це фундаментальна поведінка Unix VFS. ZFS просто робить випадкові сценарії перекриття легшими для створення.
  6. Багато «загублених» інцидентів на ранніх розгортаннях ZFS були проблемами видимості: датасети існували, але були сховані через помилкові монти або неімпортовані пули.
  7. OpenZFS поширився на Linux, illumos і BSD, і кожна платформа інтегрувала монтування під час завантаження по-різному — ті самі властивості, різна хореографія.
  8. Шифрування додало новий режим відмови: датасети можуть бути присутніми й здоровими, але не змонтованими, бо ключі не були завантажені під час завантаження.

Симптоми: «зникнення» датасетів у реальному світі

В інцидент-револьті «датасет зник» зазвичай приходить загорнутий в один з цих кейсів:

Симптом 1: Директорія порожня (або виглядає щойно створеною)

Ви cd до /srv/app і вона порожня, хоча має містити гігабайти. Або гірше: там інший набір файлів, створених нещодавно додатком, що не отримав записку.

Симптом 2: Датасет існує в метаданих ZFS

zfs list показує датасет з ненульовим used розміром і, можливо, очікуваним mountpoint. Але на шляху дані не відображаються.

Симптом 3: Після перезавантаження проблема з’являється (або зникає)

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

Симптом 4: Використання диску не відповідає тому, що ви бачите

zfs list вказує сотні гігабайт used, але du на точці монтування показує майже нічого. Або навпаки: df показує, що невелика root-файлова система заповнюється, бо додаток писав у базову директорію.

Симптом 5: Контейнери бачать інше, ніж хост

Простори імен монту означають, що хост може мати датасет змонтованим, тоді як контейнер бачить порожню директорію (або інший bind-монт). Це особливий різновид «він зник», часто звалюють на ZFS, бо люди впізнають цю назву.

Практичні завдання: команди, які можна виконати сьогодні

Це завдання придатні для продакшну й я реально використовував їх у стресових ситуаціях. Кожне містить, що означає вивід і яке рішення воно дає. Команди припускають Linux з OpenZFS; підлаштуйте шляхи під вашу ОС.

Завдання 1: Перелік датасетів і їх mountpoint’ів (базова реальність)

cr0x@server:~$ zfs list -o name,used,avail,mountpoint,canmount -r tank
NAME               USED  AVAIL  MOUNTPOINT      CANMOUNT
tank               320G  1.4T   /tank           on
tank/services      210G  1.4T   /srv            on
tank/services/app  180G  1.4T   /srv/app        on
tank/services/db    30G  1.4T   /srv/db         on

Інтерпретація: Якщо датасет має реальний mountpoint і canmount=on, ZFS має намір змонтувати його. Якщо він не видимий, підозрюйте перекриття або помилку монтування.

Завдання 2: Подивитися, що ZFS вважає наразі змонтованим

cr0x@server:~$ zfs mount
tank
tank/services
tank/services/app
tank/services/db

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

Завдання 3: Підтвердити, що ядро змонтовано в цьому шляху (виявлення перекриттів)

cr0x@server:~$ findmnt -T /srv/app
TARGET   SOURCE              FSTYPE OPTIONS
/srv/app tank/services/app   zfs    rw,xattr,noacl

Інтерпретація: Це найкорисніша команда для пастки монту. Якщо findmnt показує щось інше (ext4, overlayfs, tmpfs), ваш ZFS датасет ховається.

Завдання 4: Показати всі монтування, які можуть насладуватися в тому дереві

cr0x@server:~$ findmnt -R /srv
TARGET         SOURCE             FSTYPE OPTIONS
/srv           tank/services      zfs    rw,xattr
└─/srv/app     tank/services/app  zfs    rw,xattr
└─/srv/db      tank/services/db   zfs    rw,xattr

Інтерпретація: Якщо ви бачите несподівані записи (наприклад /srv/app як overlayfs), ви знайшли причину приховування.

Завдання 5: Перевірити, чи датасет встановлено в legacy (поширений «чому не змонтувався?»)

cr0x@server:~$ zfs get -H -o name,property,value,source mountpoint tank/services/app
tank/services/app  mountpoint  legacy  local

Інтерпретація: При legacy ZFS не монтує авто. Якщо у вас немає відповідного OS-запису для монту, ваш сервіс писатиме в базову директорію.

Завдання 6: Перевірити canmount (перемикач «є, але не монтується»)

cr0x@server:~$ zfs get -H -o name,property,value,source canmount tank/services/app
tank/services/app  canmount  noauto  local

Інтерпретація: noauto означає, що при завантаженні він не монтується автоматично; потрібно змонтувати вручну (або через інструменти). off означає, що не монтується взагалі, поки ви не зміните його.

Завдання 7: Спробувати ручне монтування і прочитати помилку (не вгадуйте)

cr0x@server:~$ sudo zfs mount tank/services/app
cannot mount 'tank/services/app': mountpoint or dataset is busy

Інтерпретація: «Busy» часто означає, що /srv/app вже є mountpoint для чогось іншого. Це сценарій перекриття. Запустіть findmnt -T /srv/app, щоб ідентифікувати «винуватця».

Завдання 8: Визначити, що займає mountpoint

cr0x@server:~$ findmnt -T /srv/app -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET   SOURCE                 FSTYPE    OPTIONS
/srv/app /dev/nvme0n1p2[/app]   ext4      rw,relatime

Інтерпретація: Ви зовсім не дивитесь на ZFS; ext4 змонтовано там. Ваш датасет не зник — ваш mountpoint зайнятий.

Завдання 9: Знайти датасет, скануючи mountpoint’и (коли підозрюєте, що він змонтований десь ще)

cr0x@server:~$ zfs list -o name,mountpoint -r tank | grep app
tank/services/app  /srv/app

Інтерпретація: Якщо тут mountpoint правильний, але ядро показує щось інше за тим шляхом, у вас конфлікт монтування.

Завдання 10: Виявити підкладені «тіньові» дані, записані коли датасет не був змонтований

cr0x@server:~$ sudo zfs unmount tank/services/app
cr0x@server:~$ ls -lah /srv/app | head
total 56K
drwxr-xr-x  14 root root 4.0K Dec 24 09:10 .
drwxr-xr-x   6 root root 4.0K Dec 24 09:09 ..
-rw-r--r--   1 root root 2.1K Dec 24 09:10 app.log
drwxr-xr-x   2 root root 4.0K Dec 24 09:10 cache

Інтерпретація: Ці файли знаходяться на базовій файловій системі (часто вашому root-диску), створені тоді, коли ZFS не було змонтовано. Ось як root-диски таємниче заповнюються під час помилки монтування ZFS.

Завдання 11: Перевірити імпорт пулу та сервіси монтування (збої під час завантаження)

cr0x@server:~$ systemctl status zfs-import-cache zfs-mount
● zfs-import-cache.service - Import ZFS pools by cache file
     Loaded: loaded (/lib/systemd/system/zfs-import-cache.service; enabled)
     Active: active (exited)
● zfs-mount.service - Mount ZFS filesystems
     Loaded: loaded (/lib/systemd/system/zfs-mount.service; enabled)
     Active: failed (Result: exit-code)

Інтерпретація: Пул імпортований, але монтування ZFS провалилося. Не гнівіться на датасет; гнатися треба за логами сервісу і причиною відмови.

Завдання 12: Прочитати причину помилки монтування в логах

cr0x@server:~$ journalctl -u zfs-mount -b --no-pager | tail -n 20
Dec 24 09:01:12 server zfs[1123]: cannot mount 'tank/services/app': directory is not empty
Dec 24 09:01:12 server systemd[1]: zfs-mount.service: Main process exited, code=exited, status=1/FAILURE

Інтерпретація: «Directory is not empty» зазвичай підказка, що хтось створив файли до монтування ZFS, або що інший mount/bind займає цей шлях. Це також може означати, що ваше ZFS-інструментальне забезпечення не дозволяє монтувати зверху непорожню директорію автоматично.

Завдання 13: Перевірити, чи завантажені ключі шифрування (невидима причина «не змонтовано»)

cr0x@server:~$ zfs get -H -o name,property,value keystatus,encryptionroot tank/services/app
tank/services/app  keystatus       unavailable
tank/services/app  encryptionroot  tank

Інтерпретація: Якщо keystatus unavailable, датасет може існувати, але не монтуватися. Завантажте ключ, потім змонтуйте.

Завдання 14: Завантажити ключ і змонтувати (обережно)

cr0x@server:~$ sudo zfs load-key -a
cr0x@server:~$ sudo zfs mount -a
cr0x@server:~$ zfs get -H -o name,property,value keystatus tank/services/app
tank/services/app  keystatus  available

Інтерпретація: Якщо це вирішує проблему, ваше «зникнення датасету» було пов’язане з управлінням ключами/порядком завантаження, а не з властивістю mountpoint.

Завдання 15: Знайти властивості, що успадковуються, і локальні (щоб виявити несподівані зміни)

cr0x@server:~$ zfs get -r -o name,property,value,source mountpoint,canmount tank/services | sed -n '1,8p'
NAME              PROPERTY    VALUE     SOURCE
tank/services     mountpoint  /srv      local
tank/services     canmount    on        default
tank/services/app mountpoint  /srv/app  inherited from tank/services
tank/services/app canmount    on        default

Інтерпретація: Якщо дитина успадковує mountpoint, зміна батька змінить ефективний mountpoint дитини. Це і сила, і небезпека в одному рядку.

Завдання 16: Безпечно змінити mountpoint (і перевірити)

cr0x@server:~$ sudo zfs set mountpoint=/srv/app2 tank/services/app
cr0x@server:~$ sudo zfs mount tank/services/app
cr0x@server:~$ findmnt -T /srv/app2
TARGET     SOURCE             FSTYPE OPTIONS
/srv/app2  tank/services/app  zfs    rw,xattr

Інтерпретація: ZFS спрощує зміну mountpoint, але ви повинні підтвердити, що новий шлях не зайнятий, і оновити додатки, записи в fstab (якщо legacy) та моніторинг.

Три міні-історії з корпоративного світу

1) Інцидент через неправильне припущення: «Датасет порожній, значить деплой його стер»

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

Хтось почав відкат. Хтось інший готував оновлення інциденту з фразами «незворотне видалення» та «відновлення з бекапів». До справи підключили інженера зі сховища, який задав спокійне питання, що зруйнувало наратив: «Що каже findmnt про цей шлях?»

Виявилось, що шлях мав два монти, які змагалися за ту саму директорію. На сервері був старий розділ ext4, ще прописаний в systemd mount unit, і він монтувався пізно в процесі завантаження — одразу після того, як ZFS успішно змонтував датасет. ext4-монт нічого не видалив; він просто накрив ZFS-монт. Дані нікуди не поділися. Вони були просто сховані за файловою системою з минулої епохи хоста.

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

2) Оптимізація, що обернулась проти: «Давайте використаємо mountpoint=legacy для більшого контролю»

Платформна команда хотіла детермінованих монтувань. Вони втомилися від «магії» і прагнули явності: поставити ZFS датасети в mountpoint=legacy, а потім керувати всім у /etc/fstab, щоб системний механізм вирішував порядок. На папері виглядало як хороша інженерія: одне місце для монтувань, один спосіб монтувати все, легкий аудит.

На практиці це була оптимізація для людей за рахунок надійності. Під час технічного вікна вони перейменували датасет і оновили сторону ZFS, але пропустили відповідний рядок в fstab на двох серверах. Ці два сервери завантажились «нормально», але датасет не змонтувався. Директорія існувала, тому додаток стартував і почав писати в underlying root-файлову систему. За години root-диски заповнилися, journald почав скидати логи, і інцидент перетворився з «чому немає метрик?» на «чому вузли помирають?»

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

Постмортем результат не був «ніколи не використовувати legacy». Було вирішено: використовувати legacy лише коли можна довести, що монтування гарантується (через залежності systemd, ранні перевірки при завантаженні і моніторинг), і коли ваша операційна модель враховує режим відмови: додаток пише не туди, куди потрібно.

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

В іншій компанії кластер бази даних працював на ZFS датасетах з ретельно продуманими mountpoint’ами. Вони вже мали надто багато страшних ранків, коли пул імпортувався, але датасет не змонтувався через затримки завантаження ключів. Тому вони впровадили нудну перевірку, що запускалася на кожному вузлі після завантаження і після змін конфігурації: перевірити, що конкретні шляхи підкріплені очікуваним джерелом файлової системи.

Перевірка не питала ZFS, що він має намір зробити. Вона питала ядро, що воно фактично зробило: findmnt -T /var/lib/postgresql, і порівнювала джерело з очікуваним датасетом. Якщо воно не збігалося, вузол позначали як нездоровий і виводили з обслуговування до приходу трафіку. Нічого складного. Жодного AI. Просто відмова працювати з станом, коли монтування неоднозначне.

Одного дня рутинне оновлення ОС додало новий tmpfs для legacy-шляху, який використовував агент. Він випадково впав на батьківський каталог і затіняв дочірній mount. Вузол повернувся після ребута, і ZFS- монти з вигляду були «ок», але перевірка шляху відпала миттєво. Вузол ніколи не долучився до кластера. Ніякого розбіжності даних, ніякого екстреного відновлення, ніякої пожежі «чому root повний?».

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

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

Ось порядок, який я використовую, коли датасет «відсутній». Мета — швидкість: звузити коло пошуку за п’ять хвилин, а тоді вирішити, чи маєте ви справу з перекриттям, помилкою монтування чи проблемою видимості через простори імен/завантаження.

Крок 1: Запитайте ядро, що змонтовано за шляхом

cr0x@server:~$ findmnt -T /srv/app -o TARGET,SOURCE,FSTYPE,OPTIONS
TARGET   SOURCE             FSTYPE OPTIONS
/srv/app tank/services/app  zfs    rw,xattr

Якщо це не ZFS: у вас перекриття або неправильний монт. Ідентифікуйте і приберіть/перемістіть монту, що займає шлях.

Крок 2: Запитайте ZFS, чи вважає він, що датасет змонтований

cr0x@server:~$ zfs mount | grep -F tank/services/app || echo "not mounted"
not mounted

Якщо він не змонтований: перевірте canmount, mountpoint, стан ключів шифрування і логи. Не припускайте, що це описка в mountpoint, поки не перевірили нудні речі.

Крок 3: Перевірити властивості mount та успадкування датасету

cr0x@server:~$ zfs get -H -o property,value,source mountpoint,canmount tank/services/app
mountpoint  /srv/app  local
canmount    on        default

Якщо mountpoint=legacy: йдіть до монтувань ОС. Якщо canmount=off/noauto: перевірте логіку монтування і скрипти завантаження.

Крок 4: Шукати помилки монтування в логах (не відмахуйтесь)

cr0x@server:~$ journalctl -u zfs-mount -b --no-pager | tail -n 50

Поширені підказки: «directory is not empty», «mountpoint busy», ключ недоступний, проблеми з дозволами в директорії монту, або відсутній батьківський mount.

Крок 5: Перевірити тіньові дані і запобігти розбіжностям

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

Крок 6: Лише потім турбуйтесь про продуктивність

Люди швидко переходять до «ZFS повільний», коли справжня проблема — «ви пишете на root-диск». Діагностика продуктивності на неправильній файловій системі — чудовий спосіб стати надзвичайно зайнятим і радикально помилковим.

Типові помилки, симптоми та виправлення

Помилка 1: Колізія mountpoint’ів (дві файлові системи хочуть одну директорію)

Симптоми:

  • zfs mount падає з «dataset is busy»
  • findmnt -T /path показує ext4/tmpfs/overlayfs замість ZFS
  • Дані «повертаються» після відмонтування чогось несуміжного

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

Помилка 2: mountpoint=legacy без робочого запису в ОС

Симптоми:

  • zfs list показує датасет, але zfs mount не монтує його
  • Додатки пишуть в базові директорії; root-файлова система заповнюється

Виправлення: Або (a) додайте правильну конфігурацію монту в ОС, або (b) змініть на нормальний mountpoint і дайте ZFS керувати:
set mountpoint=/desired/path і переконайтесь, що canmount=on. Потім підтвердьте через findmnt.

Помилка 3: canmount=off або noauto без автоматизації ручного монтування

Симптоми:

  • Датасет ніколи не монтується після перезавантаження
  • Ручний zfs mount dataset працює (для noauto)

Виправлення: Якщо потрібно, щоб датасет монтувався при завантаженні, виставте canmount=on. Якщо потрібен noauto (boot environments, staging datasets), забезпечте systemd-юніт, що змонтує його перед запуском сервісів.

Помилка 4: Батьківський mountpoint змінено, і діти успадкували нову реальність

Симптоми:

  • Кілька датасетів «перемістилися» одночасно
  • Спроби монтування провалюються через колізії у шляхах, що успадковані

Виправлення: Перегляньте успадкування через zfs get -r mountpoint. Встановіть явні mountpoint’и для дочірніх датасетів, які мають бути стабільними, або перерахуйте дерево датасетів так, щоб воно відповідало вашому макету директорій.

Помилка 5: Ключі шифрування не завантажені під час завантаження

Симптоми:

  • Датасет існує, keystatus=unavailable
  • Монтування не вдається доти, поки хтось не виконає zfs load-key

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

Помилка 6: Контейнери та простори імен монту ховають правду хоста

Симптоми:

  • Хост бачить датасет змонтованим; контейнер бачить порожню директорію
  • Відкриття контенту різниться залежно від того, де ви виконуєте ls

Виправлення: Перевіряйте монти всередині простору імен контейнера, а не тільки на хості. Переконайтесь, що bind-монти посилаються на правильний шлях хоста і що шлях хоста під час старту контейнера підкріплений очікуваним ZFS датасетом.

Контрольні списки / покроковий план

Контрольний список A: Коли дані «зникають» з точки монту

  1. Запустіть findmnt -T /path, щоб побачити реальну файлову систему на цьому шляху.
  2. Запустіть zfs mount та zfs list -o name,mountpoint,canmount для датасету.
  3. Якщо zfs mount падає, прочитайте помилку; не імпровізуйте.
  4. Перевірте zfs get mountpoint,canmount і чи значення успадковані.
  5. Перевірте логи на предмет відмов сервісу монтування.
  6. Зупиніть додатки, що пишуть у шлях, поки монтування не виправлено.
  7. Якщо датасет не був змонтований, перевірте наявність тіньових даних в underlying директорії після її відмонтування/переконання, що вона відмонтувана.
  8. Тільки після того, як видимість стане коректною, відновлюйте сервіси і перевіряйте стан додатку.

Контрольний список B: Безпечна міграція mountpoint’у (зміни в продакшн)

  1. Виберіть новий шлях, який наразі не є mountpoint’ом: перевірте через findmnt -T.
  2. Зупиніть сервіси, що пишуть у датасет.
  3. Підтвердьте, що датасет здоровий і змонтований там, де ви думаєте.
  4. Змініть mountpoint: zfs set mountpoint=/new/path dataset.
  5. Змонтуйте явно: zfs mount dataset і перевірте через findmnt.
  6. Оновіть конфіг додатка, systemd-юніти, bind-монти контейнерів, бекапи і перевірки моніторингу.
  7. Запустіть сервіси і перевірте, що записи потрапляють на ZFS (спостерігайте за used у zfs list, а не лише за логами додатку).
  8. Очистіть старі директорії на underlying файловій системі, якщо вони накопичили тіньові файли.

Контрольний список C: Запобігання пастці (нудні запобіжні заходи, що працюють)

  1. Моніторити реальність монтувань: для критичних шляхів — алерт, якщо findmnt -T source не збігається з очікуваним датасетом.
  2. Зробити залежності сервісів від ZFS монтувань (systemd ordering), щоб вони не стартували на порожніх директоріях.
  3. Уникати змішування legacy і не-legacy управління монтуванням, якщо у вас немає письмових причин і тестів.
  4. Документувати дерево датасетів і правила успадкування mountpoint’ів для вашої команди.
  5. Під час інцидент-реакції трактувати «порожня директорія» як «неоднозначне монтування», поки не доведено протилежне.

FAQ

1) Чи може датасет ZFS справді «зникнути»?

Рідко в буквальному сенсі. Здебільшого він або не змонтований, змонтований десь іще, або схований іншим монтуванням. Метадані ZFS зазвичай все ще показують його в zfs list.

2) Яка найшвидша одиночна команда, щоб підтвердити пастку монту?

findmnt -T /your/path. Вона показує, що ядро фактично змонтовано там, а це та реальність, у якій працюють ваші додатки.

3) Чому іноді ZFS відмовляється монтуватися через «directory is not empty»?

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

4) Чи погано mountpoint=legacy?

Ні. Воно корисне, коли потрібен контроль на рівні ОС. Ризик виникає, коли команди забувають, що ZFS не монтує такий датасет автоматично, і додатки починають писати у базову директорію, якщо ОС-монт не відбувається.

5) У чому різниця між canmount=off і canmount=noauto?

off означає «ніколи не монтувати». noauto означає «не монтувати автоматично, але дозволяти ручне монтування». noauto часто використовують у boot-середовищах або для проміжних датасетів.

6) Як дізнатись, чи дочірній датасет успадкував mountpoint?

Використовуйте zfs get -o name,property,value,source mountpoint -r pool/dataset. Якщо джерело каже «inherited from …», то зміна батька змінить ефективний mountpoint дитини.

7) Чому перезавантаження «виправило» відсутній датасет?

Тому що під час завантаження змінився порядок або таймінг монтувань. Можливо ZFS змонтувався до конфліктного монту в один раз, або ключі завантажилися успішно при другому перезавантаженні, або юніт з монтування не повторив спробу.

8) Як запобігти тому, щоб додатки писали не туди, коли ZFS не змонтовано?

Два шари: (1) systemd-залежності, щоб сервіси не стартували, поки не з’явиться потрібний монт, і (2) моніторинг, що перевіряє джерело монту (знову: findmnt) і виводить вузли з ротації, якщо воно неправильне.

9) Чи допоможуть снапшоти проти пастки mountpoint?

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

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

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

Висновок

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

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

← Попередня
Події OOM-killer у Proxmox: чому він вбиває процеси і як задати розумні ліміти
Наступна →
Бенчмаркінг ZFS: правила, що запобігають фейковим результатам

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