我一直在玩Docker一段时间,并在处理持久数据时继续寻找相同的问题 .
我创建 Dockerfile
和expose a volume或使用 --volumes-from
到mount a host folder inside my container .
我应该对主机上的共享卷应用哪些权限?
我可以想到两个选择:
-
到目前为止,我已经为每个人提供了读/写访问权限,因此我可以从Docker容器中写入该文件夹 .
-
将用户从主机映射到容器,这样我就可以分配更细化的权限 . 不确定这是否可行,但没有找到太多相关信息 . 到目前为止,我所能做的就是以某个用户身份运行容器:
docker run -i -t -user="myuser" postgres
,但此用户的UID与我的主机myuser
不同,因此权限不起作用 . 此外,我不确定映射用户是否会带来一些安全风险 .
还有其他选择吗?
你们这些人/女士如何处理这个问题?
13 回答
和你一样,我一直在寻找一种方法将用户/组从主机映射到docker容器,这是我迄今为止找到的最短路径:
这是我的docker-compose.yml的摘录 .
这个想法是从主机到容器挂载(以只读模式)用户/组列表,因此在容器启动后它将具有与主机相同的uid->用户名(以及组)匹配 . 现在,您可以在容器内配置服务的用户/组设置,就像它在主机系统上工作一样 .
当您决定将容器移动到另一个主机时,您只需将服务配置文件中的用户名更改为该主机上的用户名 .
这是一种仍然使用仅数据容器的方法,但不要求它与应用程序容器同步(就具有相同的uid / gid而言) .
据推测,您希望在容器中运行某个应用程序作为非root $ USER而不使用登录shell .
在Dockerfile中:
然后,在entrypoint.sh中:
To share folder between docker host and docker container, try below command
-v标志将当前工作目录挂载到容器中 . 当装入装入卷的主机目录不存在时,Docker会自动为您在主机上创建此目录,
但是,这里有两个问题:
如果您是 non-root user ,则无法写入已装入的卷,因为共享文件将归主机中的其他用户所有,
你不应该与笔记本电脑上的用户/ Jenkins相匹配,
Solution:
容器:创建用户说'testuser',默认情况下用户ID将从1000开始,
主持人:创建一个组名为'testgroup',组ID为1000,并将目录chown到新组(testgroup)
如果您使用Docker Compose,请以previleged模式启动容器:
我的方法是检测当前的UID / GID然后在容器内创建这样的用户/组并执行他下面的脚本,因此他将创建的所有文件将与运行脚本的用户匹配:
好的,现在正在tracked at docker issue #7198
现在,我正在使用您的第二个选项来解决这个问题:
Dockerfile
CLI
UPDATE 我目前更倾向于Hamy answer
对于大多数情况来说,这可能不是最好的方式,但它还没有被提及,所以它可能对某人有所帮助 .
Host folder FOOBAR is mounted in container /volume/FOOBAR
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
nobody
用户,所以我想确保nobody
属于组ID等于TARGET_GID
的组我喜欢这个,因为我可以轻松修改主机卷上的组权限,并知道这些更新的权限适用于docker容器 . 没有对我的主机文件夹/文件的任何许可或所有权修改就会发生这种情况,这让我很开心 .
我没有把自己添加到容器内的任意组中,而这些组恰好正在使用您想要的GID . 它不能与Dockerfile中的
USER
子句一起使用(除非该用户具有我认为的root权限) . 此外,它尖叫黑客工作;-)如果你想成为硬核,你显然可以通过多种方式扩展它 - 例如搜索任何子文件,多个卷等的所有组 .
为了安全和更改docker容器的root,docker主机尝试使用
--uidmap
和--private-uids
选项https://github.com/docker/docker/pull/4572#issuecomment-38400893
此外,您可以删除docker容器中的多个功能(
--cap-drop
)以确保安全性http://opensource.com/business/14/9/security-for-docker
UPDATE 支持应该在
docker > 1.7.0
UPDATE Version
1.10.0
(2016-02-04)添加--userns-remap
flag https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2基本图像
使用此图片:https://hub.docker.com/r/reduardo7/docker-host-user
或
重要提示: this destroys container portability across hosts .
1)init.sh
2)Dockerfile
3)run.sh
4)用docker构建
4)跑!
一个非常优雅的解决方案可以在官方redis image上看到,一般在所有官方图片中都可以看到 .
逐步说明过程:
如Dockerfile评论所示:
gosu是
su
/sudo
的替代品,可以从root用户轻松降级 . (Redis始终使用redis
用户运行)/data
卷并将其设置为workdir通过使用
VOLUME /data
命令配置/ data卷,我们现在有一个单独的卷,可以是docker卷,也可以绑定挂载到主机目录 .将其配置为workdir(
WORKDIR /data
)使其成为执行命令的默认目录 .这意味着所有容器执行都将通过docker-entrypoint脚本运行,默认情况下,要运行的命令是redis-server .
docker-entrypoint
是一个执行简单功能的脚本:更改当前目录(/ data)的所有权,并从root
降级为redis
用户以运行redis-server
. (如果执行的命令不是redis-server,它将直接运行命令 . )This has the following effect
如果/ data目录绑定到主机,则docker-entrypoint将在
redis
user下运行redis-server之前准备用户权限 .这使您可以轻松地设置零设置,以便在任何卷配置下运行容器 .
当然,如果您需要在不同映像之间共享卷,则需要确保它们使用相同的userid / groupid,否则最新容器将劫持前一个容器的用户权限 .
尝试向Dockerfile添加命令
积分去https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
在我的具体情况下,我试图用节点docker镜像构建我的节点包,这样我就不必在部署服务器上安装npm了 . 它运行良好,直到容器外部和主机上,我试图将文件移动到节点docker映像创建的node_modules目录中,因为它归root所有,我被拒绝了 . 我意识到我可以通过将容器中的目录复制到主机上来解决这个问题 . 通过docker docs ...
这是我用来更改由docker容器创建的目录的所有权的bash代码 .
如果需要,可以使用第二个docker容器删除该目录 .
UPDATE 2016-03-02 :从Docker 1.9.0开始,Docker的named volumes为replace data-only containers . 下面的答案,以及我链接的博客文章,仍然具有如何考虑docker内部数据的意义,但考虑使用命名卷来实现下面描述的模式而不是数据容器 .
我相信解决这个问题的规范方法是使用data-only containers . 使用这种方法,所有对卷数据的访问都是通过使用
-volumes-from
数据容器的容器进行的,因此主机uid / gid无关紧要 .例如,文档中给出的一个用例是备份数据卷 . 为此,使用另一个容器通过
tar
进行备份,并且它也使用-volumes-from
来安装卷 . 所以我认为grok的关键点在于:不要考虑如何使用适当的权限访问主机上的数据,而是考虑如何通过另一个容器执行任何操作(备份,浏览等) . . 容器本身需要使用一致的uid / gids,但它们不需要映射到主机上的任何东西,从而保持可移植性 .这对我来说也是相对较新的,但如果您有特定用例,请随时发表评论,我会尝试扩展答案 .
UPDATE :对于注释中的给定用例,您可能有一个运行graphite的图像
some/graphite
和一个图像some/graphitedata
作为数据容器 . 所以,忽略端口等,Dockerfile
的图像some/graphitedata
是这样的:构建并创建数据容器:
some/graphite
Dockerfile也应该获得相同的uid / gids,因此它可能看起来像这样:它将运行如下:
好的,现在这给了我们石墨容器和相关的仅数据容器以及正确的用户/组(注意你也可以重新使用
some/graphite
容器作为数据容器,在运行它时覆盖入口/ cmd,但是有它们作为单独的图像,IMO更清晰) .现在,假设您要编辑数据文件夹中的某些内容 . 因此,而不是绑定安装卷主机并在那里编辑它,创建一个新容器来完成这项工作 . 让我们称之为
some/graphitetools
. 让我们也创建适当的用户/组,就像some/graphite
图像一样 .您可以通过继承Dockerfile中的
some/graphite
或some/graphitedata
来创建此DRY,或者不是创建新映像而只是重用其中一个(根据需要覆盖入口点/ cmd) .现在,您只需运行:
然后
vi /data/graphite/whatever.txt
. 这非常有效,因为所有容器都具有相同的石墨用户和匹配的uid / gid .由于您从不从主机挂载
/data/graphite
,因此您无需关心主机uid / gid如何映射到graphite
和graphitetools
容器内定义的uid / gid . 这些容器现在可以部署到任何主机,它们将继续完美地工作 .关于这一点的好处是
graphitetools
可以拥有各种有用的实用程序和脚本,您现在也可以以可移植的方式部署 .UPDATE 2 :写完这个答案之后,我决定写一个关于这个方法的more complete blog post . 我希望它有所帮助 .
UPDATE 3 :我更正了这个答案并添加了更多细节 . 它之前包含一些关于所有权和权限的错误假设 - 所有权通常在卷创建时分配,即在数据容器中分配,因为这是在创建卷时 . 见this blog . 这不是一个要求 - 您可以将数据容器用作"reference/handle",并通过入口点中的chown将所有权/ perms设置在另一个容器中,该入口点以gosu结束以将命令作为正确的用户运行 . 如果有人对此方法感兴趣,请发表评论,我可以使用此方法提供样本的链接 .