What is the (best) way to manage permissions for Docker shared volumes?
我和Docker一起玩了一段时间,在处理持久性数据时一直在寻找相同的问题。
我创建了我的
我应该对主机上的共享卷应用哪些权限?
我可以想到两种选择:
到目前为止,我已经为每个人提供了读/写权限,所以我可以从Docker容器中写入文件夹。
将用户从主机映射到容器中,这样我可以分配更精细的权限。但不确定这是可能的,而且还没有找到太多关于它的信息。到目前为止,我所能做的就是以某个用户的身份运行容器:
docker run -i -t -user="myuser" postgres ,但是这个用户的uid与我的主机myuser 不同,所以权限不起作用。另外,我不确定映射用户是否会带来一些安全风险。
还有其他选择吗?
你们如何处理这个问题?
更新:作为2016年- 03 - 0 docker 1.9.0 docker已命名的,其中只有容器取代-卷的数据。回答下面的链接,以及我的博客后,仍然具有价值意义的在想关于数据如何在docker则认为大但使用命名的模式描述implement卷下面而不是煤的数据容器。
我相信这是典型的由大的求解方法-只使用数据的容器。所有与本卷的方法,获得的数据通过使用的数据的容器,容器内
例如,在一个给定的用例文档是一个backing卷上的数据。本文的另一大原因是以前做的backup集装箱通过
这是比较新的,但如果你为我以及用例有一个特别的感觉自由的评论,我会尝试对expand回答。
更新:为给定的用例在评论,你可能有个大graphite
1 2 3 4 5 6 7 8 9 | 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"] |
建立和创建的数据容器:
1 2 | docker build -t some/graphitedata Dockerfile docker run --name graphitedata some/graphitedata |
的
1 2 3 4 5 6 7 8 | 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"] |
和它会运行如下:
1 | docker run --volumes-from=graphitedata some/graphite |
好吧,现在,我们给出了相关的数据和我们的graphite集装箱货柜的correct -只有与用户/组(注意,你可以重新使用的数据为
现在,你说你想让folder在编辑数据。而煤的体积比较大bind mounting寄主和编辑它那里,创造了一个新的容器做工作。
1 2 3 4 5 6 7 | 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"] |
你能使这干燥由inheriting从
现在,你当然发抖:
1 | docker run -ti --rm --volumes-from=graphitedata some/graphitetools |
然后
因为你永远不
关于这件事的neat是
更新2:写作这个回答后,我决定写一个更大的完整的博客后,关于这种方法。我希望它helps。
更新3:我和添加更多的specifics纠正这个答案。这其中的一些不正确的assumptions以前关于ownership和perms——通常是在卷的ownership assigned创造时间即在集装箱的数据,因为这是当是创建的卷。看到这个博客。这是不是一个requirement虽然只是——你可以使用集装箱作为一个"参考的数据集的ownership /处理/ perms"和在另一个集装箱安全通过chown在entrypoint两端与gosu颤抖,其中大correct作为用户的命令。如果任何人有兴趣在这个方法是评论,请和我可以提供一个链接到样本的使用这种方法。
一个非常优雅的解决方案可以在官方的redis图像上看到,通常在所有的官方图像中都可以看到。
在逐步过程中描述:
- 创建redis用户/组之前
如Dockerfile评论所示:
add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
- 用dockerfile安装gosu
gosu是
- 配置
/data 卷,设置为workdir
通过使用
将其配置为workdir(
- 添加docker entrypoint文件,并使用默认的cmd redis server将其设置为entrypoint
这意味着所有容器执行都将通过docker entrypoint脚本运行,默认情况下,要运行的命令是redis server。
这有以下效果
如果/data目录绑定到主机,docker入口点将在
这让您可以轻松地记住,为了在任何卷配置下运行容器,都有零设置。
当然,如果您需要在不同的映像之间共享卷,您需要确保它们使用相同的userid/groupid,否则最新的容器将劫持前一个映像的用户权限。
在大多数情况下,这可能不是最好的方法,但还没有被提及,所以它可能会帮助一些人。
绑定装载主机卷
修改容器的启动脚本以查找您感兴趣的卷的gid
确保您的用户属于具有此gid的组(您可能需要创建一个新组)。在这个例子中,我将假装我的软件在容器中以
1 2 3 4 5 6 7 8 9 10 11 | 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中的
如果你想成为硬核,你可以通过很多方式来扩展它——例如搜索任何子文件、多个卷等上的所有组。
好的,现在在Docker发行版上进行跟踪7198
现在,我用你的第二个选择来处理这个问题:
Map the users from host into the container
文档文件
1 2 3 4 5 6 | #======= # 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) |
CLI
1 2 | # DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000 docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest |
更新我现在更倾向于哈米的回答
尝试向dockerfile添加命令
1 | RUN usermod -u 1000 www-data |
学分转到https://github.com/denderello/symfony docker example/issues/2 issuecomment-94387272
和你一样,我也在寻找一种方法将用户/组从主机映射到Docker容器,这是迄今为止我发现的最短的方法:
1 2 3 4 5 6 7 8 9 10 11 | 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->username(以及对于组)匹配。现在,您可以在容器内为服务配置用户/组设置,就像它在主机系统上工作一样。
当您决定将容器移动到另一个主机时,只需将服务配置文件中的用户名更改为该主机上的用户名。
这里的方法仍然使用一个只包含数据的容器,但不要求它与应用程序容器同步(就拥有相同的uid/gid而言)。
大概,您希望以非根$用户身份运行容器中的某些应用程序,而不使用登录shell。
在Dockerfile中:
1 2 3 4 5 6 7 8 9 | RUN useradd -s /bin/false myuser # Set environment variables ENV VOLUME_ROOT /data ENV USER myuser ... ENTRYPOINT ["./entrypoint.sh"] |
然后,在entrypoint.sh中:
1 2 | chown -R $USER:$USER $VOLUME_ROOT su -s /bin/bash - $USER -c"cd $repo/build; $@" |
要安全并更改docker容器的根目录,请尝试使用
https://github.com/docker/docker/pull/4572问题注释-38400893
此外,为了安全起见,您还可以删除Docker容器中的一些功能(
http://opensource.com/business/14/9/security-for-docker
更新支持应该在
更新版本
基础图像
使用此图片:https://hub.docker.com/r/reduardo7/docker-host-user
或重要提示:这会破坏跨主机的容器可移植性。
1)江户十一〔0]1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash if ! getent passwd $DOCKDEV_USER_NAME > /dev/null then echo"Creating user $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME" groupadd --gid $DOCKDEV_GROUP_ID -r $DOCKDEV_GROUP_NAME useradd --system --uid=$DOCKDEV_USER_ID --gid=$DOCKDEV_GROUP_ID \ --home-dir /home --password $DOCKDEV_USER_NAME $DOCKDEV_USER_NAME usermod -a -G sudo $DOCKDEV_USER_NAME chown -R $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME /home fi sudo -u $DOCKDEV_USER_NAME bash |
2)江户十一〔1〕号
1 2 3 4 5 6 7 | FROM ubuntu:latest # Volumes VOLUME ["/home/data"] # Copy Files COPY /home/data/init.sh /home # Init RUN chmod a+x /home/init.sh |
3)Run.SH
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/bin/bash DOCKDEV_VARIABLES=(\ DOCKDEV_USER_NAME=$USERNAME\ DOCKDEV_USER_ID=$UID\ DOCKDEV_GROUP_NAME=$(id -g -n $USERNAME)\ DOCKDEV_GROUP_ID=$(id -g $USERNAME)\ ) cmd="docker run" if [ ! -z"${DOCKDEV_VARIABLES}" ]; then for v in ${DOCKDEV_VARIABLES[@]}; do cmd="${cmd} -e ${v}" done fi # /home/usr/data contains init.sh $cmd -v /home/usr/data:/home/data -i -t my-image /home/init.sh |
4)用
1 | sh run.sh |
我的方法是检测当前的uid/gid,然后在容器中创建这样的用户/组,并在其下执行脚本,这样他将创建的所有文件都将与运行脚本的用户匹配:
1 2 3 4 5 6 7 8 9 10 | # get 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" |
在我的特定案例中,我试图用node docker映像构建我的节点包,这样就不必在部署服务器上安装NPM。它工作得很好,直到在容器外部和主机上,我尝试将文件移动到节点Docker映像创建的node_modules目录中,但由于该文件归根目录所有,我被拒绝访问该目录。我意识到我可以通过将目录从容器复制到主机来解决这个问题。通过Docker文档…
Files copied to the local machine are created with the UID:GID of the
user which invoked the docker cp command.
这是我用来更改docker容器创建的目录所有权的bash代码。
1 2 3 4 5 6 | NODE_IMAGE=node_builder docker run -v $(pwd)/build:/build -w="/build" --name $NODE_IMAGE node:6-slim npm i --production # node_modules is owned by root, so we need to copy it out docker cp $NODE_IMAGE:/build/node_modules build/lambda # you might have issues trying to remove the directory"node_modules" within the shared volume"build", because it is owned by root, so remove the image and its volumes docker rm -vf $NODE_IMAGE || true |
如果需要,可以使用第二个Docker容器删除目录。
1 | docker run -v $(pwd)/build:/build -w="/build" --name $RMR_IMAGE node:6-slim rm -r node_modules |
要在Docker主机和Docker容器之间共享文件夹,请尝试以下命令
$ docker run -v"$(pwd):$(pwd)" -i -t ubuntu
-v标志将当前工作目录装载到容器中。当绑定挂载卷的主机目录不存在时,Docker会自动在主机上为您创建这个目录。
但是,这里有两个问题:
解决方案:
集装箱:创建一个用户,比如说"testuser",默认情况下,用户ID将从1000开始,
主持人:创建一个组,比如组ID为1000的"testgroup",并将目录转换为新组(testgroup
如果使用docker compose,则以previleged模式启动容器:
1 2 3 4 5 6 | wordpress: image: wordpress:4.5.3 restart: always ports: - 8084:80 privileged: true |