Как стать автором
Поиск
Написать публикацию
Обновить

Arch Linux на ZFS для людей: новый TUI-установщик archinstall_zfs

Уровень сложностиСредний
Время на прочтение12 мин
Количество просмотров3.9K

Установка Arch Linux на ZFS всегда была не очень тривиальным делом: нужно знать много тонкостей, прочитать кучу статей и различные вики, разобраться с флагами создания датасетов и пула, с конфигурацией initramfs и с тем, какие systemd сервисы стоит включать, с параметрами командной строки ядра и правильными конфигами. Если ставить вручную, то установка занимает целый вечер, с вдумчивым раскуриванием мануалов перед черной консолью. (Небольшой лайфхак: если у вас есть второй компьютер, гораздо приятнее ставить арч с него, подключившись к таргету по ssh, именно из‑за возможности копипастинга команд).

Несколько лет назад я начал работать над автоматизацией этого процесса: написал несколько скриптов на bash, которые делают всё за меня. Это было не очень стабильно: они периодически ломались, гибкостью настройки там и не пахло: скрипт был жёстко прибит к моей конфигурации, и когда кто‑то из друзей просил помочь с установкой Arch Linux на ZFS, обычно я просто делал новую ветку репозитория, подстраивая скрипт под нужную конфигурацию. Всё изменилось зимой прошлого года, когда мне захотелось в очередной раз поставить чистую систему для экспериментов на новый SSD. Я всерьез задумался о новом установщике, который предоставлял бы гибкое меню с конфигурацией в виде TUI. У меня была идея написать инструмент с нуля на Rust, используя ratatui, но масштаб работы для написания гибкого и надёжного проекта, сравнимого по функционалу с archinstall, начал меня немного пугать. Следующей мыслью было попробовать форкнуть archinstall. В процессе чтения его исходного кода и документации я понял: мне не нужно его форкать, я могу использовать его как библиотеку.

Так и родился archinstall_zfs — установщик, который использует archinstall как библиотеку, но при этом переопределяет ключевые компоненты. Я взял от archinstall то, что работает хорошо: TUI компоненты (SelectMenu, EditMenu), систему конфигурации, установку пакетов. Но разметку диска пришлось делать с нуля — archinstall просто не умеет работать с ZFS. Поэтому я написал свой DiskManager, который через sgdisk создаёт нужные разделы, а также GlobalConfigMenu — полностью кастомное меню вместо стандартного. А для самой установки создал ZFSInstaller, который наследует от archinstall.Installer, но умеет работать с ZFS‑специфичными пакетами и конфигурацией.

Workflow установки
Workflow установки

Получилось именно то, что я хотел: гибкий TUI‑интерфейс, где можно выбрать нужные параметры, а всю грязную работу инструмент сделает сам. Теперь установка Arch на ZFS занимает не вечер с мануалами, а 15–20 минут с чашкой чая.

Но прежде чем рассказывать о возможностях установщика, давайте разберёмся, почему вообще стоит заморачиваться с ZFS.

Почему ZFS?

ZFS — это не просто файловая система, это целая философия управления данными. Представьте, что вы обновили систему, что‑то сломалось, и теперь не загружается графическая оболочка. С обычной файловой системой вы бы лезли за LiveUSB, arch‑chroot, диагностика, исправление неполадок. Либо, если вы новичок, то дело может дойти до переустановки. С ZFS, снэпшотами и ZFSBootMenu вы просто перезагружаетесь, выбираете предыдущее состояние системы из меню и продолжаете работать. А потом спокойно разбираетесь, что пошло не так.

Или другой пример: хотите попробовать Wayland вместо X11? Создаёте клон текущего датасета, загружаетесь в него, экспериментируете. Не понравилось — откатились за секунду. Никаких «ой, а как же вернуть как было».

Кроме того, если у вас есть домашний сервер с ZFS, вы можете отправлять туда инкрементальные снепшоты время от времени

Три режима установки

Я долго думал, какие сценарии установки нужно поддержать. В итоге получилось три основных режима:

1. Full Disk — для тех, кто хочет отдать весь диск под ZFS. Тут я реализовал полную автоматизацию разметки через sgdisk. Установщик сначала очищает GPT и MBR сигнатуры (привет, проблемы с остатками старых разделов!), затем создаёт свежую GPT таблицу и нарезает разделы: EFI‑раздел на 500MB, опционально swap‑раздел в конце диска, а всё остальное — под ZFS.

2. New Pool — для dual‑boot сценариев. У вас уже есть Windows на первой половине диска? Не проблема! Укажите свободный раздел, установщик создаст на нём ZFS pool и установит туда систему. EFI‑раздел можно использовать существующий или создать новый.

3. Existing Pool — моя любимая фича! У вас уже есть ZFS pool с данными или другими системами? Установщик создаст новый boot environment и установит туда свежий Arch, не трогая существующие данные. Идеально для экспериментов и мультибута разных дистрибутивов.

Вид меню в последней версии на момент публикации статьи v0.3.4
Вид меню в последней версии на момент публикации статьи v0.3.4

Кто такие эти ваши Boot Environments?

Boot Environments (BE) — это способ держать несколько независимых систем на одном ZFS‑пуле. Каждая система размещается в своём корневом датасете и выбирается при загрузке через ZFSBootMenu. Для мультибута вы можете поставить несколько дистрибутивов в один пул — каждый станет отдельным BE.

Реальный пример с моего ноутбука (с комментариями):

❯ zfs list
NAME                       USED  AVAIL  REFER  MOUNTPOINT
novafs                    1.09T   361G   192K  none

# Текущий активный BE "arch0" (контейнер, сам не монтируется)
novafs/arch0               609G   361G   192K  none
novafs/arch0/data          421G   361G   192K  none
novafs/arch0/data/home     421G   361G   344G  /home    # /home датасет для arch0
novafs/arch0/data/root     120M   361G  45.3M  /root    # данные пользователя root текущего BE
novafs/arch0/root          170G   361G   142G  /        # корневая ФС активного BE
novafs/arch0/vm           18.8G   361G  18.8G  /vm      # отдельный датасет для VM

# Предыдущий BE "archold" (не активен, но готов к загрузке)
novafs/archold             227G   361G   192K  none
novafs/archold/data        143G   361G   192K  none
novafs/archold/data/home   141G   361G   119G  /home    # /home датасет для archold
novafs/archold/data/root  1.81G   361G  1.81G  /root    # данные root второго BE
novafs/archold/root       83.7G   361G  83.7G  /        # корень второго BE

# Глобальные датасеты (вне BE, монтируются всеми boot environments)
novafs/tmp_zfs            7.08G   361G  7.08G  /tmp_zfs        # временные данные

ZFSBootMenu — загрузчик, который понимает ZFS

Забудьте про GRUB с его костылями для ZFS. ZFSBootMenu — это загрузчик, созданный специально для ZFS. В отличие от традиционных загрузчиков, он нативно понимает структуру ZFS и может показывать список boot environments в красивом ncurses‑меню, делать снапшоты и клонировать boot environments прямо при загрузке. Нужно откатиться на снапшот недельной давности? Просто выбираете его из меню, и система загружается именно в том состоянии. Хотите поэкспериментировать, не ломая текущую систему? Клонируете boot environment прямо из загрузчика и загружаетесь в копию. Интересный факт: на самом деле этот загрузчик — это полноценный Linux, который при загрузке загружает вашу систему использую системный вызов kexec.

Нативное шифрование ZFS

Поддерживается нативное шифрование ZFS без необходимости в LUKS‑контейнерах — ZFS шифрует данные сам. При этом доступны следующие варианты:

  • Без шифрования.

  • Шифрование всего пула (зашифрованы все датасеты включая корневую систему)

  • Шифрование отдельного boot environment

В текущей версии поддерживаются только plain text ключи (пароли), без более сложных схем аутентификации. За расшифровку отвечает хук zfs в initramfs, который запрашивает пароль на ранней стадии загрузки.

Dracut vs mkinitcpio — выбор за вами

Arch традиционно использует mkinitcpio для создания initramfs. Но я предпочитаю dracut — его хук zfs лучше работает с нативным шифрованием ZFS. Установщик поддерживает оба варианта, и тут есть интересные технические детали.

Для mkinitcpio я добавляю хук zfs в нужное место (после keyboard, но до filesystems), прописываю правильные модули. А вот с dracut пришлось повозиться больше: нужно было написать собственные pacman хуки, которые автоматически пересобирают initramfs при обновлении ядра. Стандартные хуки пакмана не подходят — они не знают про dracut.

Загрузка и boot environments: ZFSBootMenu, zfs‑mount‑generator и кастомный ZED‑хук

Коротко о том, как устроена загрузка:

  • В качестве загрузчика используется ZFSBootMenu: при выборе boot environment он запускает ядро Linux через системный вызов kexec и передаёт параметры командной строки ядра.

  • Корневая ФС монтируется хуком zfs в initramfs, согласно параметру командной строки: с dracut это root=ZFS=..., с mkinitcpio — через zfs=...

  • Остальные датасеты монтируются уже systemd»ом через zfs-mount-generator, который читает /etc/zfs/zfs-list.cache/<pool> и на лету генерирует unit‑файлы. Примечание: использование zpool.cache считается устаревшим и не рекомендуется Arch Wiki, поэтому был выбран подход с zfs-mount-generator

Проблема BE в том, что «по умолчанию» ZFS видит все датасеты пула, из‑за чего systemd может попытаться примонтировать чужие файловые системы (например, /home из соседнего boot environment). Это решает мой кастомный ZED‑хук history_event-zfs-list-cacher.sh: он отслеживает события ZFS, определяет активный boot environment, фильтрует датасеты (оставляя только датасеты, принадлежащие текущему BE и общие вроде pool/tmp_zfs) и атомарно обновляет кеш. Скрипт сделан иммутабельным (chattr +i), чтобы обновления не затирали его.

Swap, ZRAM и ZSWAP

Можно вовсе обойтись без swap, можно включить ZRAM — это сжатый swap в RAM через systemd-zram-generator, и в этом режиме я специально отключаю zswap. По умолчанию используется zram-size = min(ram / 2, 4096) в /etc/systemd/zram-generator.conf.

Если нужен классический swap на диске — выбирайте режим «ZSWAP + swap‑раздел»: zswap включается, а сам swap живёт на отдельном разделе. При полном стирании диска задаёте размер раздела под swap; в остальных сценариях просто выбираете существующий раздел в TUI. Для незашифрованного варианта установщик делает mkswap и явно добавляет строку с UUID= в /etc/fstab (genfstab не включает неактивный swap). Для шифрованного — прописывает cryptswap через PARTUUID в /etc/crypttab и монтирует /dev/mapper/cryptswap в fstab.

Примечание: swap на ZFS (zvol/swapfile) не поддерживается — см. раздел ArchWiki «ZFS → Swap volume». Гибернация в текущем релизе тоже не поддерживается.

Валидация совместимости ядра и ZFS

Одна из ключевых проблем при работе с ZFS на Arch — совместимость версий ядра и модулей ZFS. Precompiled модули ZFS в репозитории archzfs часто отстают от последних версий ядра, а DKMS может не компилироваться с bleeding‑edge ядрами.

Для решения этой проблемы я написал систему валидации, которая определяет диапазон совместимых ядер для текущей версии ZFS. Система работает следующим образом:

  • Парсит release notes на https://github.com/openzfs/zfs/releases для определения поддерживаемых версий ядра

  • Сопоставляет эти данные с актуальными версиями ядер (linux, linux‑lts, linux‑zen) в репозиториях Arch

  • Проверяет доступность precompiled ZFS модулей для каждого ядра

  • Анализирует возможность DKMS‑сборки с конкретными версиями ядра

  • Предупреждает о потенциальных проблемах и предлагает альтернативы

Эта валидация используется в двух местах:

1. В установщике — при выборе ядра показываются только совместимые варианты

2. При сборке ISO — скрипт iso_builder.py автоматически проверяет совместимость перед созданием образов

Как это выглядит на практике?

Процесс установки сводится к нескольким простым шагам — выберите удобный способ запуска установщика:

Вариант A: готовый ISO (рекомендуется)

  1. Скачать последний ISO из релизов проекта, ( https://github.com/okhsunrog/archinstall_zfs/releases ) загрузиться в режиме UEFI. Примечание: если вы используете Ventoy, при выборе образа нужно выбрать GRUB2 режим загрузки.

  2. Подключить сеть.

  3. Запустить установщик:

./installer
# или
cd /root/archinstall_zfs && python -m archinstall_zfs

Вариант B: официальный Arch ISO (Этот вариант занимает больше времени из‑за установки ZFS модулей в ISO.)

# 1) Загрузитесь с официального Arch ISO и подключите сеть
pacman -Sy git

# 2) Получите установщик
git clone --depth 1 https://github.com/okhsunrog/archinstall_zfs
cd archinstall_zfs
python -m archinstall_zfs

Далее в TUI пройдите короткий визард: выберите режим установки → диски → имя пула → параметры системы. После подтверждения установщик автоматически настроит ZFSBootMenu, подберёт совместимую связку ядро/ZFS, соберёт initramfs (dracut или mkinitcpio) и включит необходимые сервисы ZFS. В конце — предложение зайти в chroot и перезагрузка в свежий Arch на ZFS.

Подробнее о коде

Всё написано на Python 3.13+ с использованием archinstall как библиотеки, но архитектуру пришлось делать с нуля. Стандартные меню archinstall не подошли — сделал своё, чтобы контролировать весь процесс установки. Для разметки диска тоже реализовал отдельный класс, потому что archinstall не умеет работать с ZFS.

Установка ZFS идёт через собственный класс (наследник archinstall.Installer): он добавляет нужные пакеты, правильно собирает initramfs (dracut или mkinitcpio) и учитывает все нюансы ZFS. Валидация совместимости ядра и ZFS вынесена в отдельный модуль — он парсит репозитории, релизы ZFS и проверяет, что всё совместимо. Для конфигов используется Pydantic, чтобы не было магии с dict'ами.

Профиль для ISO собирается через шаблоны Jinja2 — так проще поддерживать разные варианты (DKMS или precompiled модули, разные хуки и сервисы, разные наборы пакетов включаются условно). Всё максимально типизировано, чтобы не ловить баги на ровном месте.

Сборка ISO: just, Justfile и Jinja2

Сборочные сценарии полностью оркестрируются через just (рецепты описаны в justfile). Это позволяет быстро собирать разные варианты ISO и управлять параметрами сборки.

# Посмотреть доступные команды:
just --list

# Релизные ISO (полный набор пакетов)
just build-main pre              # Precompiled ZFS + linux-lts (рекомендуется)
just build-main dkms linux       # DKMS + linux
just build-main dkms linux-lts   # DKMS + linux+lts (самый надёжный вариант, если версии пакетов zfs и ядер рассинхронизированы)

# Ускоренные сборки для разработки (минимальный набор пакетов)
just build-test pre              # Минимальный пакетный набор + precompiled ZFS
just build-test dkms linux-zen   # Минимальный пакетный набор + DKMS + linux-zen

just list-isos                   # Показать собранные ISO

Ключевые различия между build-main и build-test:

  • build-main — создаёт релизные ISO с полным набором пакетов (включая диагностические инструменты, сетевые утилиты, редакторы и т. д.). Использует squashfs для сжатия, что даёт меньший размер ISO.

  • build-test — создаёт тестовые ISO с минимальным набором пакетов (только базовые утилиты и установщик). Использует erofs для более быстрого сжатия, отключает таймауты загрузки и включает вывов в serial console для удобства загрузки в qemu, автоматически поднимает ssh и разрешает логин от рута. Идеально подходит для быстрого тестирования изменений в установщике в qemu.

Профиль archiso генерируется из шаблонов на Jinja2, что даёт гибкую конфигурацию без копипасты:

  • Переменные шаблонов:

    • kernel — целевой вариант ядра

    • use_precompiled_zfs / use_dkms — способ установки ZFS

    • include_headers — включать ли headers для ядра

    • fast_build — минимальный пакетный набор для быстрых тестов

  • Ключевые шаблоны:

    • packages.x86_64.j2 — список пакетов

    • profiledef.sh.j2 — метаданные ISO, флаги сборки, разрешения файлов

    • pacman.conf.j2 — конфигурация репозиториев

Скрипт iso_builder.py формирует профиль ISO на основе этих шаблонов и параметров, а результаты складываются в gen_iso/out/. Сами профильные файлы, сервисы и хуки лежат в gen_iso/profile/.

Дополнительные возможности установщика

  • Сжатие ZFS (настраиваемо): выбор алгоритма в TUI — off, lz4 (по умолчанию), zstd, zstd-5, zstd-10. Выбранное значение применяется на уровне пула/датасетов и наследуется, а в initramfs отключается лишняя компрессия, чтобы избежать двойного сжатия.

  • zrepl: генерация /etc/zrepl/zrepl.yml с снапшотами каждые 15 минут и ретеншеном 4×15m (keep=all) | 24×1h | 3×1d.

  • AUR‑интеграция: установка пакетов из AUR через временного пользователя (aurinstall), установка хелпераyay-bin. В меню доступен пункт, где можно указать список своих AUR‑пакетов, которые будут автоматически установлены.

Что ожидать в следующем релизе?

  • Поддержка Secure Boot (подпись ZFSBootMenu, управление ключами)

  • Локальная сборка ZFSBootMenu, используя системное ядро и dracut / mkinitcpio, вместо готовых EFI‑файлов, для большей кастомизации

  • Более умная генерация hostid (на основе имени хоста)

  • Возможно, добавлю русскую локализацию, если будет интерес

Пара слов о CI

За сборку отвечает GitHub Actions: раз в месяц он автоматически собирает свежие образы, а ещё он запускается при пуше нового тега и формирует релиз с ISO‑образами в качестве артифактов. Перед сборкой пайплайн проверяет совместимость: сначала пробует предсобранные ZFS‑модули, и если версии не совпадают, автоматически переключается на DKMS. Благодаря этому образ с linux-lts получается практически всегда, а linux в редких случаях, если текущая версия ядра ещё не поддерживается проектом OpenZFS, просто пропускается.


ZFS — это мощный инструмент, но сложность её настройки отпугивает многих. Я надеюсь, что archinstall_zfs сделает эту файловую систему доступнее для обычных пользователей Arch Linux. Больше не нужно быть гуру, чтобы получить все преимущества ZFS — снапшоты, boot environments, компрессию и надёжность.

Проект активно развивается, поэтому баги возможны. Но я сам использую его для всех своих установок и пока полёт нормальный:)

Если у вас есть идеи по улучшению или вы нашли баг — welcome в issues на GitHub! А если проект оказался полезным — поставьте звёздочку, это мотивирует развивать его дальше.

Ссылка на репозиторий

Так же приглашаю заглянуть в мой телеграм‑канал Okhsunrog's Logs: никакой рекламы, только технические заметки про Rust, Linux, Embedded, отчёты про прогресс моих текущих опенсорсных проектов, и конечно же, мемы.

Теги:
Хабы:
+17
Комментарии24

Публикации

Ближайшие события