我正在尝试一个简单的工作流程而没有成功,我花了很多时间来测试SO和github上的许多解决方案.在docker中命名文件夹和更多特权权限的权限是一场噩梦link1 link2 imho.
所以我从头重新开始,尝试为我的用例创建一个简单的概念证明.
我想要这个一般工作流程:
> Windows和/或Linux上的用户构建Dockerfile
>用户运行容器(如果可能不是root用户)
>容器启动一个crontab,每分钟运行一次脚本写入数据卷
>用户(在Linux或Windows上)从数据卷(而不是root)获取结果,因为权限已正确映射
我使用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"]
crontab文件:
* * * * * sh /usr/local/src/myscript/run.sh > /proc/1/fd/1 2>&1
run.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:
该策略首先描述here only使用绑定卷,而不是命名卷.我们使用entrypoint.sh根据docker run给出的信息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"]
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,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,使用docker toolBox和binded volume,i found the answer on 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
调查结果
> crontab与废料用户一起运行[确定]
>本地用户的UID / GID映射到容器用户废料[确定]
>导出的数据仍然是root [NOT OK].
> Windows / Linux [HALF OK]
如果我使用绑定卷而不是命名卷,它可以工作.但这不是理想的行为,如何在Win / Linux上使用具有正确权限的命名卷…
Linux部分
在Linux中以root用户身份运行cronjobs很容易.
这可以通过在docker容器中创建一个用户,该用户具有与主机中相同的UID,并将crontab文件复制为/ var / spool / cron / crontabs / user_name.
来自man crontab
crontab is the program used to install,deinstall or list the
tables used to drive the cron(8) daemon in Vixie Cron. Each user can
have their own crontab,and though these are files in
/var/spool/cron/crontabs,they are not intended to be edited directly.
由于Linux通过User Id识别用户,因此在docker内部,UID将绑定到新创建的用户,而在主机中,UID将与主机用户绑定.
因此,您没有任何权限问题,因为这些文件归host_user所有.现在您可以理解为什么我提到使用与主机中相同的UID创建用户.
Docker部分
Docker认为所有目录(或层)都是UNION FILE SYSTEM.无论何时构建图像,每条指令都会创建一个图层,并且该图层将标记为只读.这就是Docker容器不会保留数据的原因.因此,您必须明确告诉docker某些目录需要使用VOLUME关键字来保存数据.
您可以在不明确提及卷的情况下运行容器.如果这样做,docker守护程序会将它们视为UFS并重置权限.
为了保留对包含所有权的文件/目录的更改.相应的文件应在Dockerfile中声明为Volume.
Indeed,when a container has booted,it is moved into memory,and the boot filesystem is unmounted to free up the RAM used by the initrd disk image. So far this looks pretty much like a typical Linux virtualization stack. Indeed,Docker next layers a root filesystem,rootfs,on top of the boot filesystem. This rootfs can be one or more operating systems (e.g.,a Debian or Ubuntu filesystem).
Docker calls each of these filesystems images. Images can be layered on top of one another. The image below is called the parent image and you can traverse each layer until you reach the bottom of the image stack where the final image is called the base image. Finally,when a container is launched from an image,Docker mounts a read-write filesystem on top of any layers below. This is where whatever processes we want our Docker container to run will execute. When Docker first starts a container,the initial read-write layer is empty. As changes occur,they are applied to this layer; for example,if you want to change a file,then that file will be copied from the read-only layer below into the read-write layer. The read-only version of the file will still exist but is now hidden underneath the copy.
例:
我们假设我们有一个名为host_user的用户. host_user的UID是1000.现在我们将在Docker容器中创建一个名为docker_user的用户.因此,我将UID指定为1000.现在Docker容器中docker_user拥有的任何文件也归host_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"]
这是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
Whenever you mount
myTestVolume
to other container you can see the
data under/usr/local/src/myscript/result
is owned by UID 1000
if no user exist with that UID in that container or the username of
corresponding UID.
使用Bind音量运行
docker run --rm --name test - -dv $PWD:/usr/local/src/myscript/result test:latest
执行ls -al / home / host_user / temp时,您将看到名为cron.log的文件已创建,并由** host_user **拥有.
执行ls -al / temp时,docker容器中的docker_user将拥有相同的内容. 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","2"]
现在,无论何时将数据/绑定卷附加到/usr/local / src / myscript / result,它都将由具有UID 1000的用户拥有,并且在所有容器中都是持久的,无论哪个容器安装了相同的卷,其相应的用户为1000作为文件所有者.
请注意:我已授予777权限,以便与每个人共享.您可以根据自己的意愿跳过Dockerfle中的该步骤.
参考文献:
> Crontab manual.
> User identiier – Wiki
> User ID Definition.
> About storage drivers.
> UNION FILE SYSTEM.