我使用Docker已经有一段时间了,在处理持久数据时不断发现同样的问题。

我创建Dockerfile并公开一个卷或使用——volumes-from在容器中挂载一个主机文件夹。

主机上的共享卷需要申请哪些权限?

我可以想到两个选择:

So far I've given everyone read/write access, so I can write to the folder from the Docker container. Map the users from host into the container, so I can assign more granular permissions. Not sure this is possible though and haven't found much about it. So far, all I can do is run the container as some user: docker run -i -t -user="myuser" postgres, but this user has a different UID than my host myuser, so permissions do not work. Also, I'm unsure if mapping the users will pose some security risks.

还有其他选择吗?

你们是如何处理这个问题的?


当前回答

这里有一种方法,它仍然使用纯数据容器,但不要求它与应用程序容器同步(就具有相同的uid/gid而言)。

假设,你想在容器中运行一些应用程序作为非根$USER没有登录shell。

在Dockerfile中:

RUN useradd -s /bin/false myuser

# Set environment variables
ENV VOLUME_ROOT /data
ENV USER myuser

...

ENTRYPOINT ["./entrypoint.sh"]

然后,在entrypoint.sh中:

chown -R $USER:$USER $VOLUME_ROOT
su -s /bin/bash - $USER -c "cd $repo/build; $@"

其他回答

这里有一种方法,它仍然使用纯数据容器,但不要求它与应用程序容器同步(就具有相同的uid/gid而言)。

假设,你想在容器中运行一些应用程序作为非根$USER没有登录shell。

在Dockerfile中:

RUN useradd -s /bin/false myuser

# Set environment variables
ENV VOLUME_ROOT /data
ENV USER myuser

...

ENTRYPOINT ["./entrypoint.sh"]

然后,在entrypoint.sh中:

chown -R $USER:$USER $VOLUME_ROOT
su -s /bin/bash - $USER -c "cd $repo/build; $@"

好的,这现在被跟踪在docker问题#7198

现在,我用你的第二个选择来处理这个问题:

将用户从主机映射到容器

Dockerfile

#=======
# Users
#=======
# TODO: Idk how to fix hardcoding uid & gid, specifics to docker host machine
RUN (adduser --system --uid=1000 --gid=1000 \
        --home /home/myguestuser --shell /bin/bash myguestuser)

CLI

# DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000
docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest

我目前更倾向于哈米的回答

In my specific case, I was trying to build my node package with the node docker image so that I wouldn't have to install npm on the deployment server. It worked well until, outside out the container and on the host machine, I tried to move a file into the node_modules directory that the node docker image had created, to which I was denied permissions because it was owned by root. I realized that I could work around this by copying the directory out of the container onto the host machine. Via docker docs...

的UID:GID创建复制到本地计算机的文件 调用docker cp命令的用户。

这是我用来更改docker容器中创建的目录的所有权的bash代码。

NODE_IMAGE=node_builder
docker run -v $(pwd)/build:/build -w="/build" --name $NODE_IMAGE node:6-slim npm i --production
# node_modules is owned by root, so we need to copy it out 
docker cp $NODE_IMAGE:/build/node_modules build/lambda 
# you might have issues trying to remove the directory "node_modules" within the shared volume "build", because it is owned by root, so remove the image and its volumes
docker rm -vf $NODE_IMAGE || true

如果需要,您可以使用第二个docker容器删除该目录。

docker run -v $(pwd)/build:/build -w="/build" --name $RMR_IMAGE node:6-slim rm -r node_modules

一个非常优雅的解决方案可以在官方的redis图像和一般的所有官方图像中看到。

详细描述:

首先创建redis用户/组

如Dockerfile评论所示:

首先添加我们的用户和组,以确保他们的id被一致分配,不管添加什么依赖项

使用Dockerfile安装gosu

Gosu是su / sudo的替代品,便于从根用户降级。(Redis总是与Redis用户一起运行)

配置/data卷,设置为workdir

通过使用volume /data命令配置/data卷,我们现在有了一个单独的卷,它可以是docker卷,也可以绑定挂载到主机目录。

将其配置为工作目录(workdir /data)将使其成为执行命令的默认目录。

添加docker-entrypoint文件,并将其设置为ENTRYPOINT,默认CMD redis-server

这意味着所有容器的执行都将通过docker-entrypoint脚本运行,默认情况下要运行的命令是redis-server。

docker-entrypoint是一个脚本,它做了一个简单的功能:改变当前目录(/data)的所有权,并从根用户降级到redis用户以运行redis-server。(如果执行的命令不是redis-server,则直接执行该命令。)

这有以下影响

如果/data目录被绑定挂载到主机上,docker-entrypoint将在redis用户下运行redis-server之前准备用户权限。

这使您可以轻松地在任何卷配置下运行容器,无需进行任何设置。

当然,如果您需要在不同映像之间共享卷,则需要确保它们使用相同的userid/groupid,否则最新的容器将劫持前一个容器的用户权限。

如果你使用Docker Compose,以特权模式启动容器:

wordpress:
    image: wordpress:4.5.3
    restart: always
    ports:
      - 8084:80
    privileged: true