我使用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.

还有其他选择吗?

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


当前回答

要在docker主机和docker容器之间共享文件夹,请尝试以下命令

$(pwd):$(pwd)-i -t ubuntu

-v标志将当前工作目录挂载到容器中。当绑定挂载卷的主机目录不存在时,Docker会自动在主机上为你创建这个目录,

然而,这里有两个问题:

如果您不是root用户,则无法对挂载的卷进行写操作,因为共享文件将由主机中的其他用户拥有。 你不应该以root用户在容器中运行进程,但即使你以硬编码用户运行,它仍然不会与你笔记本电脑上的用户匹配。

解决方案:

容器: 创建一个用户testuser,默认用户id从1000开始,

主持人: 创建一个名为“testgroup”的组,组id为1000,并将目录更改为新组(testgroup . testgroup . testgroup)

其他回答

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

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

好的,这现在被跟踪在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

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

和你一样,我正在寻找一种将用户/组从主机映射到docker容器的方法,这是迄今为止我发现的最短的方法:

  version: "3"
  services:
    my-service:
      .....
      volumes:
        # take uid/gid lists from host
        - /etc/passwd:/etc/passwd:ro
        - /etc/group:/etc/group:ro
        # mount config folder
        - path-to-my-configs/my-service:/etc/my-service:ro
        .....

这是从docker-compose.yml中提取的。

其思想是(以只读模式)将用户/组列表从主机挂载到容器,这样容器启动后,它将具有与主机相同的uid->用户名(以及组)匹配。现在,您可以在容器中为服务配置用户/组设置,就像它在您的主机系统上工作一样。

当您决定将容器移动到另一个主机时,您只需要将服务配置文件中的用户名更改为该主机上的用户名。

如果你这样做是为了开发,一个很好的解决方案是使用bindfs:

保持容器用户拥有源代码。(如果可能的话,让容器克隆源代码。) 使用bindfs并为主机用户映射文件夹。

下面是我的docker-compose设置现在的样子:

project:
  web/src # Container clones it using init scripts.
  web/log
  __web__/src # Host user uses this. It's just bindfs mirror.
  __web__/log

我已经考虑这个问题一年多了,bindfs是我遇到过的最简单的选择。除了克隆,没有运行成本。

更新2016-03-02:从Docker 1.9.0开始,Docker已经命名了卷来取代数据容器。下面的答案,以及我链接的博客文章,在如何思考docker内部的数据方面仍然有价值,但考虑使用命名卷来实现下面描述的模式,而不是数据容器。


我认为解决这个问题的规范方法是使用仅数据容器。使用这种方法,对卷数据的所有访问都是通过使用数据容器中的-volumes-的容器进行的,因此主机uid/gid无关紧要。

For example, one use case given in the documentation is backing up a data volume. To do this another container is used to do the backup via tar, and it too uses -volumes-from in order to mount the volume. So I think the key point to grok is: rather than thinking about how to get access to the data on the host with the proper permissions, think about how to do whatever you need -- backups, browsing, etc. -- via another container. The containers themselves need to use consistent uid/gids, but they don't need to map to anything on the host, thereby remaining portable.

这对我来说也相对较新,但如果您有特定的用例,请随意评论,我将尝试扩展答案。

更新:对于注释中的给定用例,您可能有一个image some/graphite来运行graphite,并有一个image some/graphitedata作为数据容器。因此,忽略端口等,image some/graphitedata的Dockerfile是这样的:

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
RUN mkdir -p /data/graphite \
  && chown -R graphite:graphite /data/graphite
VOLUME /data/graphite
USER graphite
CMD ["echo", "Data container for graphite"]

构建并创建数据容器:

docker build -t some/graphitedata Dockerfile
docker run --name graphitedata some/graphitedata

some/graphite Dockerfile也应该得到相同的uid/gid,因此它可能看起来像这样:

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
# ... graphite installation ...
VOLUME /data/graphite
USER graphite
CMD ["/bin/graphite"]

它的运行方式如下:

docker run --volumes-from=graphitedata some/graphite

好了,现在我们得到了石墨容器和与正确的用户/组相关联的数据容器(注意,您也可以为数据容器重用some/graphite容器,在运行时覆盖entrypoing/cmd,但将它们作为单独的图像IMO更清楚)。

现在,假设您想要编辑数据文件夹中的内容。因此,与其将卷绑定挂载到主机并在那里编辑它,不如创建一个新容器来完成这项工作。我们叫它some/graphitetools。我们还可以创建适当的用户/组,就像some/graphite图像一样。

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
VOLUME /data/graphite
USER graphite
CMD ["/bin/bash"]

你可以通过继承Dockerfile中的一些/graphite或一些/ graphitdata使其成为DRY,或者只是重用现有的一个映像(必要时重写entrypoint/cmd)而不是创建一个新的映像。

现在,你只需运行:

docker run -ti --rm --volumes-from=graphitedata some/graphitetools

然后是vi /data/graphite/whatever。txt。这可以很好地工作,因为所有容器都有相同的石墨用户和匹配的uid/gid。

因为从来没有从主机挂载/data/graphite,所以不关心主机uid/gid如何映射到graphite和graphitetools容器中定义的uid/gid。这些容器现在可以部署到任何主机上,并且它们将继续完美地工作。

这样做的好处是,graphitetools可以有各种有用的实用程序和脚本,现在您还可以以可移植的方式部署它们。

更新2:写完这个答案后,我决定写一篇关于这种方法的更完整的博客文章。我希望这能有所帮助。

UPDATE 3: I corrected this answer and added more specifics. It previously contained some incorrect assumptions about ownership and perms -- the ownership is usually assigned at volume creation time i.e. in the data container, because that is when the volume is created. See this blog. This is not a requirement though -- you can just use the data container as a "reference/handle" and set the ownership/perms in another container via chown in an entrypoint, which ends with gosu to run the command as the correct user. If anyone is interested in this approach, please comment and I can provide links to a sample using this approach.