Mounten eines NFS-Verzeichnisses in ein Host-Volume, das für Docker freigegeben ist

8

Betrachten Sie den folgenden Docker-Container:

docker run --rm -it -v /tmp:/mnt/tmp alpine sh

Dadurch wird das Hostverzeichnis / tmp in / mnt / tmp im alpinen Container bereitgestellt.

Jetzt mounte ich auf dem Host-System ein NFS-Volume in das Verzeichnis / tmp:

mkdir /tmp/nfs
mount -t nfs4 192.168.1.100:/data /tmp/nfs

Der Mount funktioniert auf dem Host-System, und ich sehe Folgendes:

# ls /tmp/nfs
file1 file2 file3
#

Aber auf dem Docker Container sehe ich ein leeres Verzeichnis:

# ls /mnt/tmp/nfs
#

Ich weiß, dass ich das umgehen kann, indem ich den Mount direkt im Docker Container mache. Aber ich bin wirklich interessiert zu wissen, warum der Mount auf dem Host-Container funktioniert, aber nicht auf dem Docker-Container?

Caleb
quelle
Möglicherweise müssen Sie Ihr Betriebssystem, Ihre Docker-Version usw. usw. beschreiben. Ich habe dies gerade mit Centos 7 und Docker 1.10 aus Extras versucht und es hat wie erwartet funktioniert. Der Inhalt des NFS-Mount wurde in einem Debian / Jessie-Container angezeigt. Auch ob Sie Sicherheitskontrollen (zB SELinux) und andere Flags haben.
Stephen Harris
Ich verwende Ubuntu 16.04 mit Docker Version 1.12.0-dev, keine zusätzlichen Sicherheitskontrollen. Das Problem tritt nur auf, wenn ich den NFS-Mount mache, nachdem ich den Alpine-Container erstellt habe. Wenn ich den NFS-Mount mache, bevor ich den Alpine-Container erstelle, sehe ich ihn wie erwartet.
Caleb

Antworten:

15

Dies liegt daran, dass das Volume die privateMount-Weitergabe verwendet. Dies bedeutet, dass nach dem Mount keine Änderungen auf der Ursprungsseite (z. B. auf der "Host" -Seite im Fall von Docker) unter dem Mount sichtbar sind.

Es gibt verschiedene Möglichkeiten, damit umzugehen:

  1. Führen Sie zuerst die NFS-Bereitstellung durch und starten Sie dann den Container. Die Bereitstellung wird auf den Container übertragen, jedoch werden Änderungen an der Bereitstellung nach wie vor vom Container nicht gesehen (einschließlich Aufheben der Bereitstellung).

  2. Verwenden Sie die "Slave" -Verbreitung. Dies bedeutet, dass nach dem Erstellen des Mount alle Änderungen auf der Ursprungsseite (Docker-Host) im Ziel (im Container) angezeigt werden können. Wenn Sie zufällig verschachtelte Bereitstellungen durchführen, sollten Sie diese verwenden rslave( rfür rekursiv).

Es gibt auch eine "gemeinsame" Verbreitung. In diesem Modus werden Änderungen am Mountpunkt innerhalb des Containers vorgenommen, die auf den Host übertragen werden, und umgekehrt. Da Ihr Benutzer nicht einmal die Berechtigung hätte, solche Änderungen vorzunehmen (es sei denn, Sie fügen CAP_SYS_ADMIN hinzu), ist dies wahrscheinlich nicht das, was Sie möchten.

Sie können den Ausbreitungsmodus beim Erstellen des Mount wie folgt einstellen:

$ docker run -v /foo:/bar:private

Die andere Alternative wäre die Verwendung eines Volumes anstelle eines Host-Mount. Sie können dies folgendermaßen tun:

$ docker volume create \
    --name mynfs \
    --opt type=nfs \
    --opt device=:<nfs export path> \
    --opt o=addr=<nfs host> \
    mynfs
$ docker run -it -v mynfs:/foo alpine sh

Dadurch wird sichergestellt, dass die Bereitstellung immer im Container für Sie erfolgt. Sie müssen den Host nicht auf eine bestimmte Weise einrichten oder sich mit der Weitergabe von Bereitstellungen befassen.
Hinweis : Der :Pfad an der Vorderseite des Gerätepfads ist erforderlich, nur etwas Seltsames am nfs-Kernelmodul.
Hinweis : Docker wird derzeit nicht <nfs host>von einem DNS-Namen aufgelöst (dies wird in 1.13 der Fall sein ), daher müssen Sie hier die IP-Adresse angeben.

Weitere Details zu "Shared Subtree" -Mounts: https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt

cpuguy83
quelle
Sehr gute Antwort. Könnten Sie es so bearbeiten, dass es eher eine eigenständige Antwort ist, die erklärt, wie MountFlags = Slave im Docker Daemon festgelegt wird und nicht vom Kontext anderer Antworten abhängt. Dann werde ich dies auf die akzeptierte Antwort umschalten.
Caleb
4

Aktivieren Sie die Shared-Mount-Weitergabe auf dem Volume, indem Sie das Flag: shared am Ende des Volume-Arguments hinzufügen:

docker run --rm -it -v /tmp:/mnt/tmp:shared alpine sh

Wenn Docker über einen Paketmanager oder ein Installationsskript für systemd installiert wurde, müssen Sie möglicherweise das MountFlags-Daemon-Argument anpassen. Suchen Sie dazu die Datei docker.service:

$ sudo find /etc -name "docker.service"

In meinem Fall unter Ubuntu 16.04 befand es sich unter /etc/systemd/system/multi-user.target.wants/docker.service. Bearbeiten Sie diese Datei mit vi oder nano und stellen Sie sicher, dass die Option MountFlags lautet:

MountFlags=shared

Speichern Sie die Datei, laden Sie die Daemon-Argumente neu und starten Sie Docker neu:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

Jetzt sollten Sie in der Lage sein, das Flag für die gemeinsame Mount-Weitergabe auf Volumes zu setzen, wenn Sie "Docker Run" verwenden.

Caleb
quelle
3

Ab Docker 17.06 können Sie NFS-Freigaben direkt beim Ausführen in den Container einbinden, ohne dass zusätzliche Funktionen erforderlich sind

export NFS_VOL_NAME=mynfs NFS_LOCAL_MNT=/mnt/mynfs NFS_SERVER=my.nfs.server.com NFS_SHARE=/my/server/path NFS_OPTS=vers=4,soft

docker run --mount \
  "src=$NFS_VOL_NAME,dst=$NFS_LOCAL_MNT,volume-opt=device=:$NFS_SHARE,\"volume-opt=o=addr=$NFS_SERVER,$NFS_OPTS\",type=volume,volume-driver=local,volume-opt=type=nfs" \
  busybox ls $NFS_LOCAL_MNT

Alternativ können Sie das Volume vor dem Container erstellen:

docker volume create --driver local \
  --opt type=nfs --opt o=addr=$NFS_SERVER,$NFS_OPTS \
  --opt device=:$NFS_SHARE $NFS_VOL_NAME

docker run --rm -v $NFS_VOL_NAME:$NFS_LOCAL_MNT busybox ls $NFS_LOCAL_MNT

Ich habe den Hinweis von https://github.com/moby/moby/issues/28809 erhalten

ThiagoAlves
quelle