【问题标题】:How to solve permission denied when mounting volume during docker run command?如何解决在 docker run 命令期间挂载卷时权限被拒绝的问题?
【发布时间】:2020-02-23 19:36:36
【问题描述】:

我正在尝试运行绑定目录的容器,但我收到有关权限被拒绝的错误消息,因此容器根本无法启动。

在当前目录中有一个名为main的目录,在容器中有一个目录/builder/project

david@localhost ~/contrib_archives $ docker run -v `realpath main`:/build/project builder
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"/home/david/contrib_archives/main\\\" to rootfs \\\"/var/lib/docker/100000.100000/overlay2/2d14c3752819ff12891bace539ae4ef0039c42e6deb00170432c934d681b842e/merged\\\" at \\\"/build/project\\\" caused \\\"stat /home/david/contrib_archives/main: permission denied\\\"\"": unknown.
ERRO[0000] error waiting for container: context canceled 

如果我在没有-v 参数的情况下运行容器,它运行良好(但它没用,因为我无法获取数据)。

有人知道问题可能是什么吗?

我正在使用用户命名空间运行。

【问题讨论】:

    标签: docker docker-volume


    【解决方案1】:

    问题是我使用用户名空间运行并且没有正确的映射。

    在我的发行版中,文件 /etc/subuid 包含以下内容:

    david:100000:65536
    

    但我必须让它看起来像这样:

    david:1000:1
    david:100000:65536
    

    这样我自己的 uid 就会映射到容器内的根目录。

    一个不错的指南似乎是这个https://www.jujens.eu/posts/en/2017/Jul/02/docker-userns-remap/

    【讨论】:

      【解决方案2】:

      给定一个容器绑定堆,即 -v <host bind>:<container bind> 与默认的 docker 用户重新映射,我也遇到了访问被拒绝类型的错误,关键细节是:

      mounting "<host bind>" to rootfs at "<container bind>" caused: stat <host bind>: permission denied: unknown.
      

      显然 docker 正在尝试统计 &lt;host bind&gt; 但缺少权限,并且“未知”帐户名部分是因为 docker 重新映射的 uid 没有在 /etc/passwd 中设置条目。

      我通过确保&lt;host bind&gt; 的父目录允许目录执行权限解决了我的问题。例如。在用于绑定挂载的目录的父目录中:

      setfacl -m u:<userns-remap-uid>:X,g:<userns-remap-gid>:X .
      

      . 是 `./ 的父级。

      Container with mounts fails to start with --userns-remap=default option #28859

      一个经常被忽视的问题是一个目录的 unix 执行权限的含义,它提供“搜索”权限,更好地解释为 (wikipedia: File-system permissions):

      在文件名已知的情况下访问文件内容和元信息的能力

      大多数使用较弱的 umask 0002 的安装不会遇到此问题,因为其他默认情况下具有执行权限,但我运行了一个更安全的设置,我不会让系统上的每个帐户都可以访问我的主目录,其他没有 exec 或 read。无论如何,docker 容器绑定挂载代码无法统计主机的绑定目录源,因为由于缺少对父文件夹的访问权限,它缺乏获取元数据的权限。可以说,docker 宁愿执行绑定挂载,然后仅在稍后在容器初始化期间切换到重新映射的 uid,以避免需要父目录执行访问。

      作为一个更大的例子,假设你想将一个目录绑定到一个容器中,试试这个。例如。给定docker-root 作为主机绑定目录:

      mkdir /tmp/test-dock-userns-remap
      chmod o-rwx /tmp/test-dock-userns-remap
      mkdir /tmp/test-dock-userns-remap/docker-root
      chmod o-rwx /tmp/test-dock-userns-remap/docker-root
      

      注意,docker-root 父目录权限位是 770:

      $ cd /tmp/test-dock-userns-remap
      $ stat --format='type=%F perm=%A(%a)' .
      type=directory perm=drwxrwx---(770)
      

      /etc/docker/daemon.json 中默认设置为"userns-remap": "default"。然后以下内容将使 docker-root 绑定可挂载并可被容器进程以 root 或较低权限的用户(例如容器中的 uid 1000)运行:

      # Get the base/root rempped UID and GID
      dockremap_root_uid=$(grep dockremap /etc/subuid | cut -d ':' -f 2)
      dockremap_root_gid=$(grep dockremap /etc/subgid | cut -d ':' -f 2)
      # Calculate the remapped standard normal user
      user_uid=1000
      user_gid=1000
      dockremap_user_uid=$((dockremap_root_uid + user_uid))
      dockremap_user_gid=$((dockremap_root_gid + user_gid))
      # Ensure the parent dir premits the remapped root UID with rX access or else a mounting rootfs "permission denied: unknown." issue can occur
      setfacl --modify "u:$dockremap_root_uid:rX,g:$dockremap_root_gid:X" .
      # Set ACL to permit read and/or write access where needed
      setfacl --recursive --modify "u:$dockremap_root_uid:rwX,g:$dockremap_root_gid:rwX" ./docker-root
      setfacl --recursive --default --modify "u:$dockremap_root_uid:rwX,g:$dockremap_root_gid:rwX" ./docker-root
      # Allow non-priv uid 1000 in container to have access
      setfacl --recursive --modify "u:$dockremap_user_uid:rwX,g:$dockremap_user_gid:rwX" ./docker-root
      setfacl --recursive --default --modify "u:$dockremap_user_uid:rwX,g:$dockremap_user_gid:rwX" ./docker-root
      # Ensure own user has access
      setfacl --recursive --modify "u:$(id -u):rwX,g:$(id -u):rwX" ./docker-root
      setfacl --recursive --default --modify "u:$(id -u):rwX,g:$(id -u):rwX" ./docker-root
      # Set ownership to the remapped docker root UID
      sudo chown --recursive "$dockremap_root_uid:$dockremap_root_gid" ./docker-root
      

      注意,大多数人可能希望将扩展 ACL 设置为默认 ACL。这可确保在目录中创建的文件(由主机进程或容器进程创建)将具有相同的默认 ACL 传播。

      一旦我做了上述类似的事情,以下工作没有错误,容器从它自己的角度看到 root 访问:

      $ sudo docker container run --rm --volume $(pwd)/docker-root:/root alpine sh -c "touch /root/test; stat -c 'name=%n inode=%i user=%U(%u) group=%G(%g) perm=%A(%a)' /root/test"
      name=/root/test inode=262164 user=root(0) group=root(0) perm=-rw-rw----(660)
      

      但在主机上,该目录归重新映射的 docker root ID 所有,并且由于扩展 ACL,我的普通用户仍然可以访问:

      $ stat -c 'name=%n inode=%i user=%U(%u) group=%G(%g) perm=%A(%a)' docker-root/test
      name=docker-root/test inode=262164 user=UNKNOWN(165536) group=UNKNOWN(165536) perm=-rw-rw----(660)
      $ getfacl docker-root/test
      # file: docker-root/test
      # owner: 165536
      # group: 165536
      user::rw-
      user:myuser:rwx     #effective:rw-
      user:165536:rwx         #effective:rw-
      user:166536:rwx         #effective:rw-
      group::rwx          #effective:rw-
      group:myuser:rwx        #effective:rw-
      group:165536:rwx        #effective:rw-
      group:166536:rwx        #effective:rw-
      mask::rw-
      other::---
      

      在我的情况下,这是有道理的:

      $ grep dockremap /etc/sub{u,g}id
      /etc/subuid:dockremap:165536:65536
      /etc/subgid:dockremap:165536:65536
      

      要重新映射主机上命名的用户,请在 /etc/passwd 和 /etc/group 中创建条目。例如:

      if ! getent passwd dockremap-root; then
          sudo groupadd --system --gid "$dockremap_root_gid" dockremap-root
          sudo useradd --system --no-create-home --home-dir "/var/lib/docker/$dockremap_root_uid.$dockremap_root_gid" --shell /bin/false --uid "$dockremap_root_uid" --gid "$dockremap_root_gid" --comment 'userns remap for docker root' dockremap-root
      fi
      if ! getent passwd dockremap-user; then
          sudo groupadd --system --gid "$dockremap_user_gid" dockremap-user
          sudo useradd --system --no-create-home --home-dir "/var/lib/docker/$dockremap_root_uid.$dockremap_root_gid" --shell /bin/false --uid "$dockremap_user_uid" --gid "$dockremap_user_gid" --comment 'userns remap for docker user' dockremap-user
      fi
      

      但是,docker userns remap 的全部目的是使容器的帐户不映射到操作系统上的任何有效帐户,因此上述可能会适得其反并增加曝光率。

      【讨论】:

      • 我认为dockremap_root_gid 应该从文件/etc/subgid 中读取,所以命令/行dockremap_root_gid=$(grep dockremap /etc/subuid | cut -d ':' -f 2) 应该是dockremap_root_gid=$(grep dockremap /etc/subgid | cut -d ':' -f 2)
      • 感谢@CDuv,错误重用 uid 而不是 gid 已更正。
      【解决方案3】:

      我遇到了类似的问题,我所做的是我为目标和源提供了完全相同的路径,只是为了测试并且有效。

      您能否尝试以下方法,看看它是否能够运行,不用担心在容器中创建相同的路径,它会自行创建,只需运行以下一次,将路径编辑为主文件夹,然后让我知道它是否适合你:

      docker run -it -v /path/to/main/:/path/to/main builder

      【讨论】:

      • 这看起来很奇怪。
      • @LtWorf 我知道是这样,但你试过这样跑步吗?有效果吗?
      猜你喜欢
      • 2016-03-30
      • 2019-06-05
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 1970-01-01
      • 1970-01-01
      • 2022-06-23
      相关资源
      最近更新 更多