ZFSBootMenu: Bootování Linuxu na ZFS, správa a klonování snapshotů

Stalo se vám někdy, že vám chybělo místo např. v kořenovém oddílu vaší linuxové instalace? Nebo, že byste chtěli experimentovat s jinou distribucí linuxového systému, ale chyběl vám předem vytvořený oddíl? Mě se to stalo nedávno. A protože ZFS používám na svých serverech již mnoho let, hledal jsem na internetu schůdný způsob, jak provést instalaci Linuxu přímo do ZFS souborového systému. Samotné používání ZFS v Debianu je velmi snadné. Stačí si přidat repozitář contrib a doinstalovat následující balíčky:

sudo apt install linux-headers-$(uname -r)
sudo apt install zfsutils-linux zfs-dkms

Tímto způsobem se stáhnou moduly jádra s podporou ZFS a přeloží se pro aktuálně běžící kernel. Co se ale stane, pokud dojde k upgradu kernelu někdy později? Nic se nestane, moduly se znovu přeloží pro aktualizovanou verzi kernelu automaticky. Tedy jediné, co zbývá dořešit, je instalace Linuxu přímo na ZFS a bootování přímo ze ZFS. Linuxové instalátory ZFS z licenčních důvodů nepodporují a omezená je i podpora GRUBu pro ZFS, která neumožňuje plně využít výhod ZFS.

Jako řešení jsem našel projekt ZFSBootMenu. Startování Linuxu ze ZFS řeší vlastním bootloaderem, který je ve skutečnosti minimalistickou instalací Linuxu, která se spouští přímo z UEFI oddílu. Z toho důvodu obsahuje bezproblémovou podporu ZFS. Do vlastního obrazu ZFSBootMenu lze přidat například podporu sítě a SSH serveru. Pomocí ZFSBootMenu lze ZFS nejen startovat, ale i spravovat snapshoty a provádět základní údržbu.

Instalaci jednotlivých distribucí na ZFS řeší projekt svými návody pro jednotlivé distribuce. Jednotlivé instalace systému mohou být samostatné ZFS datasety a ZFSBootMenu mezi nimi umožňuje při startu vybírat. Díky snapshotům tak lze před větší aktualizací vytvořit návratový bod a v případě problémů nastartovat předchozí stav.

Ruční instalace Debianu a zavaděče ZFSBootMenu

Návody pro jednotlivé distribuce lze nalézt v levém menu domovské stránky ZFSBootMenu včetně návodu pro Debian.

První krok je stažení živé distribuce Debianu, která musí být čerstvá, aby k použitému kernelu bylo možné přeložit ZFS podporu. Po spuštění této živé distribuce z USB donglu doporučuji jako první nainstalovat balíček openssh-server, abyste instalaci mohli provádět na dálku z počítače, na kterém jste zvyklí pracovat.

apt update
apt install openssh-server

Přihlásíte se jako uživatel user, heslo živé distribuce je “live”. Poté se můžete stát rootem příkazem sudo su. Dobrý nápad také může být v nastavení zakázat živému systému úsporný režim, aby vám během kopírování nebo instalace neusnul.

V dalším kroku si doinstalujete podporu pro ZFS v Linuxu a potřebné nástroje. Rozdělíte disk, vytvoříte UEFI oddíl pro bootování, vytvoříte ZFS pool a nastavíte heslo pro šifrování a ZFS properties. Samotnou instalaci Debianu provedete nástrojem debootstrap. Následně provedete chroot, kde změníte hostname a další identifikátory, nastavíte rootovské heslo, doinstalujete potřebné balíčky. Dodatečné operace, které jsem provedl nad rámec návodu, uvádím níže:

apt install task-kde-desktop i3 firmware-linux firmware-misc-nonfree xserver-xorg-video-all mc vim screen htop openssh-server
 
# věci pro wifi
apt install firmware-iwlwifi wireless-tools wpasupplicant
 
adduser jojo
 
usermod -aG sudo jojo
 
systemctl set-default graphical.target
 
echo "auto enp2s0
allow-hotplug enp2s0
iface enp2s0 inet dhcp" >> /etc/network/interfaces

Instalace EFI aplikace ZFSBootMenu se provádí pouhým stažením z webu na patřičné místo do UEFI oddílu. Aby vám disk bootoval na všech počítačích a byl tedy přenositelný, přidejte navíc příkaz:

cp /boot/efi/EFI/ZBM/VMLINUZ.EFI \
/boot/efi/EFI/BOOT/BOOTX64.EFI

Nyní bude instalace bootovat i na počítačích, na kterých není uložen odkaz na VMLINUZ.EFI v UEFI NVRAM (BIOSu). Bohužel v hlavním návodu to neobsahuje, je to vysvětleno jako samostatné téma Portable ZFSBootMenu. Na možnost přesunu disku do jiného počítače, nebo ztracení obsahu NVRAM, je dobré se preventivně připravit.

Výhody ZFS

Nyní vás nejspíše napadá, že ta ruční instalace podle návodu je příliš zdlouhavá, a tak bude lepší se ZFS a ZFSBootMenu úplně vyhnout. Chci vám proto nabídnout jiný pohled na věc. Část příkazů v návodu je práce se ZFS, která je stejně dobré se naučit. Zbývající část, například operace v chrootu, by se vám mohla hodit, pokud se něco pokazí i v případech, že ZFS vůbec nepoužíváte. Umět instalaci či přesun systému provádět ručně se též hodí pro masové nasazení a např. klonování a zálohování disků běžících systémů. Je tedy možné, že se ona časová investice bohatě vrátí. Pro jistotu chci připomenout jednotlivé podstatné výhody ZFS oproti nejčastěji používanému souborovému systému na Linuxu ext4.

  • Při instalaci nemusím disk předem rozdělit na oddíly, každý ZFS dataset si bere tolik místa, kolik potřebuje ze svého jediného oddílu a datasety je možné libovolně vytvářet a mazat. Nemůže tak nastat později problém, že se zjistí, že jsem disk rozdělil nevhodně a tak někde dochází místo, nebo oddíl pro další možnou instalaci chybí.
  • ZFS podporuje kompresi - Lze očekávat úsporu cca 1/3 místa na disku, tedy pokud většinu místa na disku nezabírají již jednou komprimované soubory jako jsou filmy, obrázky či zálohy.
  • Mohu provést snapshot, který pak mohu zálohovat, mohu si z něj vzít např. již smazaný soubor, nebo se “vrátit v čase”. Pokud bych např. nebyl spokojen s novou verzí Debianu, např. kvůli novým potížím s hardwarem, mohu se vrátit ke své starší instalaci a to včetně původního home adresáře.
  • Mohu provádět inkrementální zálohy. Tedy přenáší se jen změny od poslední zálohy, nikoli celá záloha. Tyto zálohy je možné dělat velmi rychle a efektivně. Nová záloha pak může trvat třeba jen několik vteřin.
  • ZFS podporuje nativní šifrování datasetů. U šifrované instalace si ZFSBootMenu vyžádá heslo k odemčení před spuštěním. Lze provádět RAW zálohy (parametr -R nebo -w), kdy i přenášená data jsou zašifrována původním heslem. V tomto případě je obsah záloh chráněn stejným heslem jako hlavní souborový systém a pokud by se někdo nepovolaný dostal k záloze, data si nedokáže přečíst.
  • ZFS má stabilní výkon, při dobrém nastavení a běžném provozu je plně srovnatelný s ostatními moderními souborovými systémy. ZFS lze doporučit i na servery, zvládne velkou zátěž např. od vysoce zatížených databázových systémů. Co se naučíte na svém pracovním počítači, můžete tak snadno použít i na serverech.

Klonování instalace na jiný stroj

Řekněme, že mám na svém pracovním počítači, pro své potřeby vyladěnou instalaci Debianu Trixie běžící na ZFS. A nyní bych ji chtěl instalaci naklonovat na svůj notebook, abych mohl pracovat i na cestách. Jaký bude postup?

Na stroji, který chci klonovat, si vytvořím snapshoty.

sudo zfs snapshot zroot/ROOT/debian@migration
sudo zfs snapshot zroot/home@migration

Na novém počítači, kam chci instalaci klonovat, začnu stejně jako při nové instalaci. Tedy nabootuji do aktuální živé distribuce Debianu. Doinstaluji openssh-server. Rozdělím disk, vytvořím EFI partition a ZFS pool s šifrovaným rootovským datasetem.

Samotné klonování pak provedu na původním stroji příkazy:

ssh user@192.168.0.135 'sudo zfs create -o mountpoint=none zroot/ROOT'
sudo zfs send zroot/ROOT/debian@migration | ssh user@192.168.0.135 "sudo zfs receive -u zroot/ROOT/debian"
sudo zfs send zroot/home@migration | ssh user@192.168.0.135 "sudo zfs receive -u zroot/home"

Výchozí heslo živé distribuce Debianu je “live”. Pozor ale, pokud jste živý Debian restartovali, má stejná adresa nyní nové SSH klíče, a tak příkaz bez varování selže. Otestujete to obyčejným přihlášením přes ssh user@192.168.0.135. Nezapomeňte, že každý uživatele selhává s přihlašováním nezávisle, tedy je třeba to stejné udělat pro běžného uživatele i roota. V mé gigabitové síti přenesení necelých 100 GB obsazené části disku (s kompresí) trvalo několik minut - je to výrazně rychlejší než přenášení po jednotlivých souborech.

Při kopírování datasetů se nepřenesou properties jednotlivých datasetů. Toho bychom sice mohli dosáhnout použitím parametru -p, který u šifrovaných datasetů nelze použít bez parametru -w. Parametr -w ale použít nechceme, protože bychom pak nemohli zachovat jedno společné heslo pro všechny datasety.

Properties jednotlivých datasetů tedy po přenosu na cílovém stroji nastavíme znovu ručně příkazy:

sudo zfs set mountpoint=/ zroot/ROOT/debian
sudo zfs set canmount=noauto zroot/ROOT/debian
sudo zfs set mountpoint=/home zroot/home
sudo zpool set bootfs=zroot/ROOT/debian zroot

Dále pokračujeme podle návodu, především stažením samotného ZFSBootMenu samozřejmě s tím, že vynechám instalaci Debianu a jeho balíčků, které byly přeneseny.

Pro přenos na jiný hardware může být nutné doinstalovat balíčky s firmware Wi-fi, GPU ovladače. Vždy je dobré změnit hostname, UUID UEFI diskového oddílu v /etc/fstab, promazat SSH host keys a podobně.

ls -l /etc/ssh/ssh_host_*
rm -f /etc/ssh/ssh_host_*
ssh-keygen -A
 
vim /etc/hostname
vim /etc/hosts
zgenhostid -f
 
cat << EOF > /etc/fstab
$( blkid | grep "$BOOT_DEVICE" | cut -d ' ' -f 2 ) /boot/efi vfat defaults 0 0
EOF

Klonování ZFS instalace na notebook, na kterém zůstává i instalace s Windows

Svůj operační systém jsem si chtěl naklonovat i na svůj notebook Lenovo. Ale objevil jsem, že jsem tam nechal i zmenšený oddíl se systémem Windows. Windows jsem nikdy nepoužil, nechal jsem jej tam jen pro případ, že by mohlo být někdy v budoucnu např. upgradovat BIOS notebooku. Rozdělování disku je v live Debianu možné dělat též pomocí aplikace Gparted, které je možné si doinstalovat.

Na prvním obrázku je vidět mé původní rozdělení disků. Oddíl 1 je UEFI fat32, ten zůstane sloužit svému účelu, jen do něj dokopíruji ZFSBootMenu. Oddíly 2 a 3 používají Windows. Na ostatních oddílech byl instalován starší Debian s šifrováním zvoleným během instalace. Tyto oddíly jsem odstranil a místo nich vytvořil nový oddíl pro ZFS. Jako souborový systém nového oddílu jsem zvolil “unformatted”, jelikož Gparted zfs nenabízí. Přesto takto vytvořený oddíl ukazuje Gparted jako ext4, což je možné ignorovat, protože ZFS oddíl se formátuje až při vytváření zpoolu.

Po provedených změnách ukazuje příkaz lsblk tohle:

lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0         7:0    0   3.2G  1 loop /run/live/rootfs/filesystem.squashfs
nvme0n1     259:0    0 953.9G  0 disk 
├─nvme0n1p1 259:1    0   260M  0 part 
├─nvme0n1p4 259:2    0 822.3G  0 part 
├─nvme0n1p2 259:5    0    16M  0 part 
└─nvme0n1p3 259:6    0 131.3G  0 part

Jelikož se mění používané oddíly, budu muset změnit nastavení některých proměnných v návodu pro Debian. Hodnota pro BOOT_DEVICE zůstává stejná jak přednastaveno v návodu /dev/nvme0n1p1, ale POOL_DEVICE bude odkazovat na jiný oddíl - největší a nově vytvořený oddíl /dev/nvme0n1p4, který bezpečně poznám ve výstupu lsblk podle velikosti.

Tedy upravím v návodu pro Debian řádek s hodnotou export POOL_PART=“2” na export POOL_PART=“4”. Vynechám rozdělování disku, vytváření UEFI oddílu a oddílu pro zfs, které již existují. Vytvořím šifrovaný zpool a pokračuji stejným způsobem jako v návodu výše, při klonování systému na prázdný disk.

Je možné naklonovat celý šifrovaný zfs pool na jiný stroj ?

Provedl jsem následující pokus. Nejdříve jsem vytvořil snapshot rootovského datasetu včetně všech poddatasetů.

sudo zfs snapshot -r zroot@migration_notebook

Parametr -r znamená, že se vytvoří rekurzivně snapshoty i všech poddatasetů.

Všechny tyto snapshoty se pokouším přenést na jiný stroj jediným příkazem tak, aby bylo zachováno vše včetně jména jednotlivých datasetů, properties a šifrování.

Ale příkaz přenosu skončí chybou:

sudo zfs send -Rw zroot@migration_notebook | ssh user@192.168.0.127 'sudo zfs receive zroot'
user@192.168.0.127's password: 
cannot receive new filesystem stream: destination 'zroot' exists
must specify -F to overwrite it

Parametr -F ale není možné použít pro RAW přenos (s -w).

Pokud zroot na cílovém stroji odstraním, tak dostanu pro změnu jinou chybu

[xsouku04@deZFS1 ~]$ sudo zfs send -Rw zroot@migration_notebook | ssh user@192.168.0.127 'sudo zfs receive zroot'
user@192.168.0.127's password: 
cannot receive new filesystem stream: destination 'zroot' does not exist

Nepodařilo se mi přijít na to, jak tohle omezení obejít. Zjevně by bylo možné vše nakopírovat do jinak pojmenovaného datasetu, např. zroot/backup, ale mít na každém stroji jinou cestu k datasetům nechci.

Proto nemohu použít parametr -w, pro RAW přenos dat včetně všech parametrů, ale musím kopírovat datasety běžným způsobem.

Překvapivě tedy zazálohovat celý šifrovaný zfs pool možné je, ale naklonovat jej se zachováním stejného pojmenování a šifrování možné není.

Pokud šifrování nepoužíváte, např. protože se jedná o server, který je dobře fyzicky zabezpečen proti krádeži, budete mít situaci jednodušší a můžete používat parametry -p a -R.

Běžná práce se ZFS

Řekněme že chci přeinstalovat další notebook na novější Debian na ZFS. Předtím než disk přeformátuji, potřebuji data na něm uložená zazálohovat. Naprostá většina veškerých nastavení a uživatelský dat uživatelů jsou v podadresáři adresáře /home/. Jednou z výjimek je uložení jmen a hesel ke známým wifi sítím, týká se též VPN spojení. Ty se ukládají do adresáře /etc/NetwrokManager/. Abych mohl i tyto data snadno zálohovat, provedu nejdříve jejich lokální zálohu do tar souboru v domovském adresáři:

sudo tar -C /etc/NetworkManager -czf ~/networkmanager-connections.tar.gz system-connections

Nyní se přesunu na počítač kde mi již ZFS funguje. A vytvořím si dataset pro tuhle zálohu:

zfs create -o mountpoint=/backup_notebook -o compression=zstd-9 zroot/backup_notebook

Jelikož se jedná jen o zálohu, z které se nebude moc často číst, mohu zvolit lepší kompresi. V systému se mi nyní objeví nový adresář /backup_notebook, který představuje nový dataset.

Že v systému přibil nový dataset mohu ověřit pomocí příkazu zfs list

Samotnou zálohu adresáře /home/ provedu pomocí rsync, jelikož na tom notebooku ještě zfs není.

Příkaz použiji na počítači se ZFS na který chci zálohovat.

sudo rsync -aHAX --numeric-ids   user@192.168.0.127:/home/ /backup_notebook/

Po dokončení zálohy, zkontroluji obsazení disku.

zfs list
NAME                    USED  AVAIL  REFER  MOUNTPOINT
zroot                   155G   768G   192K  none
zroot/ROOT             16.8G   768G   192K  none
zroot/ROOT/debian      11.9G   768G  8.90G  /
zroot/ROOT/debian2     4.91G   768G  4.91G  /
zroot/backup_notebook  50.0G   768G  50.0G  /backup_notebook
zroot/home             87.8G   768G  70.4G  /home

Vidím že na notebooku data v jeho oddílu /home, který jsme zálohovaly zabírají cca 70 GB, v ZFS díky kompresi jen 50 GB.

Nyní mohu obsah disku notebooku smazat a mohu na něj nainstalovat nebo naklonovat Debian používající ZFS.

Po dokončení mohu na něj zkopírovat zpět dataset s původní zálohou.

sudo zfs send zroot/backup_notebook@migration_notebook | ssh user@192.168.0.127 "sudo zfs receive -o mountpoint=/backup_notebook -o compression=zstd-9 zroot/backup_notebook"

Jelikože zfs send v případě že se posílají původně zašifrovaná data neumí poslat properties, nasavuji je hned za zfs receive.

Konkrétně mountpoint a compression. Kdybych compression nastavil až po přenosu, neměla by již žádný vliv, takto ušetří cca 10 GB místa.

Opět nezapomeňte, že je třeba smazat záznamy o starých ssh klíčích, co používala live distribuce. Jak u běžného uživatele, tak u uživatele root.

Nová instalace vyžaduje vždy po použití sudo zadání hesla, což znemožňuje použít sudo před příkazem zfs receive.

Zde jsem narazil na problém, že sudo v nové instalaci vyžaduje vždy zadání hesla uživatele, proto není možné sudo použít před příkazem zfs receive.

Pro jednorázový přenos zálohy zpět na nový souborový systém ZFS mohu problém se sudo vyřešit dočasným potlačením nutnosti zadávat heslo při sudo.

Na notebooku provedu:

sudo sh -c 'echo "user ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/nopasswd-temp'
sudo chmod 440 /etc/sudoers.d/nopasswd-temp

Pro vypnutí hesla.

Pro zrušení této změny provedu:

sudo rm /etc/sudoers.d/nopasswd-temp

Na notebooku mohu nyní postupně přesouvat různá nastavení ze “starého disku” podle potřeby. Např. mohu obnovit automatické připojování do různých wifi sítí pomocí:

sudo tar -C /etc/NetworkManager -xzf /backup_notebook/user/networkmanager-connections.tar.gz
sudo chmod 600 /etc/NetworkManager/system-connections/*
sudo systemctl restart NetworkManager

Např. nastavení firefoxu a thunderbirdu obnovím následovně:

rm -rf ~/.thunderbird && cp -a /backup_notebook/user/.thunderbird ~/
rm -rf ~/.mozilla && cp -a /backup_notebook/user/.mozzila ~/

Starou zálohu mohu pro jistotu na disku nechat i několik let, abych si byl jistý, že jsem nezapomněl nic důležitého přenést. Až bude jisté, že ji nepotřebuji, než jakmile mi začne docházet místo na disku, prostě tohle místo uvolním příkazem.

zfs destroy zpool/backup_notebook

Stejný příkaz mohu nechat provést jak stolním počítači tak na samotném notebooku.

 
zfsbootmenu_clanek.txt · Last modified: by root