我一直在玩Docker一段时间,并在处理持久数据时继续寻找相同的问题.
创建我Dockerfile和暴露量或使用--volumes-from来安装我的容器内的主文件夹.
我应该对主机上的共享卷应用哪些权限?
我可以想到两个选择:
到目前为止,我已经给了每个人读/写访问权限,所以我可以从Docker容器写入该文件夹.
将用户从主机映射到容器,这样我就可以分配更细化的权限.不确定这是可能的,但没有找到太多关于它.到目前为止,我所能做的就是以某个用户身份运行容器:docker run -i -t -user="myuser" postgres但是此用户的UID与我的主机不同myuser,因此权限不起作用.此外,我不确定映射用户是否会带来一些安全风险.
还有其他选择吗?
你们这些人/女士如何应对这个问题?
Ram*_*man 166
更新2016年3月2日:由于码头工人1.9.0,泊坞窗已命名的体积,其替代数据只集装箱.下面的答案以及我的链接博客文章仍然具有如何考虑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"]
Run Code Online (Sandbox Code Playgroud)
构建并创建数据容器:
docker build -t some/graphitedata Dockerfile
docker run --name graphitedata some/graphitedata
Run Code Online (Sandbox Code Playgroud)
该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"]
Run Code Online (Sandbox Code Playgroud)
它将运行如下:
docker run --volumes-from=graphitedata some/graphite
Run Code Online (Sandbox Code Playgroud)
好的,现在这给了我们石墨容器和相关的仅数据容器以及正确的用户/组(请注意,您也可以重新使用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"]
Run Code Online (Sandbox Code Playgroud)
您可以通过继承Dockerfile some/graphite或some/graphitedata在Dockerfile中创建此DRY ,或者不是创建新映像而只是重用其中一个(根据需要覆盖入口点/ cmd).
现在,您只需运行:
docker run -ti --rm --volumes-from=graphitedata some/graphitetools
Run Code Online (Sandbox Code Playgroud)
然后vi /data/graphite/whatever.txt.这非常有效,因为所有容器都具有相同的石墨用户和匹配的uid/gid.
因为你永远不安装/data/graphite由主机,你不关心如何主机UID/GID映射到UID/GID里面的定义graphite和graphitetools容器.这些容器现在可以部署到任何主机,它们将继续完美地工作.
关于这一点的巧妙之处在于它graphitetools可以具有各种有用的实用程序和脚本,您现在也可以以可移植的方式进行部署.
更新2:写完这个答案之后,我决定写一篇关于这种方法的更完整的博客文章.我希望它有所帮助.
更新3:我更正了这个答案并添加了更多细节.它之前包含一些关于所有权和权限的错误假设 - 所有权通常在卷创建时指定,即在数据容器中,因为这是在创建卷时.看到这个博客.这不是一个要求 - 您可以只使用数据容器作为"引用/句柄",并通过入口点中的chown在另一个容器中设置所有权/权限,以gosu结束以将命令作为正确的用户运行.如果有人对此方法感兴趣,请发表评论,我可以使用此方法提供样本的链接.
小智 48
在官方redis图像上以及所有官方图像中都可以看到非常优雅的解决方案.
逐步说明过程:
如Dockerfile评论所示:
首先添加我们的用户和组,以确保一致地分配他们的ID,无论添加什么依赖项
古薮是的替代su/ sudo从根用户容易降压.(Redis始终与redis用户一起运行)
/data卷并将其设置为workdir通过使用VOLUME /data命令配置/ data卷,我们现在有一个单独的卷,可以是docker卷或绑定挂载到主机目录.
将其配置为workdir(WORKDIR /data)使其成为执行命令的默认目录.
这意味着所有容器执行都将通过docker-entrypoint脚本运行,默认情况下,要运行的命令是redis-server.
docker-entrypoint是一个执行简单功能的脚本:更改当前目录(/ data)的所有权并逐步降低root到redis用户运行redis-server.(如果执行的命令不是redis-server,它将直接运行命令.)
这具有以下效果
如果将/ data目录绑定到主机,则docker-entrypoint将在用户下运行redis-server之前准备用户权限redis.
这使您可以轻松地设置零设置,以便在任何卷配置下运行容器.
当然,如果您需要在不同映像之间共享卷,则需要确保它们使用相同的userid/groupid,否则最新容器将劫持前一个容器的用户权限.
Ham*_*amy 29
对于大多数情况来说,这可能不是最好的方式,但它还没有被提及,所以它可能对某人有所帮助.
绑定装载主机卷
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
Run Code Online (Sandbox Code Playgroud)
我喜欢这个,因为我可以轻松修改主机卷上的组权限,并知道这些更新的权限适用于docker容器.没有对我的主机文件夹/文件的任何许可或所有权修改就会发生这种情况,这让我很开心.
我不喜欢这个,因为它假设将自己添加到容器内的任意组中没有危险,这些组恰好使用了您想要的GID.它不能与USERDockerfile中的子句一起使用(除非该用户具有我认为的root权限).此外,它尖叫黑客工作;-)
如果你想成为硬核,你显然可以通过多种方式扩展它 - 例如搜索任何子文件,多个卷等的所有组.
Leo*_*cci 15
好的,现在正在码头问题#7198上进行跟踪
现在,我正在使用你的第二个选项处理这个问题:
将用户从主机映射到容器
#=======
# 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)
Run Code Online (Sandbox Code Playgroud)
# DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000
docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest
Run Code Online (Sandbox Code Playgroud)
FDi*_*isk 14
尝试向Dockerfile添加命令
RUN usermod -u 1000 www-data
Run Code Online (Sandbox Code Playgroud)
积分转到https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
和你一样,我一直在寻找一种方法将用户/组从主机映射到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
.....
Run Code Online (Sandbox Code Playgroud)
这是我的docker-compose.yml的摘录.
这个想法是从主机到容器挂载(以只读模式)用户/组列表,因此在容器启动后它将具有与主机相同的uid->用户名(以及用于组)匹配.现在,您可以在容器内配置服务的用户/组设置,就像它在主机系统上工作一样.
当您决定将容器移动到另一台主机时,您只需将服务配置文件中的用户名更改为该主机上的用户名即可.
为了保护和更改 docker 容器的根,docker 主机尝试使用--uidmap和--private-uids选项
https://github.com/docker/docker/pull/4572#issuecomment-38400893
--cap-drop为了安全起见,您也可以删除docker 容器中的几个功能()
http://opensource.com/business/14/9/security-for-docker
更新支持应该进来docker > 1.7.0
更新版本1.10.0(2016-02-04) 添加--userns-remap标志
https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2
这里的方法仍然使用仅数据容器,但不要求它与应用程序容器同步(具有相同的uid/gid).
据推测,您希望在容器中运行某个应用程序作为非root $ USER而不使用登录shell.
在Dockerfile中:
RUN useradd -s /bin/false myuser
# Set environment variables
ENV VOLUME_ROOT /data
ENV USER myuser
...
ENTRYPOINT ["./entrypoint.sh"]
Run Code Online (Sandbox Code Playgroud)
然后,在entrypoint.sh中:
chown -R $USER:$USER $VOLUME_ROOT
su -s /bin/bash - $USER -c "cd $repo/build; $@"
Run Code Online (Sandbox Code Playgroud)
我的做法是检测当前的UID/GID,然后在容器内创建这样的用户/组并在他下执行脚本。结果,他将创建的所有文件都将匹配主机上的用户:
# get the location of this script no matter what your current folder is, this might break between shells so make sure you run bash
LOCAL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# get current IDs
USER_ID=$(id -u)
GROUP_ID=$(id -g)
echo "Mount $LOCAL_DIR into docker, and match the host IDs ($USER_ID:$GROUP_ID) inside the container."
docker run -v $LOCAL_DIR:/host_mount -i debian:9.4-slim bash -c "set -euo pipefail && groupadd -r -g $GROUP_ID lowprivgroup && useradd -u $USER_ID lowprivuser -g $GROUP_ID && cd /host_mount && su -c ./runMyScriptAsRegularUser.sh lowprivuser"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
226464 次 |
| 最近记录: |