Memasang Direktori NFS ke Volume Host yang dibagikan dengan Docker

8

Pertimbangkan wadah Docker berikut:

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

Ini memasang direktori host / tmp ke / mnt / tmp di dalam wadah alpine.

Sekarang, pada Sistem Host saya memasang volume NFS ke direktori / tmp:

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

Mount berfungsi pada Sistem Host, dan saya melihat yang berikut:

# ls /tmp/nfs
file1 file2 file3
#

Tetapi di Docker Container, saya melihat direktori kosong:

# ls /mnt/tmp/nfs
#

Saya tahu bahwa saya dapat mengatasi ini dengan melakukan mount langsung di Docker Container. Tetapi saya benar-benar tertarik untuk mengetahui mengapa mount bekerja pada container host tetapi tidak pada container docker?

Caleb
sumber
Anda mungkin perlu menjelaskan OS Anda, versi buruh pelabuhan, dll. Saya baru saja mencoba ini dengan Centos 7 dan buruh pelabuhan 1.10 dari tambahan dan itu berfungsi seperti yang diharapkan; isi mount NFS muncul di dalam dalam wadah debian / jessie. Juga apakah Anda memiliki kontrol keamanan (mis. SELinux) dan bendera lainnya.
Stephen Harris
Saya menggunakan Ubuntu 16.04 dengan Docker versi 1.12.0-dev, tidak ada kontrol keamanan tambahan. Masalahnya hanya muncul sendiri ketika saya membuat NFS Mount setelah saya membuat wadah Alpine. Jika saya membuat Mount NFS sebelum saya membuat wadah Alpine, saya melihatnya seperti yang diharapkan.
Caleb

Jawaban:

15

Ini terjadi karena volumenya menggunakan privatemount propagation. Ini berarti bahwa begitu mount terjadi, setiap perubahan yang terjadi di sisi asal (mis. Sisi "host" dalam kasus Docker) tidak akan terlihat di bawah mount.

Ada beberapa cara untuk menangani ini:

  1. Lakukan pemasangan NFS terlebih dahulu, kemudian mulai wadah. Mount akan merambat ke wadah, namun seperti sebelum perubahan apa pun pada mount tidak akan terlihat oleh kontainer (termasuk unmount).

  2. Gunakan propagasi "budak". Ini berarti bahwa setelah mount dibuat, setiap perubahan di sisi asal (buruh pelabuhan) akan dapat dilihat di target (dalam wadah). Jika Anda sedang melakukan mount bersarang, Anda akan ingin menggunakan rslave( runtuk rekursif).

Ada juga propagasi "bersama". Mode ini akan membuat perubahan ke titik mount dari dalam wadah merambat ke host, serta sebaliknya. Karena pengguna Anda bahkan tidak memiliki hak istimewa untuk melakukan perubahan seperti itu (kecuali jika Anda menambahkan CAP_SYS_ADMIN), ini mungkin bukan yang Anda inginkan.

Anda dapat mengatur mode propagasi saat membuat mount seperti:

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

Alternatif lain adalah menggunakan volume daripada mount host. Anda dapat melakukan ini seperti ini:

$ 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

Ini akan memastikan untuk selalu me-mount dalam wadah untuk Anda, tidak bergantung pada pengaturan host dalam beberapa cara tertentu atau berurusan dengan propagasi mount.
Catatan : :di bagian depan lintasan perangkat diperlukan, hanya sesuatu yang aneh tentang modul kernel nfs.
Catatan : Docker saat ini tidak menyelesaikan <nfs host>dari nama DNS (itu akan di 1.13) sehingga Anda harus memberikan alamat ip di sini.

Rincian lebih lanjut tentang pemasangan "subtree bersama": https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt

cpuguy83
sumber
Jawaban yang sangat bagus Bisakah Anda mengeditnya menjadi lebih dari jawaban mandiri yang menjelaskan cara mengatur MountFlags = slave di Docker Daemon dan tidak bergantung pada konteks jawaban lainnya. Maka saya akan mengalihkan ini ke jawaban yang diterima.
Caleb
4

Aktifkan propagasi pemasangan bersama pada volume dengan menambahkan: shared flag di akhir argumen volume:

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

Jika Docker diinstal melalui manajer paket atau menginstal skrip untuk systemd, Anda mungkin perlu menyesuaikan argumen daemon MountFlags. Untuk melakukannya, cari file docker.service:

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

Dalam kasus saya di Ubuntu 16.04, ia berada di /etc/systemd/system/multi-user.target.wants/docker.service. Edit file ini dengan vi atau nano, dan pastikan bahwa opsi MountFlags berbunyi:

MountFlags=shared

Simpan file, muat ulang daemon args, dan mulai ulang buruh pelabuhan:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

Sekarang Anda harus dapat mengatur bendera propagasi mount bersama pada volume saat menggunakan "docker run".

Caleb
sumber
3

Mulai dari buruh pelabuhan 17,06, Anda dapat memasang saham NFS ke wadah secara langsung saat Anda menjalankannya, tanpa perlu kemampuan tambahan

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

Atau, Anda dapat membuat volume sebelum wadah:

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

Dapatkan petunjuk dari https://github.com/moby/moby/issues/28809

ThiagoAlves
sumber