Einleitung

Ich glaube es müssen heute nicht mehr viele Worte verloren werden, wie großartig ZFS als Dateisystem ist. Das hat sich rumgesprochen. Hier wird aufgeführt wie neue Festplatten in einen ZFS Pool integriert werden und was die ersten Schritte damit sind, so das die eigenen Daten ein ordentliches Zuhause bekommen. In diesem Artikel werden die Festplatten vorbereitet, die ZFS Pools angelegt und einige Optimierungen vorgenommen.

NEU: Für ganz ungeduldige habe ich einen Konsole only Abschnitt. Da gibts nur Befehle, keine Erklärungen.

Letzte Aktualisierung:

  • 01.12.2024: Kleines Tuning mit glabel und gpart. Fehler behoben bei zpool create. TRIM und SCRUB aktiviert. Platzhalter Dataset eingefügt.
  • 16.11.2024: Initiales Dokument

Grundbedingungen

  • Die Grundeinstellungen für das System wurden vorgenommen
  • Wie bereits in Hauptartikel skizziert, sind die Daten auf mehrere ZFS-Pools verteilt, um sie unabhängig vom Basissystem getrennt zu speichern:
    • Die Daten liegen auf einem Festplattenverbund im raidz2 (data) und werden hier als Devices ada0 - ada3 aufgeführt.
    • Die VMs und Jails liegen auf zwei gespiegelten SSDs (work) mit den Geräten ada4 - ada5.

Partitionieren

Bevor die Festplatten in einem ZFS-Pool zusammengefasst werden, empfehle ich einige Vorbereitungen zu treffen, um sicherzustellen, dass die Festplatten auf jeden Fall leer sind, immer das gleiche Partitionsschema haben und vor allem auch einen sinnvollen Namen tragen.

Festplatten löschen

Mit gpart destroy DEVICE wird die Festplatte einmal komplett von allem befreit, was später stören könnte.
Eine Liste mit den erkannten Festplatten lässt sich mit camcontrol devlist erstellen:

<WDC WD40EFPX-68C6CN0 81.00A81>    at scbus0 target 0 lun 0 (pass0,ada0)
<WDC WD40EFPX-68C6CN0 81.00A81>    at scbus1 target 0 lun 0 (pass1,ada1)
<WDC WD40EFPX-68C6CN0 81.00A81>    at scbus2 target 0 lun 0 (pass2,ada2)
<WDC WD40EFPX-68C6CN0 81.00A81>    at scbus3 target 0 lun 0 (pass3,ada3)
<SAMSUNG MZ7LH480HAHQ-00005 HXT7404Q>  at scbus4 target 0 lun 0 (pass4,ada4)
<SAMSUNG MZ7LH480HAHQ-00005 HXT7904Q>  at scbus5 target 0 lun 0 (pass5,ada5)
<AHCI SGPIO Enclosure 2.00 0001>   at scbus6 target 0 lun 0 (ses0,pass6)
<ATP NVMe M.2 2280 SSD A230W2EJ>   at scbus7 target 0 lun 1 (pass7,nda0)

**Wichtig: Passt die Geräte an! Eventuell bereits auf den Festplatten vorhandene Daten werden unwiederbringlich zerstört.

gpart destroy -F ada0 # Zerstört die Partitionstabelle auf ada0
gpart destroy -F ada1
gpart destroy -F ada2
gpart destroy -F ada3

gpart destroy -F ada4
gpart destroy -F ada5

Festplatten initialisieren

Mit gpart create -s TYPE DEVICE bekommen die Festplatten eine gewisse Grundstruktur, was besonders für den späteren Fall wichtig ist, wenn eine Festplatte ausfällt und ersetzt werden muss.

gpart create -s gpt ada0 # Erstellt eine neue Partitionstabelle auf ada0
gpart create -s gpt ada1
gpart create -s gpt ada2
gpart create -s gpt ada3

gpart create -s gpt ada4
gpart create -s gpt ada5

Seriennummer auslesen

Was hier schon deutlich wird, ada0 - ada5 ist wenig "griffig und nachvollziehbar", auch kann sich die Reihenfolge und die Gerätenamen durchaus mal ändern. Problematisch wird es auf jeden Fall, wenn die Festplatten mal auf einen neuen Server umgezogen werden, was die Gerätenamen komplett auf den Kopf stellt. Eine Zuordnung ist dann schwierig. Auch in einem größeren Festplattenverbund ist es mühsam, eine defekte Festplatte zu identifizieren und gezielt auszutauschen. Die Lösung: Um die Festplatte mit einem Namen ansprechen zu können, bekommt sie einfach einen. Am besten mit etwas, das sowieso schon auf der Festplatte steht: Die Seriennummer.

Automatisch

Ganz mutige können das auch in einer Schleife ablaufen lassen (ada0 ada1 ada2 ada3 ada4 ada5 anpassen!).

DEVICELIST="ada0 ada1 ada2 ada3 ada4 ada5"; for DEVICE in $DEVICELIST; do gpart create -s gpt $DEVICE && gpart add -t freebsd-zfs -l "$(camcontrol identify $DEVICE | sed -n 's/.*serial number.*\(.\{4\}\)$/\1/p')" -a 4K "$DEVICE"; done

Welche Festplatte dann welches Label erhalten hat, lässt sich mit diesem Befehl kontrollieren:

glabel list | grep -E "Geom name|1\. Name: gpt" | awk -F": " '/Geom name/ {geom=$2}/1\. Name/ {name=$2; print geom " = " name}' | sort

Manuell

Wem die Schleife nicht geheuer ist, die einzelnen Schritte sind wie folgt:

Mit camcontrol identify DEVICE | sed -n 's/.*serial number.*\(.\{4\}\)$/\1/p' werden die letzten 4 Stellen der Seriennummer ermittelt und notiert.

ada0: HPAS (aus serial number WD-XXXXXXXXHPAS)
ada1: E9EY (aus serial number WD-XXXXXXXXE9EY)
ada2: 46EE (aus serial number WD-XXXXXXXX46EE)
ada3: LLAK (aus serial number WD-XXXXXXXXLLAK)

ada4: 2482 (aus serial number SXXXXXXX2482)
ada5: 7815 (aus serial number SXXXXXXX7815)

Bei der Partitionierung mit gpart add -t FILESYSTEM -l LABEL -a BLOCKSIZE DEVICE wird der ermittelte Name direkt als Label gespeichert. Praktisch, oder?

gpart add -t freebsd-zfs  -l "HPAS" -a 4K "ada0" # Erstellt eine neue FreeBSD Partition mit dem Namen HPAS
gpart add -t freebsd-zfs  -l "E9EY" -a 4K "ada1"
gpart add -t freebsd-zfs  -l "46EE" -a 4K "ada2"
gpart add -t freebsd-zfs  -l "LLAK" -a 4K "ada3"

gpart add -t freebsd-zfs  -l "2482" -a 4K "ada4"
gpart add -t freebsd-zfs  -l "7815" -a 4K "ada5"

Pools einrichten

Damit sind die Platten bereit, um mit zpool create -m MOUNTPOINT POOLNAME RAIDTYPE DEVICELIST zu ZFS-Pools zusammengefasst zu werden. Hier wird nun deutlich, wie hilfreich die neu vergebenen Namen sind. Diese neuen Pools werden im klassischen TrueNAS-Stil unter /mnt/ gemountet.

zpool create -m /mnt/data data raidz2 /dev/gpt/HPAS /dev/gpt/E9EY /dev/gpt/46EE /dev/gpt/LLAK # Erstellt Zpool data als raidz2
zpool create -m /mnt/work work mirror /dev/gpt/2482 /dev/gpt/7815 # Erstellt Zpool work als Spiegelung

Pools tunen

Das ist ein bisschen Geschmackssache. Aus meiner Sicht sind aber einige Attribute durchaus sinnvoll, um die Daten effizient zu speichern und die Festplatten zu entlasten. Dies wird mit sogenannten ZFS-Attributen erreicht, die später von der Hauptebene auf die darunter angelegten Volumes und Datasets vererbt werden. Daher ist es sinnvoll, diese direkt bei der Installation zu setzen.

  • zfs set compression=lz4 = Komprimiert Dateien im laufenden Betrieb und ermöglicht so die Speicherung von mehr Daten auf begrenztem Speicherplatz
  • zfs set atime=off = Verbesserung der Leistung auf Dateisystemen mit vielen kleinen Dateien, auf die häufig zugegriffen wird
  • zfs set xattr=sa = Speichert erweiterte Attribute in Inodes, was zu weniger Festplattenanforderungen führt
  • zfs set acltype=posixacl = Ermöglicht die Verwendung von getfacl, setfacl für zusätzliche Zugriffsrechte
zfs set compression=lz4 atime=off xattr=sa acltype=posixacl data # Schreibt die Attribute auf den Pool data
zfs set compression=lz4 atime=off xattr=sa acltype=posixacl work

Regelmäßige TRIM und SCRUB Aufgaben ausführen

  • https://man.freebsd.org/cgi/man.cgi?query=trim Das Trim-Dienstprogramm löscht einen bestimmten Bereich des Geräts. Es ist vor allem für Speicher relevant, die Trim implementieren (z. B. Flash-basierte oder Thinly-Provisioned-Speicher). Alle gelöschten Daten sind verloren.
  • https://man.freebsd.org/cgi/man.cgi?query=zpool-scrub Der Scrub prüft alle Daten in den angegebenen Pools, um sicherzustellen, dass die Prüfsummen korrekt sind. Bei replizierten Geräten (Mirror, Raidz oder Draid) repariert ZFS automatisch jeden Schaden, der während des Scrubs entdeckt wird.
    sysrc -f /etc/periodic.conf daily_scrub_zfs_enable="YES"
    sysrc -f /etc/periodic.conf daily_trim_zfs_enable="YES"
    sysrc -f /etc/periodic.conf daily_status_zfs_enable="YES"

Platz reservieren

  • Stefano Marinelli hat da noch einen guten Tipp, um Pool Probleme bei zu wenig oder keinem Speicherplatz zu verhindern:
    Wie alle CoW (Copy-on-Write)-Dateisysteme ist ZFS nicht in der Lage, Speicherplatz freizugeben, wenn es vollständig gefüllt ist. Wenn wir reservierten Speicherplatz anlegen, kann das System ihn immer wieder freigeben und andere Daten löschen, so dass das System weiter normal funktioniert. Keine Sorge, das ist nur eine Reservierung, kein fest zugeordneter Speicherplatz.
    zfs create data/reserved && zfs set reservation=5G data/reserved
    zfs create work/reserved && zfs set reservation=5G work/reserved
    zfs create zroot/reserved && zfs set reservation=5G zroot/reserved

Mit zpool status data kann das Ergebnis überprüft werden.

  pool: data
  state: ONLINE
  scan: scrub repaired 0B in 00:03:52 with 0 errors on Fri Nov  8 00:07:34 2024
  config:

    NAME          STATE     READ WRITE CKSUM
    data          ONLINE       0     0     0
      raidz2-0    ONLINE       0     0     0
        gpt/HPAS  ONLINE       0     0     0
        gpt/E9EY  ONLINE       0     0     0
        gpt/46EE  ONLINE       0     0     0
        gpt/LLAK  ONLINE       0     0     0

Damit haben wir die Festplatten eingerichtet und die Daten können sicher gespeichert werden.

Konsole

Am Beispiel mit ada0 - ada3 für zpool data und ada4 - ada5 für zpool work. Wichtig: Passt die Geräte an! Eventuell bereits auf den Festplatten vorhandene Daten werden unwiederbringlich zerstört.

Voilá