为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

qq_花开花谢_0 2019-11-21 10:58:36
我已经和Docker玩了一段时间,在处理持久性数据时继续寻找相同的问题。我创建我的文件Dockerfile并公开一个卷,或使用--volumes-from它在容器中安装主机文件夹。我应该对主机上的共享卷应用什么权限?我可以想到两种选择:到目前为止,我已经授予所有人读取/写入访问权限,因此我可以从Docker容器写入该文件夹。将用户从主机映射到容器,以便我可以分配更多的细化权限。不确定这是否可能,但尚未找到很多相关信息。到目前为止,我只能以某些用户身份运行容器:docker run -i -t -user="myuser" postgres,但是该用户的UID与主机不同myuser,因此权限不起作用。另外,我不确定映射用户是否会带来一些安全风险。还有其他选择吗?你们如何处理这个问题?
查看完整描述

3 回答

?
胡说叔叔

TA贡献1804条经验 获得超8个赞

从Docker 1.9.0开始,Docker已命名卷来替换仅数据容器。在我如何思考docker内部的数据的意义上,下面的答案以及我的链接博客文章仍然有价值,但是可以考虑使用命名卷而不是数据容器来实现下面描述的模式。


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


例如,文档中给出的一个用例是备份数据量。为此,另一个容器用于通过进行备份tar,它也用于-volumes-from装载卷。因此,我认为grok的关键点在于:与其考虑如何通过适当的权限访问主机上的数据,不如考虑如何通过另一个容器来执行所需的任何操作(备份,浏览等)。 。容器本身需要使用一致的uid / gids,但它们不需要映射到主机上的任何内容,从而保持可移植性。


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


更新:对于注释中的给定用例,您可能有一个some/graphite运行石墨的图像,以及一个some/graphitedata作为数据容器的图像。因此,忽略端口等,Dockerfile映像some/graphitedata的类似于:


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/graphiteDockerfile也应该得到相同的UID /导报,因此它可能是这个样子:


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 继承some/graphite或some/graphitedata在Dockerfile中进行此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:写完这个答案后,我决定写一篇关于此方法的更完整的博客文章。希望对您有所帮助。


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


查看完整回答
反对 回复 2019-11-21
?
蓝山帝景

TA贡献1843条经验 获得超7个赞

可以在官方Redis图像上以及通常在所有官方图像中看到一个非常优雅的解决方案。


分步介绍:


首先创建Redis用户/组

如Dockerfile注释所示:


首先添加我们的用户和组,以确保一致分配其ID,而不考虑添加了任何依赖项


安装古薮与Dockerfile

gosu是su/ 的替代方案,sudo用于从根用户轻松降级。(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更改为redisuser以运行redis-server。(如果执行的命令不是redis-server,它将直接运行该命令。)


这具有以下效果


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


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


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


查看完整回答
反对 回复 2019-11-21
?
墨色风雨

TA贡献1853条经验 获得超6个赞

可以说这不是大多数情况下的最佳方法,但是尚未提及,因此也许会对某人有所帮助。


绑定挂载主机卷


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的容器内的任意组中没有危险。它不能与USERDockerfile中的子句一起使用(除非我认为该用户具有root特权)。此外,它还大叫黑客工作;-)


如果您想成为铁杆,显然可以通过多种方式扩展它-例如,在任何子文件,多个卷等上搜索所有组。


查看完整回答
反对 回复 2019-11-21
  • 3 回答
  • 0 关注
  • 944 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信