UnionFS für Diskless Clients benutzen¶
UnionFS erlaubt es verschiedene Dateisysteme oder Verzeichnisse zu stapeln, ohne sich wie sonst üblich zu überdecken. Benutzer und Kernel schauen von oben auf diese Schichtung drauf und alles sieht erstmal so aus wie gewohnt. Dateien von darunterliegenden Dateisystemen scheinen durch, wenn sie nicht ein weiteres Mal mit dem identischen Namen in einer höheren Ebene "näher am Betrachter" vorhanden sind. Die Besonderheit besteht im Schreibverhalten auf den einzelnen Schichten, das bei UnionFS beliebig auf nur lesbaren oder auch schreibbaren Zugriff festgelegt werden kann. So wird aus einer nur lesbaren Live-CD durch darüberlegen des beschreibbaren TempFS einer Ramdisk ein insgesamt beschreibbares Root-Dateisystem. Dateien auf dem nur lesbaren Medium, an denen Änderungen vorgenommen wurden, werden als Kopie in die Ramdisk verschoben und dort verändert.
Probleme und Lösungen¶
Für Diskless Clients bietet es sich natürlich an, ein UnionFS direkt auf oberster Ebene an / einzuhängen und so ein nur lesbares NFS oder Network Blockdevice zu vereinigen. Diese Aktion veranlasst man am besten im Initialramfs, das vor dem eigentlichen init des Linux-Systems ausgeführt wird.
Dazu muss das Unionfs-Modul im Stage 2 des Systems vorhanden sein. Wird dann die Kernel-Option unionfs angegeben oder die Variable unionfs in machine-setup auf "true" gesetzt, wird das Modul in Stage 3 nach Mounten des Stage 2 Images geladen und eine Ramdisk als schreibbare Schicht über den RO-Netzwerkmountpoint gelegt. Das Ergebnis sieht dann auch gut aus: So ist im Beispiel ein Network Blockdevice mit SquashFS das nur lesbare Client-Rootverzeichnis, welches mit UnionFS transparent überdeckt wird:
linux02:~ # cat /proc/mounts rootfs / rootfs rw 0 0 initramfsdevs /dev tmpfs rw 0 0 /dev/nbd0 /mnt squashfs ro 0 0 none /uniontmp tmpfs rw 0 0 none / unionfs rw,dirs=/uniontmp=rw:/mnt=ro,debug=0,delete=whiteout,copyup=preserve 0 0 proc /proc proc rw,nodiratime 0 0 devpts /dev/pts devpts rw 0 0 sysfs /sys sysfs rw 0 0 tmpfs /dev/shm tmpfs rw 0 0 automount(pid12018) /home autofs rw 0 0
So hängt das Blockdevice virtuell aber für den Admin und die meisten normalen Programme unsichtbar an /mnt, das UnionFS an / und der RW-Bereich des UnionFS an /uniontmp.
Während in einem klassischen Diskless Client die Ramdisk viel mehr Dateien aufnehmen muss – viele Bereiche von /etc oder auch /var, bleibt der Platzbedarf unter Verwendung von UnionFS sehr klein. In diesem Szenario landen nur wirklich veränderte Dateien im RW-Bereich. Der Unterschied macht schnell mehr als 20MByte aus.
Leider ist die Welt noch nicht perfekt, da zwar für den Admin unsichtbar, der Linux-Kernel immer noch den kompletten Pfad zu den Programmen auflöst. Damit kommen dann Tools wie startproc, checkproc oder killproc, die beispielsweise SUSE in seinen Runlevel-Skripten verwendet, nicht klar. Laufende oder gestartete Prozesse werden nicht erkannt, da der scheinbare und reale Pfad nicht übereinstimmen.
Die (fehlendes) mmap Seiteneffekte bekommt man aber mit einem Patch des Klibc-Tools run-init in den Griff:
/* Delete rootfs contents */
if ( nuke_dir("/") )
die("nuking initramfs contents");
/* wild guess and try&error */
if ( !lstat("/rorootfs", &rfs ) )
if ( mount("/rorootfs", "/", NULL, MS_MOVE, NULL) )
die("moving rorootfs");
/* Overmount the root */
if ( mount(".", "/", NULL, MS_MOVE, NULL) )
die("overmounting root");
Vor dem entscheidenden Movemount für das "Union"-Root-Verzeichnis wird noch ein Movemount auf das drunterliegende eigentliche Root-Filesystem angewendet. Das scheint erstmal zu klappen. Dazu checkt nun run-init ob ein /rorootfs da ist und verschiebt das dann. Wenn nicht,
bleibt das Verhalten so wie vorher.
Dynamisches Ein- und Aushängen¶
Man ist nicht darauf angewiesen, dass schon zum Zeitpunkt der Erstvereinigung alle teilnehmenden Verzeichnisse feststehen. Es gibt die Möglichkeit im laufenden Betrieb weitere hinzuzufügen oder auch welche zu entfernen.
Im UnionFS-Paket ab Version 1.2 findet sich im Unterverzeichnis ~/utils, sonst im Hauptverzeichnis, das kleine Hilfsprogramm unionctl. Ohne Optionen oder Parameter gibt unionctl einfach eine kurze Bedienungsanleitung aus, aufgerufen mit dem Namen des Vereinigungspunktes, sagt das Programm an, woraus eine Union besteht:
ibm-x20:/tmp # unionctl vereinigung --list
/tmp/verz1 (rw-)
/tmp/verz2 (rw-)
ibm-x20:/tmp # mkdir verz3
ibm-x20:/tmp # touch verz3/datei_Z
ibm-x20:/tmp # unionctl vereinigung --add --mode ro verz3
ibm-x20:/tmp # unionctl vereinigung --list
/tmp/verz3 (r--)
/tmp/verz1 (rw-)
/tmp/verz2 (rw-)
ibm-x20:/tmp # ls vereinigung/
datei_A datei_B datei_C datei_D datei_E datei_Z
ibm-x20:/tmp # unionctl vereinigung --remove verz3
ibm-x20:/tmp # ls vereinigung/
datei_A datei_B datei_C datei_D datei_E
Mit diesem Programm erlaubt UnionFS dem Administrator dynamisch an einer Vereinigung herumzubauen. So wird im Beispiel ein weiteres Testverzeichnis verz3 angelegt und anschliessend der Vereinigung hinzugefügt. Das neue Verzeichnis taucht jedoch nicht in der Angabe von Mount auf. Das gilt ebenso für das Entfernen des gerade hinzugefügten oder eines der ursprünglichen Verzeichnisse.
Eine sicherlich ebenfalls nützliche Funktion ist die Fähigkeit von unionctl zu einer Datei ihr ursprüngliches Verzeichnis herauszufinden, da man das in der Vereinigung nicht mehr erkennen kann:
ibm-x20:/tmp # ls vereinigung/ datei_A datei_B datei_C datei_D datei_E test test2 ibm-x20:/tmp # unionctl vereinigung/datei_A --query vereinigung/datei_A /tmp/verz1 (rw-) ibm-x20:/tmp # unionctl vereinigung/datei_C --query vereinigung/datei_C /tmp/verz2 (rw-)
Das Programm könnte im Initialramfs beispielsweise dazu eingesetzt werden, Admins zu erlauben, aus weiteren Quellen das Client-Rootfilesystem zusammenzusetzen.
Stapeln verschiedener FS-Quellen auf dem FS Root¶
Steht UnionFS zur Verfügung, gibt es die Möglichkeit das Rootfilesystem, zusätzlich zur Schreibbarkeitsschicht, durch Überlagerung zusätzlicher Netzwerkquellen weiter anzureichern.
Sinn dessen könnte es z.B. sein, ein Basissystem mit verschiedenen Softwareerweiterungen auszustatten, die sich gegenseitig ausschließen (Verschiedene Versionen des gleichen Programms), oder wegen Lizenzbedingungen nur Beschränkt zur Verfügung stehen dürfen. Auch möglich wäre es diverse Einstellungen Clientabhängig einzubinden.
Momentan wird nur das Einbinden von NFS-Shares unterstützt. Dazu reicht es diese für den Client zugänglich zu exportieren und die Option unionfs in der Kernel-Commandline oder in der Datei machine.setup auf die zu benutzenden URIs zu setzen.
Der Wert der Variable folgt dem Schema protokoll://hostname/path/to/targetdir also z.B. nfs://123.45.67.89/openslx/srv/export/my_union.
Mehrere URLs können mit Kommata getrennt angegeben werden.
Die Dateistruktur unter den angegebenen Branches werden dann der Reihe nach über das Root-Filesystem gestapelt, so dass z.B. Dateien unter nfs://123.45.67.89/openslx/srv/export/my_union/etc im Client in Stage 4 unter /etc wiederzufinden sind.