web-dev-qa-db-ja.com

Dockerと共有されるホストボリュームへのNFSディレクトリのマウント

次のDockerコンテナを検討してください。

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

これにより、ホストディレクトリ/ tmpがAlpineコンテナー内の/ mnt/tmpにマウントされます。

次に、ホストシステムでNFSボリュームを/ tmpディレクトリにマウントします。

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

マウントはホストシステムで機能し、次のように表示されます。

# ls /tmp/nfs
file1 file2 file3
#

しかし、Dockerコンテナでは、空のディレクトリが表示されます。

# ls /mnt/tmp/nfs
#

Dockerコンテナーで直接マウントすることで、これを回避できることを知っています。しかし、マウントがホストコンテナーでは機能するが、Dockerコンテナーでは機能しない理由を知りたいのですが、本当に興味がありますか?

8
Caleb

これは、ボリュームがprivateマウント伝播を使用しているために発生します。つまり、マウントが行われると、Origin側(Dockerの場合は「ホスト」側など)で行われた変更はマウントの下に表示されなくなります。

これを処理する方法はいくつかあります。

  1. 最初にNFSマウントを実行してから、コンテナーを開始します。マウントはコンテナーに伝達されますが、以前のように、マウントへの変更はコンテナーに表示されません(アンマウントを含む)。

  2. 「スレーブ」伝播を使用します。つまり、マウントが作成されると、Origin側(docker Host)での変更は、ターゲット(コンテナー内)で確認できるようになります。ネストされたマウントを実行している場合は、rslave(再帰的な場合はr)を使用する必要があります。

「共有」伝播もあります。このモードでは、コンテナー内からマウントポイントに変更が加えられ、その逆も同様です。ユーザーにはそのような変更を行う権限さえないので(CAP_SYS_ADMINを追加しない限り)、これはおそらく必要なことではありません。

次のようにマウントを作成するときに、伝播モードを設定できます。

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

もう1つの方法は、ホストマウントではなくボリュームを使用することです。あなたはそうすることができます:

$ 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

これにより、常にコンテナーにマウントされます。特定の方法でホストをセットアップしたり、マウントの伝播を処理したりする必要はありません。
:デバイスパスの前に必要ですが、nfsカーネルモジュールについては奇妙なことです。
note:Dockerは現在解決しません<nfs Host> DNS名から(1.13で対応予定)、IPアドレスをここで指定する必要があります。

「共有サブツリー」マウントの詳細: https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt

15
cpuguy83

ボリューム引数の最後に:sharedフラグを追加して、ボリュームで共有マウントの伝播を有効にします。

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

Dockerがパッケージマネージャーまたはsystemdのインストールスクリプトを使用してインストールされた場合、MountFlagsデーモンの引数を調整する必要がある場合があります。これを行うには、docker.serviceファイルを探します。

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

私の場合、Ubuntu 16.04では/etc/systemd/system/multi-user.target.wants/docker.serviceにありました。このファイルをviまたはnanoで編集し、MountFlagsオプションが次のようになっていることを確認します。

MountFlags=shared

ファイルを保存し、デーモンの引数を再読み込みして、Dockerを再起動します。

$ Sudo systemctl daemon-reload
$ Sudo systemctl restart docker

これで、「docker run」を使用するときに、ボリュームに共有マウント伝播フラグを設定できるはずです。

4
Caleb

Docker 17.06から、コンテナーを実行するときに、NFS共有をコンテナーに直接マウントできます。追加の機能は必要ありません。

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

または、コンテナの前にボリュームを作成することもできます。

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

https://github.com/moby/moby/issues/28809 からヒントを得ました

3
ThiagoAlves