NFS-Server

Ziel: Dateitransfer mit dem Network File System (NFS) durchführen, Bereitstellung eines Netzwerkdateisystemes, das Unix-Clients bequem mounten können.

(Freie Windows-Clients sind rar, eine Möglichkeit ist unter http://nekodrive.software.informer.com/ zu finden.)

Ein paar wichtige Eckpunkte:

  • NFS stammt von der 1982 gegründeten Firma SUN Microsystems, 1984 gelang ihr mit diesem Protokoll der Durchbruch in der Unix-Welt

  • Es wird als verteiltes Dateisystem bezeichnet; wenn ein beteiligter Server wegbricht, können allerdings automatische Failover-Aktionen nicht wie bei Ceph oder DFS stattfinden

  • Client/Server-Anwendung: der Server exportiert einen Teil seines Dateisystemes, der Client importiert es durch einen klassischen Mountvorgang

  • Transparente Arbeitsweise: auf die entfernte Ressource wird über einen lokalen Ordner zugegriffen (–> systemweit einheitlicher Namensraum)

  • Bis Version 3 benutzt NFS das verbindungslose UDP, die aktuelle Version 4 verwendet TCP und behebt damit kleinere Probleme, ist aber dadurch nicht mehr ganz so schnell

  • Bis Version 3 authentifizieren sich Benutzer via User-ID-Mapping, ab Version 4 ist außerdem Authentifizierung mittels Kerberos möglich

  • NFS benötigt Remote Procedure Calls (RPC), die sich auf OSI-Schicht 5 um das Zuordnen von lokalen und entfernten UDP/TCP-Ports kümmern und ein initiales Filehandle einrichten

  • RPC wird bis NFSv3 mit dem Dienst ‚portmap‘ realisiert (UDP/2049), ab NFSv4 über ‚rpcbind‘ (TCP/2049)

  • Die NFSv3-Daemons rpc.mountd, rpc.lockd und rpc.statd werden von NFSv4 nicht mehr verwendet (feste Integration im Kernel), dafür aber gibt es jetzt ein Listening am TCP-Port 2049

  • Rollen:

    • Server = der Exporteur (Datei: ‚/etc/exports‘, Tool: exportfs)

    • Client = der Importeur (Kommando mount -t nfs Server:Pfad Mountpunkt)

Installation unter Debian

Die Installation ist schnell durchgeführt. Falls nicht schon vorhanden, wird der zugrundeliegende Portmapper (Paket ‚rpcbind‘) automatisch mit installiert, ebenso wie der NFS-Client (Paket ‚nfs-common‘):

apt-get install nfs-kernel-server

Der NFS-Daemon startet sich aber nicht automatisch, wie sonst unter Debian üblich, es sei denn, es existiert bereits in der Konfigurationsdatei eine gültige Freigabe.

Als weitere Voraussetzung muss der Kernel NFS unterstützen; das Dateisystem wird dann in der Datei /proc/filesystems mit aufgelistet. Bei selbst kompilierten Kerneln fehlt diese Option oft!

NFSv3-kompatible Freigaben

Die Konfigurationsdatei bearbeitet man mit

vi /etc/exports

Für NFSv3 reicht im einfachsten Fall nur eine Zeile, die das Verzeichnis ‚/srv/pub‘ für alle Rechner ‚*‘ schreibfähig (rw) freigibt, wobei Änderungen sofort auf die Festplatte geschrieben werden (sync), außerdem sollen Dateirechte nicht rekursiv geprüft werden (no_subtree_check), was sich nur bei reinen Heimatverzeichnissen lohnt:

/srv/pub       *(rw,sync,no_subtree_check)

Nach dem Anlegen des Verzeichnisses mit

mkdir -m 777 /srv/pub

muss der NFS-Dienst gestartet werden:

/etc/init.d/nfs-kernel-server start

Eine Freigabe mit NFSv3 clientseitig einbinden

Ob der Server erreichbar ist und was er exportiert, kann auf dem Client via Netzwerk mittels

showmount -e server

überprüft werden. Das Mounten in den normalerweise leeren Ordner ‚/mnt‘ gelingt dann mit

mount -o vers=3 server:/srv/pub /mnt

Für NFSv3 ist hierbei die Option ‚vers=3‘ ausschlaggebend, was bedeutet, dass als Transportprotokoll das schnellere UDP verwendet wird.

Zum automatischen Mounten beim Bootvorgang editieren wir die Datei ‚/etc/fstab‘:

vi /etc/fstab

Als Mountpunkt legt man z.B. vorher einen Ordner ‚/media/pub‘ an und schreibt:

server:/srv/pub  /media/pub  nfs  soft,bg  0  0

Die Option ‚soft‘ verhindert ein Hängenbleiben des Clients beim Bootvorgang, falls der Server nicht erreichbar ist; mit ‚bg‘ versucht er es im Hintergrund weiter. Nach dem Abspeichern der Änderungen kann ein Reboot mittels

mount -a

simuliert werden.

Freigaben mit NFSv4

Grundsätzlich kann die bisherige Konfiguration mit der einen Zeile in der ‚/etc/exports‘ beibehalten werden. Ein moderner NFS-Client benutzt dann automatisch NFSv4, wenn er beim Mounten die Versions-Option ‚vers=3‘ weglässt. Damit kann man allerdings nicht alle Features des neuen Protokolls ausnutzen, wie z.B. das automatische Einhängen aller Freigaben unter einem bestimmten NFS-Wurzelverzeichnis.

Die Konfigurationsdatei ist zuerst einmal wieder die alte:

vi /etc/exports

Idealerweise deklariert man für NFSv4 zuerst in einer extra Zeile einen Ordner als NFS-Wurzelpunkt; das wichtigste Kennzeichen ist ‚fsid=0‘. Die zweite Zeile definiert dann die eigentliche Freigabe, auf die der Client später in relativer Schreibweise beim Mounten zugreift (im Beispiel einfach nur mit ‚pub‘, ohne führenden Slash):

/srv/nfs4      *(rw,sync,fsid=0,crossmnt,no_subtree_check)
/srv/nfs4/pub  *(rw,sync,no_subtree_check)

Nach dem Anlegen des Verzeichnisses mit

mkdir -p -m 777 /srv/nfs4/pub

muss der NFS-Dienst neu gestartet werden:

/etc/init.d/nfs-kernel-server restart

Eine Freigabe mit NFSv4 clientseitig einbinden

Ob der Server erreichbar ist und was er exportiert, kann auf dem Client wiederum mittels

showmount -e server

überprüft werden. Das Mounten in den Ordner ‚/mnt‘ gelingt dann in kürzerer Schreibweise mit

mount server:pub /mnt

Für NFSv4 ist hierbei zu beachten, dass lediglich der betreffende Freigabeordner als RELATIVER PFAD (hier: ‚pub‘) zur NFS-Wurzel (hier: ‚/srv/nfs4‘) direkt nach dem Doppelpunkt angegeben wird!

Zum automatischen Mounten beim Bootvorgang editieren wir wieder die Datei ‚fstab‘:

vi /etc/fstab

Als Mountpunkt verwenden wir nach einem ‚umount /media/pub‘ wieder den selben Ordner, die betreffende Zeile sieht jetzt so aus:

server:pub  /media/pub  nfs4  soft,bg  0  0

Nach dem Abspeichern der Änderungen kann ein Reboot mittels

mount -a

simuliert werden.

Freigaben mit ‚exportfs‘ erstellen

Das Kommando ‚exportfs‘ ist das eigentliche Tool im Backend, was die Freigaben erzeugt. Voraussetzung ist aber, dass bereits einige Daemons am Start sind:

$ ps aux | grep -E 'nfsd|mountd'
root      3969  0.0  0.6  12748  2136 pts/1    S+   20:21   0:00 grep -E nfsd|mountd
$
$ rpc.nfsd
$ rpc.mountd
$
$ ps aux | grep -E 'nfsd|mountd'
root      3973  0.0  0.0      0     0 ?        S<   20:21   0:00 [nfsd4]
root      3974  0.0  0.0      0     0 ?        S<   20:21   0:00 [nfsd4_callbacks]
root      3978  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3979  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3980  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3981  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3982  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3983  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3984  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3985  0.0  0.0      0     0 ?        S    20:21   0:00 [nfsd]
root      3987  0.0  1.5  40956  5416 ?        Ss   20:21   0:00 rpc.mountd
root      3989  0.0  0.6  12748  2132 pts/1    S+   20:21   0:00 grep -E nfsd|mountd
$
$ rpcinfo -p | grep 2049
    100003    2   tcp   2049  nfs
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    2   tcp   2049
    100227    3   tcp   2049
    100003    2   udp   2049  nfs
    100003    3   udp   2049  nfs
    100003    4   udp   2049  nfs
    100227    2   udp   2049
    100227    3   udp   2049
$

Im Beispiel soll nun das Verzeichnis /tmp lesend und schreiben freigegeben werden:

$ exportfs -o rw *:/tmp

Zur Kontrolle geben wir dann folgendes ein:

$ showmount -e localhost
Export list for localhost:
/tmp *

Will man alle Exporte mit einem Mal entfernen, schreibt man einfach:

$ exportfs -ua

Clientseitge Einbindung

Mit der Option ‚vers=3‘ nutzen wir explizit die zwar alte, aber dank UDP schnellere Version 3:

$ showmount -e d8squid
Export list for d8squid:
/tmp *
$
$ mount -o vers=3 d8squid:/tmp /tmp/mnt/
$
$ echo 123 > /tmp/mnt/datei-von-root
$
$ su - tux
$ echo 123 > /tmp/mnt/datei-von-tux

ACHTUNG: Der Benutzer root wird immer auf nobody gequetscht (Default Option: root_squash):

$ ls -ltrc /tmp/ | tail -5
insgesamt 2
-rw-r--r-- 1 nobody nogroup 4 Nov 21 20:27 datei-von-root
-rw-r--r-- 1 tux    tux     4 Nov 21 20:28 datei-von-tux
$

Fehlersuche

Fehler können sich natürlich an vielen Stellen ergeben, z.B. durch nicht vorhandene Verzeichnisse oder nicht laufende bzw. nicht neu gestartete Daemons. Zu Diagnosezwecken kommt neben dem bereits bekannten Kommando ‚showmount‘ das speziell für RPC geeignete Kommando ‚rpcinfo‘ in Frage:

rpcinfp -p client

rpcinfp -p server

Damit lässt sich kontrollieren, ob die Remote Procedure Calls auf dem Client (ca. 8 Prozesse sichtbar, vor allem ‚portmapper‘) sowie auf dem Server (ca. 30 Prozesse, neben ‚portmapper‘ auch ‚nfs‘ und ‚mountd‘) zur Verfügung stehen.

Probleme treten oft durch Firewalls auf, insbesondere mit NFSv3.

Dank der NFS-Wurzel-Option ‚fsid=0‘ wird das zu importierende Dateisystem nicht als lokales Blockgerät mit Major- und Minor-Nummer bzw. UUID betrachtet, sondern einfach mit der Dateisystem-ID 0 ausgestattet. Dadurch werden nervende „stale NFS mounts“ vermieden, deren Ursache in nicht mehr erreichbaren NFS-Servern liegen.