Montage d'un répertoire NFS dans un volume hôte partagé avec Docker


8

Considérez le conteneur Docker suivant:

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

Cela monte le répertoire hôte / tmp dans / mnt / tmp à l'intérieur du conteneur alpin.

Maintenant, sur le système hôte, je monte un volume NFS dans le répertoire / tmp:

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

Le montage fonctionne sur le système hôte, et je vois ce qui suit:

# ls /tmp/nfs
file1 file2 file3
#

Mais sur le Docker Container, je vois un répertoire vide:

# ls /mnt/tmp/nfs
#

Je sais que je peux contourner ce problème en effectuant le montage directement dans le Docker Container. Mais je suis vraiment intéressé de savoir pourquoi le montage fonctionne sur le conteneur hôte mais pas sur le conteneur docker?


Vous devrez peut-être décrire votre système d'exploitation, votre version Docker, etc. Je viens d'essayer ceci avec Centos 7 et Docker 1.10 à partir d'extras et cela a fonctionné comme prévu; le contenu du montage NFS est apparu à l'intérieur dans un conteneur debian / jessie. Indiquez également si vous disposez de contrôles de sécurité (par exemple SELinux) et d'autres indicateurs.
Stephen Harris

J'utilise Ubuntu 16.04 avec Docker version 1.12.0-dev, aucun contrôle de sécurité supplémentaire. Le problème ne se manifeste que lorsque je crée le support NFS après avoir créé le conteneur Alpine. Si je fais le montage NFS avant de créer le conteneur Alpine, je le vois comme prévu.
Caleb

Réponses:


15

Cela se produit car le volume utilise la privatepropagation de montage. Cela signifie qu'une fois le montage effectué, tous les changements qui se produisent du côté origine (par exemple, le côté "hôte" dans le cas de Docker) ne seront pas visibles sous le montage.

Il existe deux façons de gérer cela:

  1. Faites d'abord le montage NFS, puis démarrez le conteneur. Le montage se propage au conteneur, mais comme auparavant, aucune modification du montage ne sera visible par le conteneur (y compris les démontages).

  2. Utilisez la propagation "esclave". Cela signifie qu'une fois le montage créé, tout changement du côté d'origine (hôte docker) pourra être vu dans la cible (dans le conteneur). S'il vous arrive de faire des montages imbriqués, vous voudrez utiliser rslave( rpour récursif).

Il y a aussi une propagation "partagée". Ce mode apporterait des modifications au point de montage de l'intérieur du conteneur se propager à l'hôte, ainsi que l'inverse. Étant donné que votre utilisateur n'aurait même pas les privilèges pour effectuer de telles modifications (sauf si vous ajoutez CAP_SYS_ADMIN), ce n'est probablement pas ce que vous voulez.

Vous pouvez définir le mode de propagation lors de la création du montage comme suit:

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

L'autre alternative serait d'utiliser un volume plutôt qu'un montage hôte. Vous pouvez le faire comme ceci:

$ 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

Cela vous assurera de toujours monter dans le conteneur pour vous, ne dépend pas de la configuration de l'hôte d'une manière spécifique ou de la propagation du montage.
note : le :devant du chemin du périphérique est requis, juste quelque chose de bizarre sur le module du noyau nfs.
Remarque : Docker ne résout pas actuellement à <nfs host>partir d'un nom DNS (il le fera en 1.13), vous devrez donc fournir l'adresse IP ici.

Plus de détails sur les montages "sous-arborescence partagée": https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt


Très bonne réponse. Pourriez-vous le modifier pour être plus une réponse autonome qui explique comment définir MountFlags = slave dans le Docker Daemon et ne pas dépendre du contexte des autres réponses. Je passerai ensuite à la réponse acceptée.
Caleb

4

Activez la propagation du montage partagé sur le volume en ajoutant l'indicateur: shared à la fin de l'argument du volume:

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

Si Docker a été installé via un gestionnaire de packages ou un script d'installation pour systemd, vous devrez peut-être ajuster l'argument du démon MountFlags. Pour ce faire, recherchez le fichier docker.service:

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

Dans mon cas sur Ubuntu 16.04, il se trouvait dans /etc/systemd/system/multi-user.target.wants/docker.service. Modifiez ce fichier avec vi ou nano et assurez-vous que l'option MountFlags indique:

MountFlags=shared

Enregistrez le fichier, rechargez les arguments du démon et redémarrez docker:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

Vous devriez maintenant être en mesure de définir l'indicateur de propagation de montage partagé sur les volumes lorsque vous utilisez "Docker Run".


3

À partir de Docker 17.06, vous pouvez monter des partages NFS sur le conteneur directement lorsque vous l'exécutez, sans avoir besoin de fonctionnalités supplémentaires

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

Alternativement, vous pouvez créer le volume avant le conteneur:

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

Vous avez l'indication de https://github.com/moby/moby/issues/28809

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.