我使用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.
还有其他选择吗?
你们是如何处理这个问题的?
一个非常优雅的解决方案可以在官方的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,否则最新的容器将劫持前一个容器的用户权限。
如果你这样做是为了开发,一个很好的解决方案是使用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是我遇到过的最简单的选择。除了克隆,没有运行成本。
在大多数情况下,这可能不是最好的方法,但它还没有被提及,所以也许它会帮助到某些人。
绑定挂载主机卷
主机文件夹FOOBAR挂载在容器/卷/FOOBAR中
修改容器的启动脚本,以找到感兴趣的卷的GID
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
确保您的用户属于一个具有此GID的组(您可能必须创建一个新组)。对于本例,我将假装我的软件在容器内以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子句一起使用(除非该用户具有根权限)。此外,它是一种黑客工作;-)
如果你想要硬核,你显然可以在许多方面扩展它——例如,搜索任何子文件上的所有组,多个卷,等等。
和你一样,我正在寻找一种将用户/组从主机映射到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->用户名(以及组)匹配。现在,您可以在容器中为服务配置用户/组设置,就像它在您的主机系统上工作一样。
当您决定将容器移动到另一个主机时,您只需要将服务配置文件中的用户名更改为该主机上的用户名。