Montaggio di una directory NFS nel volume host condiviso con Docker


8

Si consideri il seguente contenitore Docker:

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

Questo monta la directory host / tmp in / mnt / tmp all'interno del contenitore alpino.

Ora, sul sistema host, monto un volume NFS nella directory / tmp:

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

Il mount funziona sul sistema host e vedo quanto segue:

# ls /tmp/nfs
file1 file2 file3
#

Ma sul Docker Container, vedo una directory vuota:

# ls /mnt/tmp/nfs
#

So che posso aggirare questo facendo il mount direttamente nel Docker Container. Ma sono davvero interessato a sapere perché il montaggio funziona sul contenitore host ma non nel contenitore docker?


Potrebbe essere necessario descrivere il tuo sistema operativo, la versione docker, ecc. Ecc. Ho appena provato questo con Centos 7 e docker 1.10 dagli extra e ha funzionato come previsto; il contenuto del mount NFS è apparso all'interno di un contenitore debian / jessie. Anche se si dispone di controlli di sicurezza (ad esempio SELinux) e altri flag.
Stephen Harris,

Sto usando Ubuntu 16.04 con Docker versione 1.12.0-dev, senza controlli di sicurezza aggiuntivi. Il problema si manifesta solo quando realizzo il supporto NFS dopo aver creato il container Alpine. Se eseguo il montaggio NFS prima di creare il contenitore Alpine, lo vedo come previsto.
Caleb,

Risposte:


15

Ciò accade perché il volume utilizza la privatepropagazione di mount. Ciò significa che una volta che si verifica il mount, eventuali modifiche che si verificano sul lato di origine (ad esempio il lato "host" nel caso di Docker) non saranno visibili sotto il mount.

Ci sono un paio di modi per gestirlo:

  1. Eseguire prima il montaggio NFS, quindi avviare il contenitore. Il montaggio si propaga al contenitore, tuttavia come prima le eventuali modifiche al montaggio non verranno visualizzate dal contenitore (compresi gli smontaggi).

  2. Usa la propagazione "slave". Ciò significa che una volta creato il mount, qualsiasi modifica sul lato di origine (docker host) sarà visibile nella destinazione (nel contenitore). Se ti capita di fare montature nidificate, ti consigliamo di utilizzare rslave( rper ricorsivo).

C'è anche una propagazione "condivisa". Questa modalità farebbe in modo che le modifiche al mountpoint dall'interno del contenitore si propaghino all'host e viceversa. Poiché il tuo utente non avrebbe nemmeno i privilegi per apportare tali modifiche (a meno che tu non aggiunga CAP_SYS_ADMIN), questo probabilmente non è quello che desideri.

È possibile impostare la modalità di propagazione durante la creazione del mount in questo modo:

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

L'altra alternativa sarebbe usare un volume piuttosto che un mount host. Puoi farlo in questo modo:

$ 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

Questo assicurerà di montarlo sempre nel container, non fare affidamento sull'avvio dell'host in un modo specifico o sulla gestione della propagazione del mount.
nota : :è richiesto nella parte anteriore del percorso del dispositivo, solo qualcosa di strano nel modulo del kernel nfs.
nota : Docker attualmente non risolve <nfs host>da un nome DNS (lo farà in 1.13) quindi dovrai fornire qui l'indirizzo IP.

Maggiori dettagli sui supporti "subtree condivisi": https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt


Ottima risposta Potresti modificarlo per essere più una risposta autonoma che spiega come impostare MountFlags = slave nel demone Docker e non dipendere dal contesto di altre risposte. Quindi passerò alla risposta accettata.
Caleb,

4

Abilita la propagazione di mount condivisa sul volume aggiungendo il flag: shared alla fine dell'argomento volume:

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

Se Docker è stato installato tramite un gestore pacchetti o uno script di installazione per systemd, potrebbe essere necessario modificare l'argomento del demone MountFlags. Per fare ciò, individuare il file docker.service:

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

Nel mio caso su Ubuntu 16.04, si trovava in /etc/systemd/system/multi-user.target.wants/docker.service. Modifica questo file con vi o nano e assicurati che l'opzione MountFlags sia:

MountFlags=shared

Salvare il file, ricaricare gli arg daemon e riavviare la finestra mobile:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

Ora dovresti essere in grado di impostare il flag di propagazione del mount condiviso sui volumi quando usi "docker run".


3

A partire dalla finestra mobile 17.06, è possibile montare le condivisioni NFS sul contenitore direttamente quando lo si esegue, senza la necessità di funzionalità aggiuntive

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

In alternativa, è possibile creare il volume prima del contenitore:

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

Ho ricevuto il suggerimento da https://github.com/moby/moby/issues/28809

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.