Arch Linux - Einrichten eines NFS4 Servers
Der Network File Service/Serviceist eine der nativen Methoden zur Freigabe von Dateien und Anwendungen über das Netzwerk in der Linux/UNIX-Welt. Der Dienst NFS, der ursprünglich von Sun Microsystems entwickelt wurde, ermöglicht es auf Dateien in einem Netzwerk zuzugreifen, die sich auf einem entfernten Rechner befinden, genauso wie auf lokal gespeicherten Dateien des Clients. Es ist also ein äußert praktisches Werkzeug, für die Speicherung und Nutzung großer Datenmengen unter Benutzern in einem Netzwerk bzw. von unterschiedlichen Anwendungen auf verteilten Applikations-Servern.
Weitere Hintergründe und Erklärungen finden sich in dem gut dokumentierten Wikipedia-Artikel.
In diesem Artikel wollen wir im Detail auf folgende generelle Themen bzw. auf ArchLinux spezifische Konfigurationsoptionen eingehen:
- Vergleich zwischen NFSv2, NFSv3 und NFSv4
- Konfiguration von NFS-Server und -Client mit NFSv4 unter Archlinux.
- Persistenter und nicht-persistenter Zugriff auf NFS-Freigaben unter Linux
Vergleich der unterschiedlichen NFS-Versionen
NFSv2
Version 2 des Protokolls (definiert in RFC 1094, März 1989) lief ursprünglich ausschließlich via UDP1). Die Virtual File System-Schnittstelle ermöglicht eine modulare Implementierung, was sich in einem einfachen Protokoll widerspiegelt. Bis Anfang 1986 wurden Implementierungen für Betriebssysteme wie System V Release 2, DOS und VAX/VMS unter Verwendung von Eunice demonstriert. NFSv2 erlaubte aufgrund von 32-Bit-Beschränkungen nur das Lesen der ersten 2 GB einer Datei.
- Mount-Anfragen werden nur auf Host-Basis und nicht auf Benutzerbasis gewährt.
- Clients der Version 2 haben eine Dateigrößenbeschränkung von weniger als 2 GB, auf die sie zugreifen können, da auf Grund der 32-Bit-Beschränkungen nur das Lesen der ersten 2 GB einer Datei möglich ist.
NFSv3
Mit Version 3 RFC 1813, dessen Hauptmotivation es war, das Leistungsproblem der synchronen Schreiboperation in NFS Version 2 zu beheben, wurde im Juli 1995 unter anderem Folgende Punkte eingeführt:
- Unterstützung für 64-Bit-Dateigrößen und -Offsets, um Dateien mit einer Größe von mehr als 2 Gigabyte (GB) verarbeiten zu können;
- Unterstützung für asynchrone Schreibvorgänge auf dem Server, um die Schreibleistung zu verbessern;
- zusätzliche Dateiattribute in vielen Antworten, um ein erneutes Abrufen dieser Attribute zu vermeiden;
- eine READDIRPLUS-Operation, um beim Durchsuchen eines Verzeichnisses neben den Dateinamen auch Datei-Handles und Attribute abzurufen;
- Mount-Requests werden zudem auf Host-Basis und nicht auf Benutzerbasis bewilligt.
NFSv4
Ein großer Vorteil von NFSv4 gegenüber seinen Vorgängern besteht vor allem darin, daß für den Betrieb des Dienstes nur ein einziger UDP- oder TCP-Port (2049) verwendet wird, was die Nutzung des Protokolls über Firewalls hinweg vereinfacht. NFS Version 4.2 RFC 7862 wurde im November 2016 veröffentlicht und enthält folgende neue Funktionen: serverseitiges Klonen und Kopieren, Speicherplatzreservierung und Sparse-Dateien, sowie weitere Optimierungen.
- Diese Version des Protokolls nutzt ein zustandsbehaftetes Protokoll wie TCP oder das SCTP4) als Transportprotokoll.
- Die Dienste der RPC-Bindungsprotokolle (wie
rpc.mountd,rpc.lockdundrpc.statd) sind in dieser Version von NFS daher nicht mehr erforderlich, da ihre Funktionalität in den Server integriert wurde - NFSv4 vereint diese zuvor getrennten NFS-Protokolle in einer einzigen Protokollspezifikation. - Es bietet Unterstützung für ACL-Attribute (File Access Control List) und kann sowohl Version-2- als auch Version-3-Clients unterstützen.
- NFSv4 führt das Konzept des Pseudo-Dateisystems ein, welche es NFSv4-Clients ermöglicht, die auf dem NFSv4-Server exportierten Dateisysteme als ein einziges Dateisystem zu sehen und darauf zuzugreifen.
Installation und Konfigurationen
NFS-Server Installation unter Archlinux
Unter Archlinux wird auf dem Server wie auch auf den Clients lediglich das Paket nfs-utils benötigt. Dieses Paket installieren wir uns nun auf unserem Server.
$ sudo pacman -S nfs-utils
bzw.
# pacman -S nfs-utils
Wollen wir wissen was uns dieses Paket alles in unser System gespült hat, hilft ein Blick in die Dateiliste des Paketes.
# pacman -Qil nfs-utils
Dokumentation
Hilfe findet man wie immer in den zugehörigen man-Pages. Werfen wir kurz einen Blick in die nfs-Manpage.
# man nfs
Selbiges machen wir auch mit dem Befehl exportfs indem wir in dessen Man-Page bei Bedarf einen Blick werfen.
# man exportfs
Konfiguration des NFS-Servers
pseudo-Root-NFS-Verzeichnis
Wie schon beim Vergleich der NFS-Versionen angemerkt, wurde mit NFSv4 das Konzept des Pseudo-Dateisystems eingeführt, welche es NFSv4-Clients ermöglicht, die auf dem NFSv4-Server exportierten Dateisysteme als ein einziges Dateisystem zu sehen und darauf zuzugreifen. Diesen Konfigurationspunkt wollen wir nun als erstes erledigen.
Eine bewährte Sicherheitspraxis besteht darin, Freigaben relativ zum sogenannten NFS-Stammverzeichnis zu definieren, wodurch Benutzer auf diesen Mountpoint beschränkt bleiben. Hierzu verwendet man sogenannte Bind-Mounts mit denen dann der Mountpoint der Freigabe mit dem eigentlichen Verzeichnis an einer anderen Stelle im Dateisystem verknüpft wird. Durch Konfiguration dieses pseudo-root Verzeichnisses für NFS Exports wird der exportierte Pfad unabhängig vom echten Pfad auf dem Server, was auch ggf. bei einem Umzug von Verzeichnissen und Dateien sehr hilfreich sein kann.
Im ersten Schritt erstellen wir nun unser Export-Verzeichnis /exports welches später alle Verzeichnis-Exports enthalten soll und fassen dort dann alle Daten mittels Bind-Mounts zusammen.
# mkdir /exports
In unserem Konfigurationsbeispiel wollen wir das Verzeichnis /usr/local/src/ auf unserem NFS-Server, via NFS anderen Hosts zur Verfügung stellen, ebenso wie das Verzeichnis /srv/nfs.
- Als erstes Verknüpfen wir also das Verzeichnis
/usr/local/src/mit dem Unterverzeichnis/exports/src. Das betreffende Unterverzeichnis erstellen wir nun noch.# mkdir /exports/src
Anschließend binden wir die beiden Verzeichnisse zusammen.
# mount --bind /usr/local/src/ /exports/src
- Gleiches machen wir nun noch mit der NFS-Partition:
# mount --bind /srv/nfs /exports
- Das Verzeichnis
/proc/mountenthält eine Liste aller auf dem System gemounteten Dateisysteme. Wir können seinen Inhalt mit dem Befehlcatlesen, um auf die Liste zuzugreifen. Werfen wir also kurz einen Blick in die nun gemounteten Dateisysteme.# cat /proc/mounts | grep exports
/dev/sda2 /exports/src btrfs rw,relatime,space_cache=v2,subvolid=256,subvol=/@ 0 0 /dev/sda3 /exports btrfs rw,relatime,space_cache=v2,subvolid=256,subvol=/@nfs 0 0
- Damit nun bei einem Neustart des Servers unser Pseudo-Root-NFS-Verzeichnis automatisch zur Verfügung steht, tragen wir diese am Ende der Konfigurationsdatei
/etc/fstabein.# vim /etc/fstab
... /exports /srv/nfs none bind 0 0 /exports/src /usr/local/src none bind 0 0
Export der Verzeichnisse für die Clients
Nun konfigurieren wir den eigentlichen Verzeichnis-Export für unsere Client-Maschinen. Wie immer erstellen wir zunächst eine Kopie der Konfigurationsdatei des Archlinux-Paketes.
# cp -av /etc/exports /etc/exports.orig
Anschließend exportieren wir als erstes unser pseudo-Root-NFS-Verzeichnis /exports. Hierzu bearbeiten wir die Konfigurationsdatei /etc/exports wie folgt.
# vim /etc/exports
- /etc/exports
# Pseudo-root für NFSv4 /exports 10.0.10.239/32(rw,no_subtree_check,fsid=root,crossmnt) # Export des Unterverzeichnisses 'src' /exports/src 10.0.10.239/32(rw,async,sec=sys,no_subtree_check)
Mit nachfolgendem Befehl können wir die exportierten Verzeichnisse anhand der oben vorgenommenen Konfiguration aktualisieren.
# exportfs -rv
exporting 10.0.10.239/32:/exports/src exporting 10.0.10.239/32:/exports
Nach erfolgreicher Änderung der exportierten Verzeichnisse bzw. auch jederzeit zur Überprüfung kann man bei Bedarf die aktuell aktiven exportierten Verzeichnisse wie folgt abfragen.
# exportfs -v
/exports 10.0.10.239/32(sync,wdelay,hide,crossmnt,no_subtree_check,fsid=0,sec=sys,rw,root_squash,no_all_squash) /exports/src 10.0.10.239/32(async,wdelay,hide,no_subtree_check,sec=sys,rw,root_squash,no_all_squash)
Firewall/Paketfilter - firewalld
Bevor wir nun unseren NFSv4 Server starten, müssen wir natürlich sicherstellen, daß auf dem betreffendem Host auch die Kommunikationsbeziehungen entsprechend erlaubt sind!
Wie auch schon früher bei CentOS ab Release 7 bzw. den nachfolgenden Release-Kandidaten Stream von RHEL nutzen wir auch unter Arch Linux den dynamischen firewalld Service. Ein großer Vorteil der dynamischen Paketfilterregeln ist unter anderem, daß zur Aktivierung der neuen Firewall-Regel(n) nicht der Daemon durchgestartet werden muß und somit alle aktiven Verbindungen kurz getrennt werden. Sondern unsere Änderungen können on-the-fly aktiviert oder auch wieder deaktiviert werden.
In folgendem Konfigurationsbeispiel gehen wir von einem Host aus, der zwei Firewall-Zonen hält, einmal die Zone nfs und einmal die Zone intra. In beiden Zonen sollen später Client-Systeme exportierte Verzeichnisse in ihr Dateisystem einbinden können.
Damit unsere Clients Verbindungen zu dem geöffneten 2049/TCP des NFSv4-Servers aufbauen können, müssen wir für diese noch Änderungen am Paketfilter firewalld vornehmen.
# firewall-cmd --permanent --zone=nfs --add-service=nfs
success
# firewall-cmd --permanent --zone=intra --add-service=nfs
success
Oder wir schalten gezielt einen Host einer Zone für den Dienst nfs frei:
# firewall-cmd --permanent --zone=intra --add-rich-rule='rule family="ipv4" source address="10.0.10.68/24" service name="nfs" accept'
success
Anschließend können wir den Firewall-Daemon einmal neu laden und überprüfen, ob die Regeln auch entsprechend unserer Definition, gezogen haben.
# firewall-cmd --reload
success
Werfen wir noch kurz einen Blick in die Zone nfs:
# firewall-cmd --zone=nfs --list-services
nfs ssh
Gleiches gilt natürlich für die Zone intra:
# firewall-cmd --zone=intra --list-services
nfs ssh
Starten des NFSv4-Daemon
Da wir ausschließlich das Protokoll NFSv4 nutzen und somit zur Verfügung stellen wollen, starten wir hierzu den betreffenden Dienst.
# systemctl start nfsv4-server.service
Im Journal wird uns der Start entsprechend protokolliert.
# journal -f
Protokollierung des nfsd im journal
Bei Bedarf können wir natürlich auch den Status unseres Daemons jederzeit abfragen.
# systemctl status nfsv4-server.service
● nfsv4-server.service - NFSv4 server and services
Loaded: loaded (/usr/lib/systemd/system/nfsv4-server.service; disabled; preset: disabled)
Active:active (running) since Tue 2026-04-07 16:17:43 CEST; 1min 27s ago
Invocation: 85c5016d8c9442d5965cf9640c043b7e
Process: 1557 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Process: 1558 ExecStart=/usr/sbin/rpc.nfsd -N 3 (code=exited, status=0/SUCCESS)
Main PID: 1558 (code=exited, status=0/SUCCESS)
Mem peak: 2.1M
CPU: 22ms
Apr 07 16:17:43 nfs-arch systemd[1]: Starting NFSv4 server and services...
Apr 07 16:17:43 nfs-arch systemd[1]: Finished NFSv4 server and services.
Alternativ dazu können wir auch einen Blick in die Prozeß-Liste werfen um uns zu vergewissern ob der Daemon läuft.
# ps auxwf | grep nfsv4-server
root 1656 0.0 0.0 6728 4460 pts/1 S+ 16:35 0:00 | \_ grep --color=auto nfsv4-server
Wir können jetzt auch schon mit Hilfe des Utility ss abfragen ob der nfsv4-server den Port 2049 auf den zugehörigen Adressen geöffnet hat.
# ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process tcp LISTEN 0 4096 0.0.0.0:2049 0.0.0.0:* tcp LISTEN 0 4096 [::]:2049 [::]:*
Einbinden der Exports auf dem Client
manuelles Mounten auf dem Zielsystem
Zum Testen unseres Servers binden wir nun auf dem hierzu berechtigten Client mit der IPv4 10.0.10.239/24 das bzw. die exportierten Verzeichnisse ein.
Der Befehl mount liefert leider oft nicht die allerbesten detaillierten Fehlermeldungen aus, was uns bei der ggf. nötigen Fehlersuche die Sache nicht ganz leicht macht. Daher verwenden wir die Option -v um ggf,. an mehr Informationen zu kommen. Ferner ist man gut beraten, explizit die Version, also in unserem Fall -t nfs4 oder auch -o vers=4 zu verwenden.
Wir binden also das Verzeichnis srv unserer Pseudo-Root-NFS-Umgebung des NFS-Servers 10.0.10.2 wir folgt ein:
# mount -v -t nfs4 10.0.10.2:/src /mnt/src
mount.nfs4: timeout set for Tue Apr 7 16:53:53 2026 mount.nfs4: trying text-based options 'vers=4.2,addr=10.0.10.2,clientaddr=10.0.10.239'
Ein erfolgreicher Mount mit NFSv4.2 liefert also obige Ausgabe.
Man beachte die Angabe des Exports auf dem Server relativ zum pseudo-root und auch die Ausgabe der verwendeten NFS-Version!
Zum Testen legen wir nun eine Testdatei an, hierzu schreiben wir einfach das aktuelle Datum in die Datei testdatei.txt und „schenken diese unseren Adminuser django.
# date > /usr/local/src/testdatei.txt ; chown django: /usr/local/src/testdatei.txt
Auf unserem Clientrechner sehen wir nun auch diese Datei:
# ls -alF /mnt/
total 4 drwxr-xr-x 1 root root 26 Apr 7 17:00 ./ drwxr-xr-x 1 root root 202 Apr 7 16:48 ../ -rw-r--r-- 1 django django 33 Apr 7 17:01 testdatei.txt
Mounten via /ety/fstab auf dem Zielsystem
Natürlich wollen und werden wir auf unseren Zielsystemen nicht manuell die Verzeichnisse einbinden, sondern die Zielsysteme sollen automatisch die exportierten Verzeichnisse einbinden. Auch hier ist es nun wichtig, daß das NFS-Export-Stammverzeichnis des Servers weggelassen wird.
# vim /etc/fstab
... 10.0.10.2:/arch-mirror /mnt/arch-mirror nfs defaults,timeo=900,retrans=5,_netdev 0 0 10.0.10.2:/backups /mnt/backups nfs defaults,timeo=900,retrans=5,_netdev 0 0 10.0.10.2:/repository /mnt/repository nfs defaults,timeo=900,retrans=5,_netdev 0 0 10.0.10.2:/src /mnt/src nfs defaults,timeo=900,retrans=5,_netdev 0 0
Damit unser System Kenntnis von unseren Erweiterungen in der /etc/fstab bekommt, ist es notwendig den systemd einmal neu zu laden:
# systemctl daemon-reload
Anschließend können wir unsere am NFS-Server exportierten Verzeichnisse mounten.
# mount -a
Eine Prüfung des nun zur Verfügung stehenden Speicherplatzes zeigt uns folgender Befehl:
# df -h
Filesystem Size Used Avail Use% Mounted on dev 7.8G 0 7.8G 0% /dev run 7.8G 1.7M 7.8G 1% /run efivarfs 154K 78K 72K 53% /sys/firmware/efi/efivars /dev/mapper/root 238G 81G 156G 35% / tmpfs 7.8G 12M 7.8G 1% /dev/shm none 1.0M 0 1.0M 0% /run/credentials/systemd-journald.service tmpfs 7.8G 24M 7.8G 1% /tmp /dev/mapper/root 238G 81G 156G 35% /var/cache/pacman/pkg /dev/mapper/root 238G 81G 156G 35% /home /dev/nvme0n1p1 1022M 50M 973M 5% /boot /dev/mapper/root 238G 81G 156G 35% /var/log tmpfs 1.6G 132K 1.6G 1% /run/user/1000 10.0.10.2:/arch-mirror 11T 6.0M 11T 1% /mnt/arch-mirror 10.0.10.2:/backups 11T 6.0M 11T 1% /mnt/backups 10.0.10.2:/repository 11T 6.0M 11T 1% /mnt/repository 10.0.10.2:/src 11T 6.0M 11T 1% /mnt/src
Am Ende sehen wir unsere vier NFS-Verzeichnisse die wir eingebunden haben.
Da wir unsere Systeme mit Hilfe von Ansible orchestrieren werden, brauchen wir uns um UID und GID keine großen Gedanken machen. Wir können somit unter anderem auf das NFSv4 IDMapping verzichten!
NFS-Client Installation unter Archlinux
Auf unseren Clients gibt es nun mehrere Varianten die vom Server exportierten Verzeichnisse einzubinden.
/etc/fstab
Die, sagen wir mal klassische Variante der Einbindung via /etc/fstab, eignet sich vor allem für „stationäre“ Clientmaschinen und Hosts, welche schon beim Bootvorgang eine entsprechende Netzwerkverbindung nutzen können. Im Abschnitt Mounten via /etx/fstab auf dem Zielsystem haben wir bereits diese Variante beleuchtet.
autofs
Auf einem Mobilen Gerät wie einem Laptop wird man in aller Regel für die Netzwerkverbindungen Dinge wie den NetzwerkManager einbinden, mit dem man dann nach Anmeldung am Desktop auswählt, welche Art von Netzwerkverbindung man nutzen möchte, wie z.B. LAN, WLAN oder Mobilfunk. Hier eignet sich die Einbindung via /etc/fstab nicht, da ja beim Booten noch keine Netzwerkverbindung besteht und somit der Auto- bzw. Re-Mount nicht möglich ist und den Bootvorgang unnötig in die Länge zieht.
Zur Einrichtung des autots-mounts wird das AUR-Paket autofs benötigt. Nun über Sinn und Qualität der Pakete im AUR-Repo kann man trefflich streiten, aber nachdem der Paketmaintainer zwar sein Paket mit einem PGP-Schlüssel signiert, es aber versäumt hat diesen Schlüssel z.B. auf einem Keyserver zu hinterlegen, werden wir hier diesen Weg nicht weiter verfolgen, da wir auf Sicherheit und Vertraulichkeit unserer Daten doch einen hohen stellen! Bei Bedarf findet man im Arch-Wiki entsprechende Informationen.
systemd automount
Da wir uns aus Sicherheitsgründen nicht für die vorgenannte Variante via autofs entschieden haben, werden wir nun auf unserem mobilen Gerät die automatische Einbindung via systemd beschreiten. Im nachfolgenden Konfigurationsbeispiel wollen wir das exportierte Verzeichnis /exports/backup von unserem NFSv4-Server mit der IP-Adresse 10.0.10.2 einbinden.
Zunächst installieren wir auf unserem Clientrechner das Paket nfs-utils.
$ sudo pacman -S nfs-utils
bzw.
# pacman -S nfs-utils
Wir benötigen je Share, den wir vom NFS-Server mounten wollen, jeweils zwei Dateien:
mount-Unit : Hier wird definiert:What:- Die Quelle, also von welchem NFS-Servewr wir welches Share einbinden wollen.Where:- Wo im Dateisystem wollen wir das Share des NFS-Servers lokal einbinden?Type:- Welche NFS-Version wollen wir verwenden?Options:- Optionen die für das Share gelten sollen.
Wir legen uns also nun diese Mount-Systemd-Unit-Datei an.
# vim /etc/systemd/system/mnt-backups.mount
- /etc/systemd/system/mnt-backups.mount
[Unit] Description=Mount NFS share backups Documentation=https://dokuwiki.nausch.org/doku.php/linux:nfs#systemd_automount [Mount] What=10.0.10.2:/backups Where=/mnt/backups Type=nfs4 Options=_netdev,hard,rw [Install] WantedBy=multi-user.target
Der Type=nfs4 erklärt sich von selbst, wir benutzen NFS-Version 4.
Die Options= haben dabei folgende Bedeutung:
_netdevweist das System an, zu warten, bis das Netzwerk verfügbar ist, bevor versucht wird, die Freigabe einzuhängen.hard: Legt das Wiederherstellungsverhalten des NFS-Clients fest, nachdem eine NFS-Anfrage abgelaufen ist. Bei der Optionhardwerden NFS-Anfragen unbegrenzt oft wiederholt.rwdefiniert, daß das Dateisystem mit Lese- und Schreibzugriff eingebunden werden soll.
Die zweite Unit mit der Endung .automount macht genau das, was der Name besagt: Sie liest die gerade beschriebene .mount-Unit und hängt die dort benannte Freigabe ein.
# vim /etc/systemd/system/mnt-backups.automount
- /etc/systemd/system/mnt-backups.automount
[Unit] Description=Automount NFS share backups Documentation=https://dokuwiki.nausch.org/doku.php/linux:nfs#systemd_automount Requires=NetworkManager.service After=network-online.target Wants=network-online.target [Automount] Where=/mnt/backups TimeoutIdleSec=10min [Install] WantedBy=multi-user.target
Der TimeoutIdleSec=10min definiert eine Zeitüberschreitung bei Inaktivität. Sobald die eingebundene Freigabe für die angegebene Zeit inaktiv war, versucht systemd, sie zu deaktivieren.
Achtung :
Keinesfalls bei den Mountpoints im Dateisystem Namen mit einem - verwenden! Denn aus den Namen wird der Mountpoint gebildet, indem / durch ein - ersetzt wird. Der volle Verzeichnis-Datei-Name, den wir bei der Option Where in der Automount-Unit angeben muss zum Unit-Namen passen. In unserem Konfigurationsbeispiel Where=/mnt/backups wird der Unit-Name dann mnt-backups.automount.
Würde man hingegen als Mountpoint /mnt/backup-2026 verwenden sowie den Unit-Namen entsprechend mnt-backup-2026 wird uns der systemd eine entsprechende Fehlermeldung auswerfen: mnt-backup-2026.automount: Where= setting doesn't match unit name. Refusing.
Bevor wir nun unsere neue Automount-Unit aktivieren, informieren wir den systemd über die neuen Unit-files durch einen Reload des systemd.
# systemctl daemon-reload
Nach einem erfolgreichen Neustart unseres Client-Rechners werfen wir zunächst einen Blick in die gemounteten Dateiverzeichnisse.
# bat /proc/mounts
Ausgabe des Befehls bat /proc/mounts
Wir sehen also, es ist unser NFS-Verzeichnis nicht gemountet.
Nun greifen wir auf unser Freigabeverzeichnis /mnt/backups zu.
$ cd /mnt/backups
Im Journal wird der Zugriffsversuch und der Mount des Freigabeverzeichnisses entsprechend protokolliert:
Apr 14 16:00:27 pml010068 systemd[1]: mnt-backups.automount: Got automount request for /mnt/backups, triggered by 10290 (vim) Apr 14 16:00:27 pml010068 systemd[1]: Mounting NFSv4 share backups... Apr 14 16:00:27 pml010068 systemd[1]: Mounted NFSv4 share backups. Apr 14 16:00:27 pml010068 nfsrahead[10301]: setting /mnt/backups readahead to 128
Auf dem NFS-Server sehen wir diesen Zugriff im journal:
Apr 14 16:00:31 nfs-arch nfsv4.exportd[9926]: v4.2 client attached: 0x37b6efbb69dd1f27 from "10.0.10.68:686"
Greifen wir 10 Minuten nicht auf das Verzeichni zu, wird die freigabe wieder entfernt:
Apr 14 16:01:02 pml010068 systemd[1]: snapperd.service: Deactivated successfully. Apr 14 16:10:28 pml010068 systemd[1]: Unmounting NFSv4 share backups... Apr 14 16:10:28 pml010068 systemd[1]: mnt-backups.mount: Deactivated successfully. Apr 14 16:10:28 pml010068 systemd[1]: Unmounted NFSv4 share backups.
Der automatische unmount unseres Verzeichnisses wir auf dem NFS-Server entsprechend protokolliert:
Apr 14 16:01:32 nfs-arch nfsv4.exportd[9926]: v4.2 client detached: 0x37b6efbb69dd1f27 from "10.0.10.68:686"
Orchestrierung - Installation und Konfiguration des NFSv4-Servers mit Hilfe von Ansible
Aufgabenstellung
Wie auch schon bei der Einrichtung anderer Server-Diensten wollen wir auch hier weder eine manuelle Installation und Konfiguration unseres NFSv4-Servers sehen noch betreiben. Setzen wir einen neue virtuellen Server unter Arch Linux neu auf, oder wollen wir bei einem bestehenden Host die Konfiguration aktualisieren, verwenden wir wie zuvor schon angeschnitten Ansible als Orchestrierungswerkzeug. So ist sichergestellt, daß all unsere Hosts entsprechend gleich aufgebaut, konfiguriert und betrieben werden, es also keine Bastel-/Frickellösung geben wird!
Folgende Übersicht zeigt die Infrastrukturumgebung für unser Konfigurationsbeispiel, welches wir nun mit Hilfe von Ansible orchestrieren wollen.
Der NFS-Server hat hier folgende Eigenschaften:
- IP-Adressen:
10.0.10.2undfd00:0:0:7:10:0:10:2 - Partition/Verzeichnis in dem die Dateien physikalisch abgespeichert werden:
/srv/nfs - zu exportierende Verzeichnisse:
archmirrorbackupsrepositorysrc
Wir haben zwei unterschiedliche Client-Rechner:
- Büro Thinclient NitroPC mit
- IP-Adressen:
10.0.10.60undfd00:0:0:7:10:0:10:60 - Server-Verzeichnisse die eingebunden werden sollen:
archmirrorbackupssrc
- Büro Thinclient NitroPAD mit
- IP-Adressen:
10.0.10.70undfd00:0:0:7:10:0:10:70 - Server-Verzeichnisse die eingebunden werden sollen:
archmirrorbackupsrepository
Lösung
Der ungeduldigen Leser kann auch direkt zur Tat schreiten und das manuelle Anlegen der Inventory-Hülle, des Playbooks und der zugehörigen Rolle überspringen und diese Aufgaben mit folgendem Befehl sozusagen auf einem Rutsch erledigen:
$ mkdir -p ~/devel/ansible ; wget https://gitlab.nausch.org/django/example_nfs/-/archive/main/example_nfs-main.tar.gz \
-O - | tar -xz --strip-components=1 -C ~/devel/ansible
Nach Anpassung der Daten im Inventory kann man anschließend direkt zur Ausführung schreiten.
Vorbereitung - (Server-)Daten im Inventory
Bei unserem Konfigurationsbeispiel hier gehen wir von den vorgenannten Parametern aus.
Die Konfigurationsdatei unseres inventory in unsere, Ansible-Verzeichnis beinhaltet demnach unter anderem:
$ vim inventories/production/hosts
Jeder Node hat im Inventory-Verzeichnis dann jeweils eine Datei hostconfig mit den jeweiligen generellen Hostdaten, sowie der NFS-Server pml010002 eine nfs_server mit den NFS-Server-Daten und die beiden Client-Hosts dann jeweils eine eigenständige nfs_client-Datei mit den Client spezifischen NFS-Parametern.
NFS-Server pml010002
$ vim inventories/production/host_vars/pml010002/hostconfig
inventories/production/host_vars/pml010002/hostconfig
$ vim inventories/production/host_vars/pml010002/nfs_server
NFS-Client pml010060
$ vim inventories/production/host_vars/pml010060/hostconfig
inventories/production/host_vars/pml010060/hostconfig
$ vim inventories/production/host_vars/pml010060/nfs_client
NFS-Client pml010070
$ vim inventories/production/host_vars/pml010070/hostconfig
inventories/production/host_vars/pml010070/hostconfig
$ vim inventories/production/host_vars/pml010070/nfs_client
globale Parameter
Parameter die für alle Hosts gelten sollen legen wir unter group_vars/all/nfs ab.
$ vim inventories/production/group_vars/all/nfs
inventories/production/group_vars/all/nfs
Unser Beispiels-Inventory hat also nunmehr folgenden Aufbau:
inventories/production/
├── group_vars
│ └── all
│ └── nfs
├── hosts
└── host_vars
├── pml010002
│ ├── hostconfig
│ └── nfs_server
├── pml010060
│ ├── hostconfig
│ └── nfs_client
└── pml010070
├── hostconfig
└── nfs_client
7 directories, 8 files
Playbooks
In diesem Konfigurationsbeispiel haben wir zwei Playbooks, einmal eines für den NFS-Server und 1x eines für die Clients.
playbooks/ ├── arch_nfs_client.yml └── arch_nfs_server.yml 1 directory, 2 files
Das Playbook arch_nfs_server.yml zum Installieren und Konfigurieren des NFSv4-Servers ist wie immer schlank, unscheinbar und unspektakulär, beinhaltet aber Hinweise zur Aufgabe und wie es aufzurufen ist.
$ vim playbooks/arch_nfs_server.yml
Gleiches gilt für das Playbook arch_nfs_client.yml, welches wir für die Konfiguration der NFS-Clientspezifischen Parametern auf den beiden Client-Rechnern verwenden.
$ vim playbooks/arch_nfs_client.yml
Rolle: arch_nfs_server
Für die Konfiguration des NFSv4-Servers verwenden wir eine eigene Rolle arch_nfs_server, die wir bei unserem zuvor angelegten Playbooks später einfach mit aufrufen werden. Hierzu kopieren wir uns zunächst die Mustervorlage common, welche wir bei der initialen Ansible-Einrichtung angelegt hatten.
$ cp -avr roles/common/ roles/arch_nfs_server
Ausgabe von cp -avr roles/common/ roles/arch_nfs_server
Bei Bedarf können wir uns die Struktur die somit angelegt wurde mit nachfolgendem Befehl anzeigen lassen.
$ tree roles/arch_nfs_server/
Ausgabe von tree roles/arch_nfs_server/
Wie wir sehen ist die Rolle durchaus überschaubar, im Task main.yaml verweisen wir lediglich auf die folgenden Tasks:
nfs_server_config, in die die Konfiguration des NFSv4-Servers erfolgt,firewalld_configwo wir abschließend die Installation und Konfiguration unseres nftables-basierten Paketfilters definieren.
$ vim roles/arch_nfs_server/tasks/main.yml
roles/arch_nfs_server/tasks/main.yml
Die Installation des benötigten ArchLinux-Paketes für den NFSv4-Daemon wird in der ersten Task-Gruppe mit dem tag packages vorgenommen.
$ vim roles/arch_nfs_server/tasks/packages.yml
roles/arch_nfs_server/tasks/packages.yml
Für die Konfiguration des NFSv4-Servers, wie im Abschnitt Konfiguration des NFSv4-Servers erklärt, werden die nötigen Schritte in der Task-Gruppe mit dem tag nfs_server_config definiert.
$ vim roles/arch_nfs_server/tasks/nfs_server_config.yml
roles/arch_nfs_server/tasks/nfs_server_config.yml
Die Konfigurationsdatei auf dem Zielhost /etc/exports wird mit Hilfe des Jinja2 Templates exports.j2 sauber formatiert angelegt.
$ vim roles/arch_nfs_server/templates/exports.j2
roles/arch_nfs_server/templates/exports.j2
Werden Änderungen an der /etc/fstab vorgenommen, so wird über den Handler Reload systemd ein Reload das Systemd initiiert. Änderungen an der Shares des Servers, die in der Datei /etc/exports definiert werden, wiederum werden dem NFS-Server Durch den Befehl exportfs -r. Die Konfiguration der beiden Handler erfolgt mit Hilfe der Datei main.yml im Unterverzeichnis handlers.
$ vim roles/arch_nfs_server/handlers/main.yml
roles/arch_nfs_server/handlers/main.yml
Zum Schluß konfigurieren wir abschließend noch die Paketfilter-Regeln für unseren Firewall-Daemon firewalld.
$ vim roles/arch_nfs_server/tasks/firewalld_config.yml
Rolle: arch_nfs_sclient
Für die Konfiguration des NFSv4-clients verwenden wir eine weitere Rolle arch_nfs_client, die wir bei unserem zuvor angelegten Playbooks später einfach mit aufrufen werden. Hierzu kopieren wir uns zunächst die Mustervorlage common, welche wir bei der initialen Ansible-Einrichtung angelegt hatten.
$ cp -avr roles/common/ roles/arch_nfs_client
Ausgabe von cp -avr roles/common/ roles/arch_nfs_client
Bei Bedarf können wir uns die Struktur die somit angelegt wurde mit nachfolgendem Befehl anzeigen lassen.
$ tree roles/arch_nfs_client/
Ausgabe von tree roles/arch_nfs_client/
Wie wir sehen ist auch diese Rolle durchaus überschaubar, im Task main.yaml verweisen wir lediglich auf die folgenden Tasks:
nfs_client_config, in die die Konfiguration des NFSv4-Clients erfolgt,
$ vim roles/arch_nfs_client/tasks/main.yml
roles/arch_nfs_client/tasks/main.yml
Die Installation des benötigten ArchLinux-Paketes für den NFSv4-Client wird in der ersten Task-Gruppe mit dem tag packages vorgenommen.
$ vim roles/arch_nfs_client/tasks/packages.yml
roles/arch_nfs_client /tasks/packages.yml
Für die Konfiguration des NFSv4-Clients, wie im Abschnitt Konfiguration des NFSv4-Clients erklärt, werden die nötigen Schritte in der Task-Gruppe mit dem tag nfs_client_config definiert.
$ vim roles/arch_nfs_client/tasks/nfs_client_config.yml
roles/arch_nfs_client/tasks/nfs_client_config.yml
Die benötigten Systemd-Unit-Files auf dem Zielhost im Verzeichnis /etc/systemd/system werden mit Hilfe der beiden Jinja2 Templates automount.j2 und mount.j2 angelegt.
$ vim roles/arch_nfs_client/templates/automount.j2
roles/arch_nfs_client/templates/automount.j2
$ vim roles/arch_nfs_client/templates/mount.j2
roles/arch_nfs_client/templates/mount.j2
Werden Änderungen an den Systemd-Unit-Files vorgenommen, so wird über den Handler Reload systemd ein Reload das Systemd initiiert. Die Konfiguration des Handlers erfolgt mit Hilfe der Datei main.yml im Unterverzeichnis handlers.
$ vim roles/arch_nfs_client/handlers/main.yml
Ausführung - Playbooklauf
Die orchestrierte Variante der Installation und Konfiguration unseres NFSv4-Servers gestaltet sich ab sofort sehr einfach, brauchen wir doch lediglich die Konfigurationswerte im Inventory zu hinterlegen und zu pflegen und letztendlich das Playbook entsprechend aufzurufen:
$ ansible-playbook playbooks/arch_nfs_server.yml --limit pml010002
[22:12:48] Gathering Facts ↳ pml010002 | SUCCESS | 2.40s [22:12:51] arch_nfs_server : Installation der benötigten Pakete. ↳ pml010002 | SUCCESS | 17ms [22:12:51] ↳ packages: Installation der benötigten Pakete. ↳ pml010002 | SUCCESS | 1.92s [22:12:53] arch_nfs_server : Konfiguration des NFS Servers. ↳ pml010002 | SUCCESS | 23ms [22:12:53] ↳ nfs_server_config: Benutzerdefinierte Export-Stammverzeichnisse unter /srv/nfs anlegen. ↳ pml010002 | CHANGED | 2.04s [22:12:55] ↳ nfs_server_config: Pseudo-Root-NFS-Verzeichnis anlegen. ↳ pml010002 | CHANGED | 380ms [22:12:55] ↳ nfs_server_config: Export-Verzeichnisse unter /exports anlegen. ↳ pml010002 | CHANGED | 1.88s [22:12:57] ↳ nfs_server_config: Änderungen an der /etc/fstab mit blockinfile vornehmen. ↳ pml010002 | SUCCESS | 452ms [22:12:58] ↳ nfs_server_config: Checken ob es bereits eine Backupdatei von /etc/exports gibt. ↳ pml010002 | SUCCESS | 564ms [22:12:58] ↳ nfs_server_config: Backupdatei der Exports Konfigurationsdatei /etc/exports erstellen. pml010002 | SKIPPED | 23ms [22:12:58] ↳ nfs_server_config: Exports Konfigurationsdatei aus Template erzeugen. ↳ pml010002 | SUCCESS | 921ms [22:12:59] ↳ nfs_server_config: Systemd Service des NFSv4-Servers starten und aktivieren. ↳ pml010002 | SUCCESS | 823ms [22:13:00] arch_nfs_server : Konfiguration des Paketfilters auf Basis firewalld. ↳ pml010002 | SUCCESS | 21ms [22:13:00] ↳ firewalld_config: Installation des Firewall-Daemons. ↳ pml010002 | SUCCESS | 1.29s [22:13:01] ↳ firewalld_config: Sicherstellen, dass der Firewall-Daemon reboot(-fest) starten. ↳ pml010002 | CHANGED | 893ms [22:13:02] ↳ firewalld_config: Firewall-Zone für Zone intra anlegen. ↳ pml010002 | SUCCESS | 710ms [22:13:04] ↳ firewalld_config: Firewall Daemon neu laden mit: firewall-cmd --reload. ↳ pml010002 | CHANGED | 626ms [22:13:04] ↳ firewalld_config: Interface net0 der Firwall-Zone intra zuordnen. ↳ pml010002 | SUCCESS | 516ms [22:13:05] ↳ firewalld_config: Service Rules SSH für Zone intra definieren. ↳ pml010002 | SUCCESS | 1.07s [22:13:06] ↳ firewalld_config: Service Rules IPv6 echo-request für Zone intra definieren. ↳ pml010002 | SUCCESS | 1.07s [22:13:08] ↳ firewalld_config: Service Rules NFS für Zone intra definieren. ↳ pml010002 | SUCCESS | 4.30s [22:13:12] system -- Play recap -- pml010002 : ok=20 changed=5 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Gleiches gilt natürlich auch für die Konfiguration der NFS-Clients, die wir ab sofort mit Hilfe unseres Ansible Playbooks betanken können.
$ ansible-playbook playbooks/arch_nfs_client.yml --limit pml010095
[22:23:00] Gathering Facts ↳ pml010095 | SUCCESS | 1.47s [22:23:02] arch_nfs_client : Installation der benötigten Pakete. ↳ pml010095 | SUCCESS | 24ms [22:23:02] ↳ packages: Installation der benötigten Pakete. ↳ pml010095 | SUCCESS | 1.26s [22:23:03] arch_nfs_client : Konfiguration des NFS Servers. ↳ pml010095 | SUCCESS | 39ms [22:23:03] ↳ nfs_client_config: Export-Verzeichnisse unter /mnt anlegen. ↳ pml010095 | CHANGED | 1.67s [22:23:05] ↳ nfs_client_config: Automount systemd Unit Datei(en) für NFS-Shares erzeugen und kopieren. ↳ pml010095 | CHANGED | 3.96s [22:23:09] ↳ nfs_client_config: Mount systemd Unit Datei(en) für NFS-Shares erzeugen und kopieren. ↳ pml010095 | CHANGED | 3.58s [22:23:13] ↳ nfs_client_config: Systemd Service Automount der Shares starten. ↳ pml010095 | CHANGED | 3.18s triggering handler | arch_nfs_client : Reload systemd ↳ pml010095 | SUCCESS | 3.94s [22:23:16] system -- Play recap -- pml010095 : ok=9 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0