如何在Docker中实现挂载卷的一致性所有权?

7
我正试图理解docker上出现的一些奇怪行为。我想要运行一个容器,将缓存数据写入来自主机的挂载卷中,以便稍后重用该容器的未来执行,并且可以从主机读取。在主机上,我看到我的用户具有用户ID 1000
# This is on the host
$ id
uid=1000(juan-munoz) gid=1000(juan-munoz) groups=1000(juan-munoz)...

我正在运行容器,没有为用户设置任何特殊标志,因此它以root身份运行:

# This is on the container
$ id
uid=0(root) gid=0(root) groups=0(root)

此外,已经存在一个id=1000的用户:

# The image is provided by AWS and apparently it includes a user with this ID
$ id -nu 1000
ec2-user

我使用-v /some/local/directory:/var/mounted挂载了一个目录。在本地,这个目录是由我的用户(id=1000)拥有的:

# On the host
ls -ld /some/local/directory
drwx------ 2 juan-munoz juan-munoz 4.0K Jun 21 16:21 /some/local/directory

在容器中,如果我检查目录,会发现它当前由root所有。这是我不理解的第一部分。
# ls -ld /var/mounted
drwx------ 2 root root 4096 Jun 22 03:36 /var/mounted

为什么是root?我原本期望使用mount时能够尊重用户ID。

如果我试图将用户更改为1000,会出现以下情况:

# Inside the container
$ chown -R 1000:1000 /var/mounted
ls -ld /var/mounted
drwx------ 2 ec2-user 1000 4096 Jun 22 03:36 /var/mounted

这个对我看起来很好,但是当我这么做时,如果我查看 host 上发生的情况,我会看到以下内容:

# On the host
ls -ld /some/local/directory
drwx------ 2     100999     100999 4.0K Jun 21 20:36 /some/local/directory

主机或容器的所有者出了问题。如果我在主机上运行chown 1000:1000,容器将其视为root,如果我在容器上运行chown 1000:1000,主机将其视为100999

我做错了什么?

复现步骤

$ mkdir $HOME/testing
$ docker run -it --name=ubuntu-test --entrypoint="/bin/bash" --rm -v $HOME/testing:$HOME/testing ubuntu:latest

# Inside the container
$ cd /home/myusername/testing
$ touch file.txt
root@b98b7a5445e3:/home/juan-munoz/testing# ls -l
total 0
-rw-r--r-- 1 root root 0 Jun 30 23:52 file.txt

# Outside the container
$ ls -l $HOME/testing
total 0
-rw-r--r-- 1 juan-munoz juan-munoz 0 Jun 30 16:52 file.txt

观察到的行为:

  • 在某些计算机上,从容器外部访问文件时,该文件的所有者是本地用户。而在另一些计算机上,该文件的所有者是 root。

期望的行为:

  • 在不同计算机上表现一致。

你是否偶然启用了用户命名空间重映射?你是在本机Linux主机上直接使用Docker引擎吗? - David Maze
是的,主机正在本地运行Ubuntu。我最近安装了Linux版的Docker桌面版,我认为这可能会破坏一些配置,但我不知道它是否有关。我阅读了“用户命名空间重新映射”文档,谢谢。我无法确定守护程序是否启用了它,但我尝试在“docker run”上使用“--userns = host”来确保它被禁用,但没有改变任何东西。 - Juan Enrique Muñoz Zolotoochin
我觉得用户命名空间可能仍然在某种程度上发挥作用。你的 /etc/docker/daemon.json 里面有什么?容器进程的 cat /proc/.../uid_map 是否显示除了 0 0 4294967295 之外的任何内容? - bgfvdu3w
1个回答

0

我在安装了Docker Desktop的Ubuntu 22.04下遇到了同样的问题。在卸载Docker Desktop并重新安装Docker Engine后,一切都按照我的期望进行:主机和容器之间挂载目录的所有权保持一致。

这是我的使用情况:我想启动一个Ubuntu 20.04容器,并将其用作应用程序的编译环境。 Dockerfile如下:

FROM ubuntu:20.04
ARG USER=docker
ARG UID=1000
ARG GID=1000

# create a new user with same UID & PID but no password
RUN groupadd --gid ${GID} ${USER} && \
    useradd --create-home ${USER} --uid=${UID} --gid=${GID} --groups root && \
    passwd --delete ${USER}
# add user to the sudo group and set sudo group to no passoword
RUN apt update && \
    apt install -y sudo && \
    adduser ${USER} sudo && \
    echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# prevent tzdata to ask for configuration
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt -y install tzdata
RUN apt install -y build-essential git cmake

# setup default user when enter the container
USER ${UID}:${GID}
WORKDIR /home/${USER}

构建脚本:

#!/bin/bash
set -e
UID=$(id -u)
GID=$(id -g)
docker build --build-arg USER="$USER" \
    --build-arg UID="$UID" \
    --build-arg GID="$GID" \
    --tag "ubuntu-env" \
    --file ./Dockerfile \
    --progress=plain \
    .

由于我将其用作编译环境,整个主目录都被挂载以方便使用:

#!/bin/bash
set -e
docker run -it \
    --name "build-env" \
    --user "${USER}" \
    --workdir "${PWD}" \
    --env TERM=xterm-256color \
    --volume="$HOME":"$HOME" \
    --detach \
    "ubuntu-env" \
    /bin/bash

一些情况下,安装了Docker桌面版后,挂载的主目录的所有者总是root而不是主机用户。在卸载后,挂载的目录现在会在容器中获得预期的所有者,即主机用户。

我将把这个标记为被接受的答案,因为尽管我仍然不完全理解这里发生了什么,但很明显这与安装了Docker桌面版有关。我卸载了Docker桌面版,现在它表现得像预期的那样。谢谢。 - Juan Enrique Muñoz Zolotoochin
很高兴听到它对你有所帮助。除了分享我的经验,我希望我能解释为什么,但是我对音量如何工作的了解非常有限(我倾向于认为这是Docker桌面版的一个错误,因为它在仪表板中的所有设置都看起来无害)。 - tanjor
1
我知道这已经过时了,但我们遇到了同样的问题。以下链接解释了它:https://docs.docker.com/desktop/faqs/linuxfaqs/Linux上的Docker桌面版运行虚拟机(VM),因此在启动时创建并使用自定义的docker上下文桌面-linux。 - veroxii

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