使主机上的 NFS 挂载在 Docker 容器内可见且可读写

使主机上的 NFS 挂载在 Docker 容器内可见且可读写

我是 Docker 新手,我想使用它来为我的代码获取一个可控的编译环境。

我已经有一个包含所有所需工具的 Docker 映像。我目前的问题如下:

  • 我的代码位于主机中,位于从 NFS 服务器挂载的主文件夹中
  • 我想让这个文件夹在 Docker 容器内以 r+w 权限可见

这是我第一次尝试(以源文件夹作为卷运行容器)以及收到的错误:

[mbrandalero@machine ~]$ docker run -it --cap-add sys_admin -v "/homes/mbrandalero/src:/usr/local/src/" mbrandalero/my-image bash
/usr/bin/docker-current: Error response from daemon: error while creating mount source path '/homes/mbrandalero/src': mkdir /homes/mbrandalero/src: permission denied.

(显然它正在尝试在主机端创建目录,但该目录已经存在)

奇怪的是,当我尝试以整个主文件夹作为卷运行容器时,它可以工作但会产生不同的错误(文件夹中没有写权限):

[mbrandalero@machine ~]$ docker run -it --cap-add sys_admin -v "/homes/mbrandalero/:/usr/local/src/home" mbrandalero/my_image bash
root@46712ad936f2:/usr/local/src# cd home/
bash: cd: home/: Permission denied
root@46712ad936f2:/usr/local/src# ls -lah | grep "\(\.\|home\)"
total 4.0K
drwxr-xr-x  1 root  root    18 May 20 14:50 .
drwxr-xr-x  1 root  root    17 May 15 14:06 ..
drwxr-x--- 30 10031 10031 4.0K May 20 15:03 home

我做得对吗?我遗漏了什么?

附加信息:

  • 操作系统:CentOS Linux 7.6
  • Docker 版本:1.13.1

更新(1):

显然,在运行时设置用户 IDdocker run可以修复此问题,但这是正确的做法吗?以这种方式运行可以解决问题,但看起来很奇怪(我得到的用户名是“我没有名字!”):

[mbrandalero@machine ~]$ docker run -it --cap-add sys_admin -v "/homes/mbrandalero/:/usr/local/src/home" --user $(id -u) mbrandalero/my_image bash
I have no name!@2efec822e572:/usr/local/src$ cd home/
I have no name!@2efec822e572:/usr/local/src/home$

答案1

正如您在更新中指出的那样,文件上的 UID 未映射到绑定挂载中,这是 Linux 进行绑定挂载的方式。您可以使用不同的 UID 启动容器,但这会导致容器内的 /etc/passwd 映射到不同的用户,甚至没有(在您的情况下)用户。有多种选择,但我的偏好是使用 usermod 命令修改容器的 UID,该命令在图像的入口点内运行,并使用我的修复权限脚本。这需要以 root 身份运行,但随后您可以使用gosu在运行命令时返回到用户。我在我的dockercon 演示


请注意,除了绑定挂载到主机 NFS 目录之外,您还可以直接在 NFS 服务器上执行卷挂载。以下是执行此操作的几个示例:

  # create a reusable volume
  $ docker volume create --driver local \
      --opt type=nfs \
      --opt o=nfsvers=4,addr=nfs.example.com,rw \
      --opt device=:/path/to/dir \
      foo

  # or from the docker run command
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=nfs.example.com\",volume-opt=device=:/host/path \
    foo

  # or to create a service
  $ docker service create \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=nfs.example.com\",volume-opt=device=:/host/path \
    foo

  # inside a docker-compose file
  ...
  volumes:
    nfs-data:
      driver: local
      driver_opts:
        type: nfs
        o: nfsvers=4,addr=nfs.example.com,rw
        device: ":/path/to/dir"
  ...

答案2

如果您以 身份运行容器root,您可能会看到该error while creating mount source path ... permission denied消息,因为 NFS 主机正在重新映射所有远程根 UID(又名 root-squash)。

https://en.wikipedia.org/wiki/Unix_security#Root_squash

这是一项安全导向功能,可防止恶意行为者以自己的root用户身份挂载您的共享,然后对数据进行恶意操作。因此,NFS 挂载通常root_squash默认设置该选项,以防止此类问题。如果您需要容器以 身份运行root,您可以使用no_root_squashNFS 主机/etc/exports文件中的选项覆盖此选项。

/srv/nfs/shared_folder <hostname>(rw,sync,no_subtree_check,no_root_squash)

http://nfs.sourceforge.net/nfs-howto/ar01s03.html

https://www.thegeekdiary.com/understanding-the-etc-exports-file/

答案3

这对我有用 - 将主机 nfs 路径声明为容器的卷。并且主机 nfs 路径是非主目录路径,它不是主目录。

我的主机 nfs 挂载点:/mnt/abc

我的 docker-compose.yml 文件片段。

   ...
   volumes:
  - /mnt/abc/:/abc
   ...

相关内容