我正在尝试一个简单的工作流程但没有成功,我花了很长时间在 SO 和 github 上测试许多解决方案。 docker 中命名文件夹的权限和更一般的权限卷是一场噩梦 link1 link2恕我直言。
所以我从头开始,试图为我的用例创建一个简单的概念证明。
我想要这个一般的工作流程:
我用
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>&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使用绑定(bind)卷,并且未命名卷 .我们使用
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"]
入口点.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,使用 docker 工具箱和绑定(bind)卷,i found the answer on SO .我使用
c:/Users/MyUsers
用于绑定(bind)的文件夹,它更简单。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
调查结果如果我使用绑定(bind)卷而不是命名卷,它可以工作。但这不是所需的行为,我如何在 Win/Linux 上使用具有正确权限的命名卷...
最佳答案
让我将答案分为Linux部分和Docker部分两部分。您需要了解两者才能解决此问题。
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 通过用户 ID 识别用户,因此在 docker 内部,UID 将绑定(bind)到新创建的用户,而在主机中,UID 将与主机用户绑定(bind)。
因此,您没有任何权限问题,因为文件归 host_user 所有。现在你应该明白为什么我提到在主机上创建具有相同 UID 的用户了。
docker 部分
Docker 将所有目录(或层)视为 UNION FILE SYSTEM。每当您构建图像时,每条指令都会创建一个层,并且该层被标记为只读。这就是 Docker 容器不保存数据的原因。所以你必须明确告诉 docker 一些目录需要使用
VOLUME
来持久化数据。关键词。您可以在不明确提及容量的情况下运行容器。如果这样做,docker daemon 会将它们视为 UFS 并重置权限。
为了保留对文件/目录的更改,包括所有权。相应的文件应在 Dockerfile 中声明为 Volume。
来自 UNION FILE SYSTEM
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 是 1000 .现在我们要创建一个名为 的用户。 docker_user 在 Docker 容器中。所以我将他的 UID 分配为 1000 .现在,如果这些文件可由 host_user 从主机访问(即通过卷),则 Docker 容器中 docker_user 拥有的任何文件也归 host_user 所有。
现在您可以与其他人共享绑定(bind)目录,而不会出现任何权限问题。您甚至可以在相应目录上授予 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**
创建并拥有.将拥有相同的所有权。 docker_user 在 docker 容器中执行
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"]
现在,每当您将数据/绑定(bind)卷附加到
/usr/local/src/myscript/result
时它将由具有 UID 1000 的用户拥有,并且在所有容器中都保持不变,无论哪个容器安装了相同的卷,其对应的用户为 1000 作为文件所有者。请注意:我给了
777
权限,以便与每个人共享。您可以根据自己的意愿在 Dockerfle 中跳过该步骤。 引用:
关于docker - 使用 linux 和 win 提取非 root 命名卷权限的工作方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52433220/