Linux/Saját linux live CD készítése/ZFS root fájlrendszerű gép installálása

Ez a szócikk példa, hogyan használható a saját live CD. A ZFS root fájlrendszerű gép installálásán felül azt is ki akarjuk próbálni, hogyan alakítható át egy BIOS/mbr-ben partícionált gép UEFI/gpt-re. Nem célunk viszont belemélyedni a ZFS lehetőségeibe: nem készítünk RAID-et, dataset-eket is elsősorban a példa érdekében.

A gpt-re alakítás simán megy, kivéve azt az apróságot, hogy a gép bootolhatatlanná válik, újabb példával támasztva alá Murphy egyik számítástechnikai törvényét: igazán komoly kárt csak az admin tud tenni a saját gépében. Enyhítő körülmény, ha meg is tudja gyógyítani, amihez ZFS root fájlrendszerű gép esetén ZFS-t ismerő live/rescue CD kell.

Kiindulási helyzet

szerkesztés

Üres (virtuális) gépen vagyunk, bebootoltunk a live CD-vel, bejelentkeztünk ssh-val. Van egy partícionálatlan üres diszkünk:

root@ZFS-live:~# cat /proc/partitions 
major minor  #blocks  name
  11        0     518966 sr0
   8        0    8388608 sda
   7        0     490984 loop0

Partícionálás

szerkesztés

Egy kissé zilált partíciós táblát készítünk a próba kedvéért:

Disk /dev/sda: 8 GiB, 8589934592 bytes, 16777216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x146049cb

Device     Boot    Start      End  Sectors  Size Id Type
/dev/sda1           2048 15362047 15360000  7.3G 83 Linux
/dev/sda3       15362048 16777215  1415168  691M  5 Extended
/dev/sda5       15364096 15978495   614400  300M 82 Linux swap / Solaris

A 2. partíció helyét szándékosan hagytuk ki. Az extended partíció minden maradék helyet elfoglal, de azon belül még lehetne partíciót létrehozni.

Meglennénk swap nélkül, amíg azt ZFS-ben létrehozzuk, de ha már van, használatba vesszük:

mkswap /dev/sda5
swapon /dev/sda5
free
              total        used        free      shared  buff/cache   available
Mem:        1019716       32276      895288        1884       92152      869044
Swap:        307196           0      307196

Pool létrehozása

szerkesztés

Először a poolt kell létrehozni: ez az a diszkterület, amivel a ZFS fájlrendszer gazdálkodik. Éles helyzetben RAID-es poolt hoznánk létre;[1] ettől itt az egyszerűség kedvéért eltekintünk.

modprobe zfs       # a ZFS kernel-modulok nem toltodnek be automatikusan
zpool create -f -o ashift=12 \
      -O atime=off -O canmount=off -O compression=lz4 -O normalization=formD \
      -O devices=off -O mountpoint=/ -R /mnt \
      helyi /dev/sda1

A pool neve helyi, a használt diszk a /dev/sda1. Az ashift=12 4096 (212) bájtos blokkméretet jelent. A -f akkor is megcsinálja a poolt, ha egyébként csak figyelmeztetne valamilyen lehetséges hibára. A többi, -O kapcsolóval megadott paraméter az automatikusan létrehozott dataset-re vonatkozik. (A dataset lényegében a fájlrendszer elnevezése a ZFS-terminológiában.) A létrejött datasetet nem fogjuk használni, de al-dataseteket hozunk majd létre benne, és azok – a root fájlrendszert is beleértve – örökölni fogják az itt beállított tulajdonságokat:

  • atime=off: nem írja fel a fájlok utolsó hozzáférési dátumát. Ez jelentősen csökkenti a fájlrendszer írásterhelését, az elveszített információt pedig szinte sohasem használjuk.
  • canmount=off: a fájlrendszer nem mountolható. Csak arra használjuk, hogy al-fájlrendszereket hozzunk létre benne, melyekben ezt a paramétert majd módosítjuk.
  • compression=lz4: automatikus blokk-tömörítés lz4 algoritmussal
  • normalization=formD: a fájlnevek UTF-8 kódolásúak
  • devices=off: az eszközfájlok használata (olvasása) nem megengedett a fájlrendszerben
  • mountpoint=/: a fájlrendszer csatolási pontja. A ZFS ezt nem a szokásos /etc/fstab-ban tartja, hanem magában a fájlrendszerben, mint annak egyik tulajdonságát. Ennek több következménye van:
    • a csatolási pontok ütközésének elkerülésére a ZFS csak üres könyvtárba tud fájlrendszert csatolni (ha a könyvtár nem létezik, létrehozza)
    • két pool csatolási pontjainak ütközése a -R kapcsolóval kerülhető el: a pool valamennyi csatolási pontja ehhez a könyvtárhoz képest értendő. Ez esetben azért kell, mert a root fájlrendszer már foglalt – mint mindig, ha új root fájlrendszert hozunk létre.

Az eredmény ellenőrzése: zpool list

NAME    SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
helyi  7.31G   324K  7.31G         -     0%     0%  1.00x  ONLINE  /mnt

Datasetek létrehozása

szerkesztés

A leendő tényleges root fájlrendszer:

zfs create -o canmount=on -o mountpoint=/ -o devices=on helyi/ROOT

A gyökér fájlrendszert nem a ROOT-ban, hanem az alatta levő datasetben szokás létrehozni. Ennek egyelőre linuxban nincs jelentősége.

A zfs -o kapcsolója ugyanazokat a tulajdonságokat adja meg, mint a zpool -O kapcsolója (a zpool -o-ja a pool tulajdonsága, nem a dataseté).

Példaként három datasetet (al-fájlrendszert) hozunk létre. Éles rendszerben jobban szeparálnánk, annál is inkább, mert a ZFS-ben nemcsak a fájlrendszer jogosultságait, hanem a területének a méretét is ennek alapján lehet szabályozni. Külön dataset lehet pl.: /home, /var/log, /var/mail, /opt, stb. A /usr külön datasetbe tétele vitatható; e vitát itt most eldönti az a debian stretch bug, ami miatt a /usr/lib a gyökér fájlrendszerben kell legyen, egyébként a gép nem tud bootolni.

zfs create -o canmount=on -o setuid=off -o exec=off helyi/var
zfs create -o exec=on helyi/var/lib
zfs create -o canmount=on helyi/tmp
chmod 1777 /mnt/tmp

A /var fájlrendszerben nem megengedett a programvégrehajtás. A /var/lib visszakapja ezt a jogot, felülírva az öröklődést. A /var a tulajdonságait nem a ROOT, hanem a pool legfelső, névtelen datasetjétől örökli, vagyis eszközfájl nem használható /var-ban:

zfs get devices helyi/var
helyi/var  devices               off                    inherited from helyi

Ellenőrzés: zfs list

NAME            USED  AVAIL  REFER  MOUNTPOINT
helyi           756K  7.08G    96K  /mnt
helyi/ROOT       96K  7.08G    96K  /mnt
helyi/tmp        96K  7.08G    96K  /mnt/tmp
helyi/var       192K  7.08G    96K  /mnt/var
helyi/var/lib    96K  7.08G    96K  /mnt/var/lib

Debian installálás

szerkesztés

Ezt már ismerjük a live CD előállításából. Gyorsabb, ha a live CD tartalmát másoljuk a leendő diszk fájlrendszerébe, mert abban van már ZFS és néhány más csomag és beállítás.

cd /media
mkdir p{1,2}
mount /dev/sr0 p1 -o ro
mount p1/live/filesystem.squashfs p2 -o ro        # felcsatoltuk a live CD tartalmat /media/p2-re

rsync -a p2/* /mnt/         # atmasoljuk. Ellenoriztuk, nincs-e rejtett fajl p2-ben
mkdir /mnt/boot             # a /boot mashol van a CD-n
cp -p p1/vmlinuz /mnt/`readlink /mnt/vmlinuz`     # kernel masolas. initrd-t nem kell, mert ujra letrehozzuk
umount p2
umount p1                   # lecsatoltuk a CD-tartalmat
rmdir p1 p2                 # rendet teszunk magunk utan

# chroot elokeszites
mount /dev /mnt/dev --bind
mount /proc /mnt/proc --bind
mount /sys /mnt/sys --bind
chroot /mnt          # beleptunk chroot-ba

export LC_ALL=C      # ne nyafogjon az apt a magyar locale miatt
apt-get purge live-boot-initramfs-tools      # a diszken nem kell live
apt-get autoremove   # a live-hez tartozo, feleslegesse valt csomagok torlese

/etc/default/zfs-ben a kommentben levő ZFS_INITRD_ADDITIONAL_DATASETS paramétert erre állítsuk:

ZFS_INITRD_ADDITIONAL_DATASETS="helyi/var helyi/var/lib"

Erre azért van szükség, hogy a felsorolt két dataset a ROOT-tal együtt csatolódjék, még mielőtt a journald elkezdené írni a könyvtárakat. Ez esetben ui. már nem lennének üresek, és nem lehetne csatolni őket. A beállítást el kell magyarázni a grub-nak, és initrd-t generálni:

apt-get install zfs-initramfs     # ZFS root-hoz kell
update-initramfs -u -t -k all     # generaljuk initrd-t
apt-get install grub-pc           # boot loader install BIOS módban. A grub-ot /dev/sda-ba rakatjuk, amikor megkerdezi.
apt-get clean
umount /proc /sys /dev
exit                 # kileptunk chroot-bol
zpool export helyi   # lecsatoljuk ZFS-t

Bootolás, ellenőrzés

szerkesztés

Leállítás, a live CD eltávolítása, bekapcsolás. A gépnek be kell bootolnia.

Ellenőrzések:

grub-probe /                # a root fájlrendszer zfs
free                        # nincs swap
zfs list                    # a datasetek listája a helyfoglalással
zfs mount                   # a felcsatolt datasetek
zfs get compressratio -r helyi   # a ZFS átlagos tömörítési aránya 1.8
systemctl list-unit-files --state enabled  # a bootkor elinduló szolgáltatások listája
ip addr list                # a hálókártyák és IP-címeik listája

Most kezdődik a konfigurálás és a szolgáltatások telepítése, de ez már túlnyúlik a szócikk keretein; egyedül a swap létrehozásával foglalkozunk.

A swap fájlrendszer nélküli diszkterület (raw disk), és ezt a ZFS-nek meg kell magyarázni. Ezeknek a területeknek – a ZFS fájlrendszerűekkel ellentétben – eszközfájljuk keletkezik /dev/zvol/poolnév/dataset néven, és a hagyományos módon, /etc/fstab-ban lehet őket kezelni. (Az így létrehozott területre nemcsak swap-ot, hanem akár a ZFS-től különböző fájlrendszert is lehet tenni. Ezt is tömöríti a ZFS, ha kérjük.)

A swapterület létrehozása:

zfs create -V 1G -b $(getconf PAGESIZE) -o compression=zle -o logbias=throughput \
        -o sync=always -o primarycache=metadata -o secondarycache=none \
        -o com.sun:auto-snapshot=false -o refreservation=200m  helyi/swap
mkswap /dev/zvol/helyi/swap
swapon /dev/zvol/helyi/swap
free

A -V jelzi, hogy raw diszket kell létrehozni, egyúttal a méretet is, mely a terület egyik tulajdonsága. Ez azt is jelenti, hogy a tulajdonság módosításával a swap mérete is változtatható (természetesen előbb a swap-ot le kell állítani, a méretváltoztatás után újra ki kell adni az mkswap utasítást). A méret változtatása:

zfs set volsize=2500m

(A volsize nem szerepelhet a -V-vel együtt, mert ilyenkor az eredmény – nyilván a raw diszk mérete – kiszámíthatatlan.)

A refreservation=200m 200m helyet fenntart a swap számára a közös területből, és ha onnan elfogyott a hely, a swap számára még mindig van 200m. (Ez ZFS fájlrendszerek esetén is megtehető: így lehet a dataset minimális méretét szabályozni.)

Hogy a következő bootolás után automatikusan legyen swap, /etc/fstab-ba:

/dev/zvol/helyi/swap    none            swap    sw         0 0
/dev/sda5               none            swap    sw         0 0

Konvertálás GPT-re

szerkesztés

A dolog nagyon egyszerű. A gdisk automatikusan konvertálja a memóriában a beolvasott partíciós táblát, és w-re diszkre írja.

A gdisk-et először fel kell installálni, célszerűen a parted-del együtt:

apt-get install gdisk parted

Ezt kaptuk a partíció gdisk-es módosítása után fdisk -l /dev/sda-ra:

Disk /dev/sda: 8 GiB, 8589934592 bytes, 16777216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 504D36E2-3CE0-4A4B-B510-3F70F5B11F8A

Device        Start      End  Sectors  Size Type
/dev/sda1      2048 15362047 15360000  7.3G Linux filesystem
/dev/sda5  15364096 15978495   614400  300M Linux swap

Az extended partíció eltűnt (ilyen nincs gpt-ben, hiszen felesleges). A rendszer működik partprobe /dev/sda (a partíciós tábla kernelbe olvasása) után is, de nem bootol. Nem csoda: megszűnt az mbr, ahol a grub első fázisa volt, és eltűnt a partíciók közötti hely, ahol a grub második fázisa eddig hajléktalan módjára meghúzta magát.

A bootolhatatlan gép helyreállításának első lépése, hogy megpróbáljuk kézzel, grub-utasításokkal bootolni. Itt most ez szóba sem jön: a grub el sem indult.[2]

Bootolhatatlan gép javítása live CD-vel

szerkesztés

Bebootoljuk a gépet a ZFS-tudó live CD-vel, és létrehozunk egy 10M méretű, 4-es típusú gpt-partíciót 2. partícióként a grub számára /dev/sda-n. Nem kell rá fájlrendszer. Most ilyen a partíciós tábla:

Device        Start      End  Sectors  Size Type
/dev/sda1      2048 15362047 15360000  7.3G Linux filesystem
/dev/sda2  15978496 15998975    20480   10M BIOS boot
/dev/sda5  15364096 15978495   614400  300M Linux swap

Beimportáljuk a ZFS poolt, ezzel felmountoljuk a diszket /mnt-re:

zpool import -R /mnt helyi

A szokásos módon bemegyünk chroot-ba, és installáljuk a grub-ot:

grub-install /dev/sda

Ugyancsak a szokásos módon kilépünk chroot-ból, és exportáljuk a poolt:

zpool export helyi

A gép most már diszkről is bootol: a live CD-vel megjavítottunk egy bootolhatatlan gépet.

Még egy próba

szerkesztés

Ha megér még egy próbát, nullázzuk ki a 2-es partíció elejét:

dd if=/dev/zero of=/dev/sda2 bs=1024 count=1024

Próbáljunk bootolni: nem sikerül. Tényleg ide került a grub.

Bootoljunk live CD-vel, hozzunk létre egy 6. partíciót 4-es típussal, a kinullázott 2. partíció típusát változtassuk meg, pl. 1-re (EFI System[3]):

Device        Start      End  Sectors  Size Type
/dev/sda1      2048 15362047 15360000  7.3G Linux filesystem
/dev/sda2  15978496 15998975    20480   10M EFI System
/dev/sda5  15364096 15978495   614400  300M Linux swap
/dev/sda6  15998976 16019455    20480   10M BIOS boot

Installáljuk a grubot a fenti módon: a gép bootolni fog, miközben a 2. partícióban továbbra is 0-k vannak:

hexdump -C /dev/sda2

Most már talán elhihetjük, hogy akárhol hozzuk is létre a BIOS boot partíciót, a grub bele tud települni, és bootolható lesz a gépünk. Ez fontos, ha éles gépen tervezzük a fenti akciót. (Azért mindenképpen mentsünk előtte, mert a gpt→mbr irány jóval macerásabb.)

  1. Hacsak a diszk maga már nem hardver RAID, pl. SAN-terület.
  2. A második lépés a live/rescue CD, a harmadik a visszatöltés mentésből. Ez utóbbit kerüljük, hiszen az utolsó mentéstől a visszatöltésig keletkezett/módosult adatok elvesznek.
  3. Önmagában ez még nem teszi UEFI-módban bootolhatóvá a gépet.