我正在尝试一个简单的工作流程,但没有成功,我花了很多时间在SO和github上测试许多解决方案。对命名文件夹的权限和停靠中的更多一般权限卷是link1 link2 imho的噩梦。
因此,我从头开始,试图为我的用例创建一个简单的概念证明。
我要这个一般的工作流程:
我使用supercronic是因为它在没有root权限的容器中运行crontab。
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"]crontab文件:
* * * * * sh /usr/local/src/myscript/run.sh > /proc/1/fd/1 2>&1run.sh脚本
#!/bin/bash
name=$(date '+%Y-%m-%d-%s')
echo "some data for the file" >> ./result/fileName$name命令:
# 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当我这样做时,结果文件夹local_backup及其包含的文件具有root:root权限,因此启动该容器的用户不能访问这些文件。
有没有一种可行的解决方案,允许启动相同脚本的windows/linux/mac用户轻松地访问卷中的文件,而不存在权限问题?
编辑1 :
该策略首先描述了只在这里工作的绑定卷、和未命名的卷。我们使用entrypoint.sh来根据docker提供的信息来创建容器文件夹的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"]The 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建造、发射、出口的程序:
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编辑2 :
对于Windows,使用停靠器工具箱和绑定卷我在上面找到了答案。我使用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 调查结果
发布于 2018-10-09 19:31:16
让我将答案分为Linux部分和Docker部分。为了解决这个问题,你需要理解这两个方面。
Linux部分
在Linux中,除了root之外,还可以轻松地以用户身份运行cron作业。
这可以通过使用与主机中相同的UID在docker容器中创建一个用户,并将crontab文件复制为/var/spool/cron/crontab/ user _name来实现。
来自man crontab
crontab是用于安装、卸载或列出用于驱动Vixie Cron中cron(8)守护进程的表的程序。每个用户都可以拥有自己的crontab,尽管这些是/var/spool/cron/crontabs,中的文件,但它们并不打算直接编辑。
因为Linux通过用户Id来标识用户,所以在坞内,UID将绑定到新创建的用户,而在主机中,UID将与主机用户绑定。
因此,您没有任何权限问题,因为这些文件属于host_user。现在,您应该已经理解了为什么我提到在主机中使用相同的UID创建用户。
码头零件
Docker认为所有目录(或层)都是UNION文件系统。每当您构建图像时,每个指令都会创建一个层,并且该层被标记为只读。这就是Docker容器不持久化数据的原因。因此,您必须显式地告诉docker,有些目录需要使用VOLUME关键字来持久化数据。
您可以不显式地提到卷就可以运行容器。如果这样做,那么docker守护进程就会认为它们是UFS,并重置权限。以保留对文件/目录的更改,包括所有权。应在Dockerfile中将相应的文件声明为卷。
来自联合文件系统
实际上,当容器启动时,它被移动到内存中,引导文件系统被卸载以释放initrd磁盘映像所使用的RAM。到目前为止,这看起来很像一个典型的Linux虚拟化堆栈。实际上,Docker下一层是根文件系统( rootfs ),位于引导文件系统的顶部。这个rootfs可以是一个或多个操作系统(例如Debian或Ubuntu文件系统)。Docker调用这些文件系统映像中的每一个。图像可以层叠在一起。下面的图像称为父图像,您可以遍历每个层,直到到达图像堆栈的底部,最后的图像被称为基本图像。最后,当容器从映像中启动时,Docker会将读写文件系统安装在下面任何层的顶部。这是我们希望我们的Docker容器运行的任何进程都将执行的地方。当Docker第一次启动容器时,初始读写层为空。当发生更改时,它们将应用于此层;例如,如果您想要更改文件,那么该文件将从下面的只读层复制到读写层。文件的只读版本仍然存在,但现在隐藏在副本下面。
示例:
让我们假设我们有一个名为host_user的用户。UID of host_user是1000。现在,我们将在Docker容器中创建一个名为docker_user的用户。所以我给他指定UID为1000。现在,docker_user在Docker容器中拥有的任何文件也属于host_user,如果host_user可以从主机(即通过卷)访问这些文件。
现在,您可以在没有任何权限问题的情况下与其他人共享绑定目录。您甚至可以在相应的目录上授予777权限,从而允许其他人编辑数据。否则,您可以保留755权限,允许其他人进行复制,但只允许所有者编辑数据。
我已经将目录声明为将更改作为卷持久化。这保留了所有的变化。注意,一旦您将目录声明为卷,则在构建将被忽略的同时对该目录进行进一步的更改,因为这些更改将位于不同的层中。因此,执行目录中的所有更改,然后将其声明为卷。
这是码头文件。
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"]这是crontab
* * * * * /usr/bin/whoami >> /temp/cron.log塑造形象
docker build . -t test创建新卷
docker volume create --name myTestVolume与数据量一起运行
docker run --rm --name test -d -v myTestVolume:/usr/local/src/myscript/result test:latest每当您将
myTestVolume挂载到其他容器时,您都可以看到/usr/local/src/myscript/result下的数据属于UID 1000,如果在该容器中没有该UID或相应UID的用户名的话。
与绑定卷一起运行
docker run --rm --name test - -dv $PWD:/usr/local/src/myscript/result test:latest当您执行ls -al /home/host_user/temp时,您将看到名为cron.log的文件是创建的,属于**host_user**。
当您执行一个docker_user的ls -al /temp时,在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"] 现在,每当您将数据/绑定卷附加到/usr/local/src/myscript/result时,它将由拥有UID 1000的用户拥有,并且在所有容器之间都具有相同的持久化,无论哪种容器安装了相同的卷,相应的用户以1000作为文件所有者。
请注意:为了与每个人共享,我已经授予了777 的权限。您可以根据您的方便性跳过Dockerfle中的这一步骤。
参考文献:
https://stackoverflow.com/questions/52433220
复制相似问题