rey*_*n64 5 permissions cross-platform docker docker-volume
我正在尝试一个简单的工作流程而没有成功,我花了很多时间来测试SO和github上的许多解决方案.在docker中命名文件夹和更多特权权限的权限是一个噩梦link1 link2 imho.
所以我从头重新开始,尝试为我的用例创建一个简单的概念证明.
我想要这个一般工作流程:
我使用supercronic它是因为它在容器中运行crontab而没有root权限.
的Dockerfile:
FROM artemklevtsov/r-alpine:latest as baseImage
RUN mkdir -p /usr/local/src/myscript/
RUN mkdir -p /usr/local/src/myscript/result
COPY . /usr/local/src/myscript/
WORKDIR /usr/local/src/myscript/
RUN echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories
RUN apk --no-cache add busybox-suid curl
ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.$
SUPERCRONIC=supercronic-linux-amd64 \
SUPERCRONIC_SHA1SUM=9aeb41e00cc7b71d30d33c57a2333f2c2581a201
RUN curl -fsSLO "$SUPERCRONIC_URL" \
&& echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \
&& chmod +x "$SUPERCRONIC" \
&& mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \
&& ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic
CMD ["supercronic", "crontab"]
Run Code Online (Sandbox Code Playgroud)
该crontab文件中:
* * * * * sh /usr/local/src/myscript/run.sh > /proc/1/fd/1 2>&1
Run Code Online (Sandbox Code Playgroud)
该run.sh脚本
#!/bin/bash
name=$(date '+%Y-%m-%d-%s')
echo "some data for the file" >> ./result/fileName$name
Run Code Online (Sandbox Code Playgroud)
命令:
# create the volume for result, uid/gid option are not possible for windows
docker volume create --name myTestVolume
docker run --mount type=volume,source=myTestVolume,destination=/usr/local/src/myscript/result test
docker run --rm -v myTestVolume:/alpine_data -v $(pwd)/local_backup:/alpine_backup alpine:latest tar cvf /alpine_backup/scrap_data_"$(date '+%y-%m-%d')".tar /alpine_data
Run Code Online (Sandbox Code Playgroud)
当我这样做时,结果文件夹local_backup和它包含的文件具有root:root权限,因此启动此容器的用户无法访问这些文件.
有没有一个有效的解决方案,它允许启动相同脚本的 Windows/linux/mac用户轻松访问文件到卷而没有权限问题?
编辑1:
此处首次描述的策略仅适用于绑定卷,而不是命名卷.我们entrypoint.sh根据docker run给出的信息使用a chown容器文件夹的uid/gid.
我复制粘贴修改后的Dockerfile:
FROM artemklevtsov/r-alpine:latest as baseImage
RUN mkdir -p /usr/local/src/myscript/
RUN mkdir -p /usr/local/src/myscript/result
COPY . /usr/local/src/myscript/
ENTRYPOINT [ "/usr/local/src/myscript/entrypoint.sh" ]
WORKDIR /usr/local/src/myscript/
RUN echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories
RUN apk --no-cache add busybox-suid curl su-exec
ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.$
SUPERCRONIC=supercronic-linux-amd64 \
SUPERCRONIC_SHA1SUM=9aeb41e00cc7b71d30d33c57a2333f2c2581a201
RUN curl -fsSLO "$SUPERCRONIC_URL" \
&& echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \
&& chmod +x "$SUPERCRONIC" \
&& mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \
&& ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic
CMD ["supercronic", "crontab"]
Run Code Online (Sandbox Code Playgroud)
entrypoint.sh
#!/bin/sh
set -e
addgroup -g $GID scrap && adduser -s /bin/sh -D -G scrap -u $UID scrap
if [ "$(whoami)" == "root" ]; then
chown -R scrap:scrap /usr/local/src/myscript/
chown --dereference scrap "/proc/$$/fd/1" "/proc/$$/fd/2" || :
exec su-exec scrap "$@"
fi
Run Code Online (Sandbox Code Playgroud)
构建,启动,导出的过程:
docker build . --tag=test
docker run -e UID=1000 -e GID=1000 --mount type=volume,source=myTestVolume,destination=/usr/local/src/myscript/result test
docker run --rm -v myTestVolume:/alpine_data -v $(pwd)/local_backup:/alpine_backup alpine:latest tar cvf /alpine_backup/scrap_data_"$(date '+%y-%m-%d')".tar /alpine_data
Run Code Online (Sandbox Code Playgroud)
编辑2:
对于Windows,使用docker toolbox和binded volume,我在SO上找到了答案.我使用c:/Users/MyUsers文件夹进行绑定,它更简单.
docker run --name test -d -e UID=1000 -e GID=1000 --mount type=bind,source=/c/Users/myusers/localbackup,destination=/usr/local/src/myscript/result dockertest --name rflightscraps
Run Code Online (Sandbox Code Playgroud)
调查结果
Windows/Linux [HALF OK]
如果我使用绑定卷而不是命名卷,它可以工作.但这不是理想的行为,我如何在Win/Linux上使用具有正确权限的命名卷...
让我把答案分为两部分:Linux 部分和 Docker 部分。您需要了解两者才能解决此问题。
在 Linux 中,以 root 以外的用户身份运行 cronjobs 很容易。
这可以通过在 docker 容器中创建一个与主机中具有相同 UID 的用户并将 crontab 文件复制为 /var/spool/cron/crontabs/user_name 来实现。
从man crontab
crontab 是用于安装、卸载或列出用于驱动 Vixie Cron 中 cron(8) 守护进程的表的程序。每个用户都可以有自己的 crontab,尽管这些文件位于 /var/spool/cron/crontabs中,但它们不适合直接编辑。
由于Linux通过用户ID来识别用户,因此在docker内部,UID将绑定到新创建的用户,而在主机中,UID将与主机用户绑定。
因此,您不存在任何权限问题,因为这些文件归 host_user 所有。现在您应该明白为什么我提到创建与主机中的 UID 相同的用户了。
Docker 将所有目录(或层)视为 UNION FILE SYSTEM。每当您构建图像时,每条指令都会创建一个层,并且该层被标记为只读。这就是 Docker 容器不保存数据的原因。所以你必须明确告诉docker某些目录需要使用VOLUME关键字来持久化数据。
您可以在不明确提及卷的情况下运行容器。如果这样做,docker 守护进程会将它们视为 UFS 并重置权限。为了保留对文件/目录的更改(包括所有权)。相应的文件应在 Dockerfile 中声明为 Volume。
来自联合文件系统
事实上,当容器启动时,它会被移动到内存中,并且卸载启动文件系统以释放 initrd 磁盘映像使用的 RAM。到目前为止,这看起来非常像典型的 Linux 虚拟化堆栈。事实上,Docker 在启动文件系统之上又分层了一个根文件系统 rootfs。该 rootfs 可以是一个或多个操作系统(例如,Debian 或 Ubuntu 文件系统)。Docker 调用每个文件系统镜像。图像可以一层一层地叠加。下面的图像称为父图像,您可以遍历每一层,直到到达图像堆栈的底部,其中最终图像称为基础图像。最后,当从镜像启动容器时,Docker 会在下面的任何层之上安装一个读写文件系统。这是我们希望 Docker 容器运行的任何进程都将执行的地方。当Docker第一次启动一个容器时,初始的读写层是空的。当发生变化时,它们会被应用到这一层;例如,如果要更改一个文件,那么该文件将从下面的只读层复制到读写层。该文件的只读版本仍然存在,但现在隐藏在副本下方。
让我们假设我们有一个名为host_user的用户。host_user 的UID是1000。现在我们将在 Docker 容器中创建一个名为docker_user的用户。所以我将给他分配 UID 为1000。现在,如果 host_user 可从主机(即通过卷)访问这些文件,则 Docker 容器中 docker_user 拥有的任何文件也归 host_user 所有。
现在您可以与其他人共享绑定的目录,而不会出现任何权限问题。你甚至可以给相应目录赋予777权限,允许其他人编辑数据。或者,您可以保留 755 权限,允许其他人复制,但只有所有者可以编辑数据。
我已声明该目录将更改保留为卷。这会保留所有更改。请小心,因为一旦将目录声明为卷,在构建时对该目录所做的进一步更改将被忽略,因为这些更改将位于单独的层中。因此,在目录中进行所有更改,然后将其声明为卷。
这是 Docker 文件。
FROM alpine:latest
ARG ID=1000
#UID as arg so we can also pass custom user_id
ARG CRON_USER=docker_user
#same goes for username
COPY crontab /var/spool/cron/crontabs/$CRON_USER
RUN adduser -g "Custom Cron User" -DH -u $ID $CRON_USER && \
chmod 0600 /var/spool/cron/crontabs/$CRON_USER && \
mkdir /temp && \
chown -R $ID:$ID /temp && \
chmod 777 /temp
VOLUME /temp
#Specify the dir to be preserved as Volume else docker considers it as Union File System
ENTRYPOINT ["crond", "-f", "-l", "2"]
Run Code Online (Sandbox Code Playgroud)
这是 crontab
* * * * * /usr/bin/whoami >> /temp/cron.log
Run Code Online (Sandbox Code Playgroud)
塑造形象
docker build . -t test
Run Code Online (Sandbox Code Playgroud)
创建新卷
docker volume create --name myTestVolume
Run Code Online (Sandbox Code Playgroud)
以数据量运行
docker run --rm --name test -d -v myTestVolume:/usr/local/src/myscript/result test:latest
Run Code Online (Sandbox Code Playgroud)
每当您挂载到其他容器时 ,如果该容器中不存在具有该 UID 的用户或相应 UID 的用户名,则
myTestVolume您可以看到下面的数据由 UID 1000/usr/local/src/myscript/result拥有。
使用绑定卷运行
docker run --rm --name test - -dv $PWD:/usr/local/src/myscript/result test:latest
Run Code Online (Sandbox Code Playgroud)
当您执行以下操作时,ls -al /home/host_user/temp您将看到名为的文件cron.log已创建并由 拥有**host_user**。
当您执行ls -al /temp. 的内容cron.log将是docker_user.
所以,你的有效Dockerfile应该是
FROM artemklevtsov/r-alpine:latest as baseImage
ARG ID=1000
ARG CRON_USER=docker_user
RUN adduser -g "Custom Cron User" -DH -u $ID $CRON_USER && \
chmod 0600 /var/spool/cron/crontabs/$CRON_USER && \
echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && \
apk --no-cache add busybox-suid curl && \
mkdir -p /usr/local/src/myscript/result && \
chown -R $ID:$ID /usr/local/src/myscript/result && \
chmod 777 /usr/local/src/myscript/result
COPY crontab /var/spool/cron/crontabs/$CRON_USER
COPY . /usr/local/src/myscript/
VOLUME /usr/local/src/myscript/result
#This preserves chown and chmod changes.
WORKDIR /usr/local/src/myscript/
ENTRYPOINT ["crond", "-f", "-l", "2"]
Run Code Online (Sandbox Code Playgroud)
现在,每当您将数据/绑定卷附加到/usr/local/src/myscript/result它时,它都将由 UID 1000 的用户拥有,并且相同的内容在所有容器中持久存在,无论哪个容器都以其相应的用户(文件所有者为 1000)安装了相同的卷。
请注意:我已授予777权限以便与所有人分享。您可以根据自己的方便程度跳过 Dockerfle 中的该步骤。
参考:
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |