Datenverzeichnisse außerhalb des Jails mit NullFS verbinden

Bestimmte Verzeichnisse innerhalb einer Jail können in "externe" (Datasets) ausgelagert werden. Dadurch werden diese Daten unabhängig vom Jail gespeichert. Ziel ist es, ähnlich wie bei Docker, so wenig wie möglich vom Jail selbst abhängig zu sein. Sollte die Jail aus irgendeinem Grund beschädigt oder gelöscht werden, ist man so in der Lage, die vorherige Konfiguration und die Daten mit minimalem Aufwand wiederherzustellen. Außerdem können diese Verzeichnisse dann effizient und regelmäßig per Snapshot gesichert werden, was auch weitere Backups vereinfacht. Ganz zu schweigen von Umzügen oder Migrationen.

Die Verwaltung in TrueNAS wird mit iocage verwaltet und ist vorinstalliert, kann aber auch in FreeBSD mit pkg install iocage installiert und genutzt werden. Der Vorteil ist, das entweder über die TrueNAS GUI oder eine reine Shell die wichtigsten Einstellungen und Anpassungen vorgenommen werden können. War beleuchten hier mal beides.

Letzte Aktualisierung:

  • 23.01.2024: Etwas getrafft und Konfiguration in TrueNAS aufgenommen
  • 18.08.2023: Initiale Version

Begrifflichkeiten

  • JAILNAME = Der Name des Jails, z.B. gitea
  • QUELLPFAD = Das Verzeichnis (DATASET) auf dem TrueNAS/FreeBSD, z.B. /mnt/tank/jails_data/gitea/data
  • ZIELPFAD = Das Verzeichnis innerhalb des Jails, z.B. /mnt/tank/iocage/jails/gitea/root/var/db/gitea
  • ID = Benötigte Benutzer-ID innerhalb des Jails, z.B. 211
  • ZPOOLNAME = Der Poolname, welches die Daten enthält, z.B. tank

Verzeichnisstruktur

Jails werden in aller Regel in /usr/jails oder unter TrueNAS in /mnt/ZPOOLNAME/iocage/jails mit folgender Verzeichnisstruktur abgelegt:

└── jails         # Jail Wurzelverzeichnis
    └── JAILNAME  # Jail Name
        └── root  # Root des Jails, das / im Jail

Dazu wird nun ein neues Dataset mit dem Namen jails_data angelegt, welches die "Jail Daten" beherbergt und die obige Struktur etwas widerspiegelt, damit es leicht nachvollziehbar bleibt. Das kann z.B. auch auf einem ganz anderen Pool /mnt/ZPOOLNAME/jails_data liegen, welcher vielleicht wesentlich mehr Speicherplatz besitzt. Das ist sehr praktisch bei grossen Datenhalden wie Bildern oder Dateifreigaben, die im Jail direkt einfach nix verloren haben. Auch nur lesend falls benötigt.

└── jails_data     # Als Gegenstück zu jails
    └── JAILNAME   # Der gleiche Name wie in Jails, z.B. `gitea`
        └── DATASET  # Zielverzeichnisse für die ausgelagerten Daten, z.B. `data`

NullFS

Aber wie kommt das zusammen? Ganz einfach über NullFS. NullFS legt quasi den Inhalt von Verzeichnis A auf Verzeichnis B, auch über Jailgrenzen hinweg. Sehr praktisch! Ein wesentlicher Faktor sind die Zugriffsrechte und die richtigen Berechtigungen. Wenn es in der Jail einen Benutzer USER mit der ID 123 gibt, dann MUSS das Verzeichnis außerhalb der Jail die gleichen Rechte haben. Glücklicherweise reicht dafür die Benutzer-ID aus, es muss also nicht jedes Mal auch der entsprechende Benutzername im TrueNAS/FreeBSD Host angelegt werden. Da die Verzeichnisse meist noch nicht in der Jail existieren, müssen diese vorher angelegt werden. Eigentlich werden diese erst bei der Installation der Pakete angelegt, was aber zu spät ist. Denn während der Installation wird der Inhalt im Zielverzeichnis oft schon mit angelegt.

Alles was hier ausgeführt nachfolgend wird, passiert auf dem TrueNAS/FreeBSD Host. NICHT innerhalb des Jails!

Direkt in der Shell

Das Jail muss jedesmal mit iocage restart JAILNAME neu gestartet werden, damit die neuen Pfade eingebunden werden.
Mit iocage fstab -e JAILNAME können die einmal gesetzten Einträge nachträglich angepasst oder entfernt werden.

zfs create -p ZPOOLNAME/jails_data/JAILNAME/DATASET # QUELLPFAD (Dataset) in jail_data erstellen
chown -R ID:ID QUELLPFAD                            # Benutzer setzen, es reicht die nackte ID, z.B. `211`
iocage start JAILNAME                               # Jail starten
iocage exec -f JAILNAME "install -d ZIELPFAD"       # Verzeichnis im Jail anlegen (als root) oder
iocage exec -f JAILNAME "install -d -g USERID -o GROUPID ZIELPFAD" # als Benutzer (z.B. 211 für Gitea)
iocage fstab -a JAILNAME QUELLPFAD ZIELPFAD nullfs rw 0 0 # Verzeichnisse einbinden  
iocage stop JAILNAME                             # Jail stoppen

Über TrueNAS

Benutzer erstellen

  • TrueNAS / Accounts / Groups / Add
    GID: ID # z.B. 211
    Name: NAME # z.B. gitea
  • TrueNAS / Accounts / Users / Add
    Full Name: NAME    # z.B. Gitea User
    Username: USERNAME # z.B. gitea
    Password: PASSWORD # z.B. 123
    User ID: ID        # z.B. 211
    Primary Group: ID  # z.B. 211
    Shell: nologin     # Kein Login per SSH
    Home: /nonexistent # Kein Home Verzeichnis

Datenverzeichnisse (DATASET) erstellen

  • TrueNAS / Storage / Pools / tank/jails_data/JAILNAME / Add Dataset
    Name: POOLNAME # z.B. data

    Datenverzeichnisse Berechtigungen

  • TrueNAS / Jails / Mount Points / tank/jails_data/JAILNAME / Edit Permissions
    User: ID  # z.B. 211
    Group: ID # z.B. 211

Datenverzeichnisse einbinden

Prakisch: Die Zielverzeichnisse im Jail werden automatisch angelegt, wenn die Mount Punkte zugeordnet werden. Auch rekursiv!

  • TrueNAS / Jails / JAILNAME / Mount Points / Actions / Add
    data:
    └── Source: QUELLPFAD     # z.B. /mnt/tank/jails_data/gitea/data
    └── Destination: ZIELPFAD # z.B. /mnt/tank/iocage/jails/gitea/root/var/db/gitea

Damit zeigt im Jail GITEA das Verzeichnis /var/db/gitea auf das eigentlich extern liegende Verzeichnis /mnt/tank/jails_data/gitea/data.
Alles klar? Gut!

Voilá

Wenn Du diese Inhalte für wertvoll und nützlich findest, dann freue ich mich über eine Rückmeldung per Matrix, folge mir doch auf Mastodon oder hinterlasse hier einen Kommentar.