如何解决在 docker 运行 命令期间挂载卷时权限被拒绝的问题?

How to solve permission denied when mounting volume during docker run command?

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

在当前目录中有一个名为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 运行 -it -v /path/to/main/:/path/to/main 生成器

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

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

david:100000:65536

但我不得不让它看起来像这样:

david:1000:1
david:100000:65536

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

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

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

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

显然 docker 正在尝试统计 <host bind> 但缺少权限,“未知”帐户名称部分是因为 docker 重新映射的 uid 没有在 [=65= 中设置条目].

我通过确保 <host bind> 的父目录允许目录执行权限来解决我的问题。例如。在用于绑定安装的目录的父目录中:

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 执行权限的含义,它提供“搜索”权限,更好地解释为 as (wikipedia: File-system permissions):

the ability to access file contents and meta-information if its name is known

大多数使用 0002 较弱 umask 的安装不会 运行 出现此问题,因为默认情况下其他人具有执行权限,但我 运行 一个更安全的设置,我没有' 让系统上的每个帐户都可以访问我的主目录,而其他帐户没有 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 用户重新映射的全部意义在于使容器的帐户不映射到 OS 上的任何有效帐户,因此上述做法可能适得其反并增加曝光率。