在Docker容器内挂载NFS共享

50

有人知道如何在CentOS基础镜像的Docker容器内挂载NFS共享吗?我已尝试了以下命令:

mount server:/dir /mount/point

并获得了下一个错误:

mount.nfs: rpc.statd未运行,但远程锁定需要它。
mount.nfs: 要么使用“-o nolock”以保持本地锁定,要么启动statd。
mount.nfs: 指定了不正确的挂载选项

当我尝试使用-o nolock选项时,出现以下错误:

mount.nfs: Operation not permitted

您可以参考下面的链接。https://dev59.com/U1cO5IYBdhLWcg3wvUQp?answertab=votes#tab-top - tony
5个回答

86

从Docker 17.06开始,您可以在运行容器时直接挂载NFS共享,无需额外的功能。

export NFS_VOL_NAME=mynfs
export NFS_LOCAL_MNT=/mnt/mynfs
export NFS_SERVER=my.nfs.server.com
export NFS_SHARE=/my/server/path
export 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

4
这应该是自Docker 17.06版本以来的第一项功能。我等待这个功能已经很久了! - Slack Flag
1
我已编辑答案,修正了一个拼写错误,并突出了人们通常想要自定义的参数(容器中的本地挂载点、NFS服务器主机名/IP和远程NFS共享路径)。 - ThiagoAlves
1
我仍在努力理解嵌入式挂载选项,但看起来这个对我有效。我真的很喜欢它在创建容器的过程中具有幂等性地创建卷。 - rubicks
1
你能否使用相同的方法来处理绑定挂载而不是卷? - Bort
按照您所写的方式操作,我收到了“没有这样的文件或目录”的错误提示,尽管我可以使用完全相同的设置从我的主机手动挂载。 - pbn

50
要使用mount,您需要CAP_SYS_ADMIN权限,但在创建容器时Docker会删除此权限。有几种解决方案:
  1. Start the container with the --cap-add sys_admin flag. This causes Docker to retain the CAP_SYS_ADMIN capability, which should allow you to mount a NFS share from within the container. This might be a security issue; do not do this in untrusted containers. [A previous version of this answer suggested using the --privileged=true to retain all capabilities, thanks to @earcam for the suggestion to use --cap-add instead].
  2. Mount the NFS share on the host and pass it into the container as a host volume:

    you@host > mount server:/dir /path/to/mount/point
    you@host > docker run -v /path/to/mount/point:/path/to/mount/point
    
  3. Use a Docker volume plugin (like the Netshare plugin) to directly mount the NFS share as a container volume:

    you@host > docker run \
      --volume-driver=nfs \
      -v server/dir:/path/to/mount/point \
      centos
    

选项1:如果不使用“--privileged=true”,如何解决问题? - Zelphir Kaltstahl
3
方法2似乎不起作用。我已经在本地系统上挂载了NFS并且可以看到所有文件。但是当我将挂载的文件夹作为卷传递给容器时,我只得到了一个空文件夹。我尝试了像Jing Qiu建议的更改权限,但没有成功。 - cage
1
(在2019年)--cap-add--privileged=true提供了更细粒度的控制。 - earcam
1
@earcam 谢谢你的建议!我已经将它融入到我的答案中了。 - helmbert
1
嗨@helmbert,我在使用你的建议#2时遇到了问题,一些容器需要chown它们在挂载目录中创建的文件。然而,根据我的发现,NFS不允许这样做。你有没有找到解决方法或者你没有遇到任何需要这样做的容器? - dalanmiller
显示剩余2条评论

11

对于接受答案中列出的第二个选项,我不确定您是否尝试过使用"docker run -v"命令将主机上的NFS共享传递给Docker容器作为卷。

我最近尝试了这样做,以下是主机上NFS共享的信息:

nfs-server:/path_to_mount on /path_dest type nfs

然后:

docker run -it -v /path_dest:/path_in_docker docker_name bash

但是 Docker 守护进程始终报告以下错误:

docker: Error response from daemon: stat /path_dest: permission denied.

经过多次搜索,我发现错误实际上来自于作为"root"运行的docker daemon。当docker运行容器并挂载卷时,它会请求docker daemon进行挂载。问题是,NFS服务器会以不同的方式处理"root"。默认情况下,NFS服务器会将"root"映射为"nobody",导致错误消息:参考资料


我也遇到了同样的问题,你解决了吗? - reptilicus
我也遇到了关于“nobody”的同样问题。肮脏的解决方法是在NFS服务器上使用“no_root_squash”。如果IT不允许你这样做,那么嗯... - Morris Yang

2
我在Docker容器中挂载NFS,感谢@helmbert。
  1. Run a docker container with the --privileged=true flag.

    $ docker run -it --privileged=true centos:7 bash
    [root@f7915ae635aa /]# yum install -y nfs-utils
    
  2. Install the nfs tool package and mount nfs on CentOS.

    [root@f7915ae635aa /]# yum install -y nfs-utils
    [root@f7915ae635aa /]# mount -t nfs example.tw:/target/ /srv -o nolock
    
  3. Show mount of the nfs server.

    [root@f7915ae635aa /]# showmount example.tw
    Hosts on example.tw:
    10.10.10.1
    10.10.10.2
    

1

对于我来说,仅向客户端容器添加--cap-add sys_admin标志是不够的。 我收到了以下错误:

mount.nfs: mount(2): Permission denied
mount.nfs: access denied by server while mounting 1.2.3.4:/exports

经过数小时的研究,我发现似乎需要完整特权--privileged才能在Docker容器内正确挂载..

同时不要忘记在Docker容器内安装必要的NFS客户端软件包。 对于基于Debian的容器:

apt-get install -y nfs-common

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接