管理Docker共享卷权限的(最佳)方式是什么?

我一直在玩docker一段时间,并在处理持久数据时继续发现同样的问题。

我创建了Dockerfile并公开了卷,或者使用--volumes-from在我的容器中安装主机文件夹

我的问题是,我应该对主机上的共享卷应用什么权限? 我可以想到2个选项:

  • 到目前为止,我一直在做的是,给每个人读/写权限,以便我可以从码头容器中写入文件夹

  • 将主机中的用户映射到容器中,以便我可以分配更细化的权限。 不知道这是可能的,但没有发现太多。 到目前为止,我所能做的就是以某个用户的身份运行容器: docker run -i -t -user="myuser" postgres ,但该用户与我的主机myuser具有不同的UID,因此权限不起作用。 另外,我不确定映射用户是否会带来一些安全风险。

  • 任何其他的选择?

    你们怎么处理这个问题?


    更新2016-03-02 :从Docker 1.9.0开始,Docker已经命名了可替换纯数据容器的卷。 下面的答案以及我的链接的博客帖子,仍然具有如何考虑Docker中的数据的意义,但考虑使用命名卷来实现下面描述的模式,而不是数据容器。


    我相信解决这个问题的标准方法是使用纯数据容器。 采用这种方法,所有对卷数据的访问都是通过使用-volumes-from数据容器的-volumes-from容器进行的,因此主机uid / gid无关紧要。

    例如,文档中给出的一个用例是备份数据卷。 为此,另一个容器用于通过tar进行备份,并且它也使用-volumes-from来装入卷。 所以我认为grok的关键点是:不要考虑如何以适当的权限访问主机上的数据,而是考虑如何做到你需要的任何事情 - 备份,浏览等 - 通过另一个容器。 容器本身需要使用一致的uid / gid,但它们不需要映射到主机上的任何东西,从而保持便携。

    这对我来说也是比较新的,但是如果你有一个特定的用例可以随意发表评论,我会试着扩展答案。

    更新 :对于评论中的给定用例,您可能会有some/graphite图像用于运行石墨,以及some/graphitedata图像用作数据容器。 所以,忽略端口等,image some/graphitedataDockerfile就像这样:

    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容器作为数据容器,在运行时覆盖入口/ 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中继承some/graphite或者some/graphitedata来做到这一点,或者不用创建一个新的镜像,而是重新使用现有的镜像(根据需要重写入口点/ cmd)。

    现在,你只需运行:

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

    然后vi /data/graphite/whatever.txt 。 这完美地工作,因为所有的容器都有相同的石墨用户与uid / gid匹配。

    由于您从不从主机安装/data/graphite ,因此您不必关心主机uid / gid如何映射到graphitegraphitetools容器中定义的uid / gid。 这些容器现在可以部署到任何主机,并且它们将继续完美工作。

    关于这一点很简单,就是graphitetools可以有各种有用的实用程序和脚本,现在您也可以以便携的方式进行部署。

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

    更新3 :我更正了这个答案并添加了更多细节。 它之前包含了关于所有权和权限的一些不正确的假设 - 所有权通常是在创建卷时(即在数据容器中)分配的,因为这是创建卷时的情况。 看到这个博客。 但这不是必需的 - 您可以将数据容器用作“引用/句柄”,并通过chown在入口点中将另一个容器中的所有权/权限设置为gosu,以便以正确的用户身份运行该命令。 如果有人对此方法感兴趣,请发表评论,我可以提供使用此方法的示例链接。


    官方redis映像和所有官方映像中都可以看到非常优雅的解决方案。

    逐步描述过程描述:

  • 在其他任何事情之前创建redis用户/组
  • 正如在Dockerfile中所看到的那样:

    首先添加我们的用户和组,以确保其ID一致地分配,而不管添加的任何依赖关系如何

  • 用Dockerfile安装gosu
  • gosu是su / sudo的另一种选择,可以轻松从root用户降级。 (Redis总是使用redis用户运行)

  • 配置/data卷并将其设置为workdir
  • 通过使用VOLUME /data命令配置/ data卷,我们现在有一个单独的卷,可以是docker卷或绑定安装到主机目录。

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

  • 添加docker-entrypoint文件并将其设置为带默认CMD redis-server的ENTRYPOINT
  • 这意味着所有容器执行都将通过docker-entrypoint脚本运行,默认情况下要运行的命令是redis-server。

    docker-entrypoint是一个执行简单功能的脚本:更改当前目录(/ data)的所有权,并从root用户redis-server更改为redis用户,以运行redis-server 。 (如果执行的命令不是redis-server,它将直接运行该命令。)

    这具有以下效果

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

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

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


    这可能不是大多数情况下最好的方式,但它尚未提及,所以它可能会帮助某人。

  • 绑定安装主机卷

    Host folder FOOBAR is mounted in container /volume/FOOBAR

  • 修改您的容器的启动脚本以查找您感兴趣的卷的GID

    $ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)

  • 确保您的用户属于使用此GID的组(您可能必须创建一个新组)。 在这个例子中,我假装我的软件在容器内部作为nobody用户运行,所以我想确保nobody属于组ID等于TARGET_GID的组

  •   EXISTS=$(cat /etc/group | grep $TARGET_GID | wc -l)
    
      # Create new group using target GID and add nobody user
      if [ $EXISTS == "0" ]; then
        groupadd -g $TARGET_GID tempgroup
        usermod -a -G tempgroup nobody
      else
        # GID exists, find group name and add
        GROUP=$(getent group $TARGET_GID | cut -d: -f1)
        usermod -a -G $GROUP nobody
      fi
    

    我喜欢这一点,因为我可以轻松修改主机卷上的组权限,并知道这些更新权限适用于Docker容器内部。 这发生在没有任何许可或所有权修改我的主机文件夹/文件,这让我很开心。

    我不喜欢这样做,因为它假设将自己添加到恰巧使用所需GID的容器内的任意组是没有任何危险的。 它不能与Dockerfile中的USER子句一起使用(除非该用户具有我认为的root权限)。 另外,它尖叫黑客的工作;-)

    如果你想硬核,你可以用很多方式来扩展它 - 例如搜索任何子文件,多卷等的所有组。

    链接地址: http://www.djcxy.com/p/18243.html

    上一篇: What is the (best) way to manage permissions for docker shared volumes

    下一篇: How can I delete Docker's images?