Montaje de un directorio NFS en el volumen del host que se comparte con Docker

8

Considere el siguiente contenedor Docker:

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

Esto monta el directorio host / tmp en / mnt / tmp dentro del contenedor alpino.

Ahora, en el sistema host, monte un volumen NFS en el directorio / tmp:

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

El montaje funciona en el sistema host y veo lo siguiente:

# ls /tmp/nfs
file1 file2 file3
#

Pero en el Docker Container, veo un directorio en blanco:

# ls /mnt/tmp/nfs
#

Sé que puedo evitar esto haciendo el montaje directamente en el Contenedor Docker. Pero estoy realmente interesado en saber por qué el montaje funciona en el contenedor host pero no en el contenedor acoplable.

Caleb
fuente
Es posible que necesite describir su sistema operativo, la versión de Docker, etc., etc. Acabo de probar esto con Centos 7 y Docker 1.10 desde extras y funcionó como se esperaba; el contenido del montaje NFS apareció dentro de un contenedor debian / jessie. También si tiene controles de seguridad (por ejemplo, SELinux) y otros indicadores.
Stephen Harris
Estoy usando Ubuntu 16.04 con Docker versión 1.12.0-dev, sin controles de seguridad adicionales. El problema solo se muestra cuando realizo el montaje NFS después de haber creado el contenedor Alpine. Si realizo el montaje NFS antes de crear el contenedor Alpine, lo veo como se esperaba.
Caleb

Respuestas:

15

Esto sucede porque el volumen está utilizando la privatepropagación de montaje. Esto significa que una vez que ocurre la montura, cualquier cambio que ocurra en el lado de origen (por ejemplo, el lado "host" en el caso de Docker) no será visible debajo de la montura.

Hay un par de formas de manejar esto:

  1. Primero monte el NFS, luego inicie el contenedor. La montura se propagará al contenedor, sin embargo, como antes, el contenedor no verá ningún cambio en la montura (incluidos los desmontes).

  2. Utilice la propagación "esclava". Esto significa que una vez que se crea el montaje, cualquier cambio en el lado de origen (host acoplable) podrá verse en el destino (en el contenedor). Si estás haciendo monturas anidadas, querrás usar rslave( rpara recursivo).

También hay propagación "compartida". Este modo haría cambios en el punto de montaje desde el interior del contenedor propagado al host, así como al revés. Dado que su usuario ni siquiera tendría privilegios para realizar tales cambios (a menos que agregue CAP_SYS_ADMIN), probablemente esto no sea lo que desea.

Puede configurar el modo de propagación al crear el montaje de esta manera:

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

La otra alternativa sería usar un volumen en lugar de un montaje de host. Puedes hacer esto así:

$ 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

Esto asegurará que siempre se monte en el contenedor por usted, no dependa de tener la configuración del host de alguna manera específica o de lidiar con la propagación del montaje.
nota : :se requiere la parte frontal de la ruta del dispositivo, algo extraño en el módulo del kernel nfs.
nota : Docker actualmente no se resuelve a <nfs host>partir de un nombre DNS (lo hará en 1.13), por lo que deberá proporcionar la dirección IP aquí.

Más detalles sobre los montajes de "subárbol compartido": https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt

cpuguy83
fuente
Muy buena respuesta. ¿Podría editarlo para que sea una respuesta más independiente que explique cómo configurar MountFlags = slave en Docker Daemon y no depender del contexto de otras respuestas. Entonces cambiaré esto a la respuesta aceptada.
Caleb
4

Habilite la propagación de montaje compartido en el volumen agregando el indicador: shared al final del argumento de volumen:

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

Si Docker se instaló a través de un administrador de paquetes o script de instalación para systemd, es posible que deba ajustar el argumento del demonio MountFlags. Para hacerlo, busque el archivo docker.service:

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

En mi caso en Ubuntu 16.04, estaba ubicado en /etc/systemd/system/multi-user.target.wants/docker.service. Edite este archivo con vi o nano, y asegúrese de que la opción MountFlags lea:

MountFlags=shared

Guarde el archivo, vuelva a cargar los argumentos del demonio y reinicie la ventana acoplable:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

Ahora debería poder establecer el indicador de propagación de montaje compartido en los volúmenes cuando use "docker run".

Caleb
fuente
3

A partir de Docker 17.06, puede montar recursos compartidos NFS en el contenedor directamente cuando lo ejecuta, sin la necesidad de capacidades adicionales

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

Alternativamente, puede crear el volumen antes del contenedor:

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

Obtuve la pista de https://github.com/moby/moby/issues/28809

ThiagoAlves
fuente