在Dockerfile中使用mount命令时出错
以下Dockerfile在构build时会引发错误。 有没有一种方法可以在构build容器时使用overlay
mount
?
Dockerfile
FROM ubuntu:15.10 RUN mkdir /var/data \ && mkdir /var/data/delta \ && mkdir /var/data/delta/changes \ && mkdir /var/data/delta/workdir \ && mkdir /var/data/merged \ && mkdir /var/data/lower RUN mount -t overlay overlay -o lowerdir=/var/data/lower,upperdir=/var/data/delta/changes,workdir=/var/data/delta/workdir /var/data/merged
错误
…
Step 2 : RUN mount -t overlay overlay -o lowerdir=/var/data/lower,upperdir=/var/data/delta/changes,workdir=/var/data/delta/workdir /var/data/merged ---> Running in 37434cc88e15 mount: overlay is write-protected, mounting read-only mount: cannot mount overlay read-only Removing intermediate container 37434cc88e15 The command '/bin/sh -c mount -t overlay overlay -o lowerdir=/var/data/lower,upperdir=/var/data/delta/changes,workdir=/var/data/delta/workdir /var/data/merged' returned a non-zero code: 32
注意
我试着在ubuntu:15.10
容器中运行下面的mount命令,它给出了相同的错误。 如果容器以--privileged
启动, --privileged
该命令起作用。
有没有一种方法可以在构build容器时使用
overlay
mount
?
简答: 不,不会很快 。
似乎共识是在构build过程中的任何一种特权操作都会破坏图像可移植性合同,因为它可能会修改主机系统。 如果一个不同的系统然后拉和运行这样的图像,而不是从源头上build立它,从容器的angular度来看,主机将处于无效状态。
请记住, docker构build通过使用(松散地)完成Dockerfile
中的每个步骤/层来完成:
- 将最后一步/图层的图像作为新的容器运行
- 完成容器中当前步骤/图层的操作
- 提交容器(包括新状态)到一个新的图像
- 重复进一步的步骤
因此,在这种情况下,特权构build操作显然有可能脱离临时容器并触摸主机。 没有bueno。
那么,该怎么办?
解决scheme1(烤入式)
更新 – 2015-10-24:失败。 请参阅下面的解决scheme2以获取工作实现
注意:YMMV取决于Docker版本,存储/graphics驱动程序等。这里是我的泊坞窗信息 ,用于比较:
Containers: 12 Images: 283 Storage Driver: overlay Backing Filesystem: extfs Execution Driver: native-0.2 Logging Driver: json-file Kernel Version: 4.1.10-040110-generic Operating System: Ubuntu 15.04 CPUs: 4 Total Memory: 7.598 GiB Name: agthinkpad ID: F6WH:LNV4:HH66:AHYY:OGNI:OTKN:UALY:RD52:R5L5:ZTGA:FYBT:SWA4 WARNING: No swap limit support
那么,我惊奇地发现,通过Docker提交将mount挂载到映像中几乎是不可能的。 在/proc
文件系统中,内核(更具体地说是/proc/self/mounts
,从一个容器内)编写的挂载元数据的文件表示看起来并没有被Docker持久化。 从/var/lib/docker/overlay/<container-root-lower>/root/proc
是空的, /var/lib/docker/overlay/<container-root-upper>/upper/proc
不存在。
我认为/proc
可以通过一个卷来操作,并且确实find了一些2年前的绑定挂接/proc:/proc
来实现可能没有人应该尝试的事情(像这样,可能?),但是它看来这根本不起作用了。 试图将mount /proc
绑定到主机目录,或者甚至只是制作一个卷,现在是一个致命的错误,即使使用docker run --privileged :
Code: System error Message: "/var/lib/docker/overlay/c091a331f26bed12f22f19d73b139ab0c5b9971ea24aabbfad9c6482805984c9/merged/proc" cannot be mounted because it is located inside "/proc" Frames: --- 0: setupRootfs Package: github.com/opencontainers/runc/libcontainer File: rootfs_linux.go@37 --- 1: Init Package: github.com/opencontainers/runc/libcontainer.(*linuxStandardInit) File: standard_init_linux.go@52 --- 2: StartInitialization Package: Error response from daemon: Cannot start container c091a331f26bed12f22f19d73b139ab0c5b9971ea24aabbfad9c6482805984c9: [8] System error: "/var/lib/docker/overlay/c091a331f26bed12f22f19d73b139ab0c5b9971ea24aabbfad9c6482805984c9/merged/proc" cannot be mounted because it is located inside "/proc"
对于一个不需要运行mount ...的方法来说,通过启动/入口点脚本从映像生成的容器,我真的不知道从哪里开始。 由于/proc/self/mounts
是由内核pipe理的,更不用说可写了,这可能永远不可能。 希望我能忽略一些东西,有人可以指引我正确的方向。
如果你必须在图像编辑过程中做到这一点,你可以通过下面的方式来编辑你自己的编译器脚本: – 或者,首先创build一个Dockerfile并使用库存编译器:FROM mybaseimg | scratch COPY ./a/tmp/一个RUN foo …`docker build -t mynewimg .` – 使用以下组合来编写shell脚本:`CID = $(docker create mynewimg)`,[`docker cp …`](https://docs.docker.com / docker start $ CID,docker exec | run … $ CID …`,`docker stop $ CID`,`docker commit $ CID mynewimg`等等*(编辑:使用[API](https://docs.docker.com/reference/api/remote_api_client_libraries/)!)*当您需要应用特权操作时,可以升级`docker run`命令,但是`–privileged在这里完全是过度的。 如果你认为*你不应该需要` – 特权`的东西,你几乎可以肯定*不*。 对于OverlayFS / AuFS挂载,你将需要用`–cap-add = [SYS_ADMIN]`来初始化`docker run`,对于使用`AppArmor`的Ubuntu(也可能是其他)主机,你还需要`–security- opt = [apparmor:unconfined]`(或者最好是一个AppArmorconfiguration文件,放宽必要的限制,而不是`unconfined`)。 我不确定`SELinux`。
解决scheme2(运行时安装)
host$
uname -a
Linux agthinkpad 4.1 .10-040110-generic#201510030837 SMP Sat Oct 3 12:38:41 UTC 2015 x86_64 x86_64 x86_64 GNU / Linux
host$
mkdir / tmp / overlay-test && cd / tmp / overlay-test
./Dockerfile
:
FROM debian:jessie RUN apt-get update && apt-get install -y curl jq WORKDIR /usr/local/sbin # Locate and fetch the latest version of gosu RUN ["/bin/bash", "-c", "curl -o ./gosu -sSL \"$( \ curl -s https://api.github.com/repos/tianon/gosu/releases/latest \ | jq --raw-output \ '.assets[] | select(.name==\"gosu-'$(dpkg --print-architecture)'\") | .browser_download_url' \ )\" && chmod +x ./gosu"] COPY ./entrypoint.sh ./entrypoint RUN chmod +x ./entrypoint # UPPERDIR and WORKDIR **MUST BE ON THE SAME FILESYSTEM**, so # instead of creating a VOLUME for UPPERDIR we have to create a # parent directory for both UPPERDIR and WORKDIR, and then make # it the VOLUME. RUN ["/bin/bash", "-c", "mkdir -p /var/overlay-test/{lower,upper/{data,work}} /mnt/overlay-test"] VOLUME /var/overlay-test/upper # Create a file named FOO in the lower/root branch RUN touch /var/overlay-test/lower/FOO ENTRYPOINT ["entrypoint"]
./entrypoint.sh
:
#!/bin/bash set -e cd /var/overlay-test mount -t overlay -o lowerdir=lower,upperdir=upper/data,workdir=upper/work overlay /mnt/overlay-test chown -R "$DUID":"$DGID" ./ chown root: ./upper/work chmod 0750 ./upper/work cd /mnt/overlay-test exec gosu "$DUID":"$DGID" $@
host$
docker build -t覆盖testing./
Successfully built 582352b90f53
好,我们来testing一下吧!
注意:在Ubuntu 15.04主机下,我无法通过容器中的挂载目录删除(overlay whiteout)存在于lowerdir
中的任何文件。 这个错误似乎是罪魁祸首: https : rm
– 编辑: rm
工程突然,我可以看到upper/data
的char文件,所以我只能假设这是固定的,我收到了一个更新的软件包。
host$
docker运行-it -name =覆盖testing-env =“DUID = $(id -u)”--env =“DGID = $(id -g)”--cap-add = SYS_ADMIN - security-opt = apparmor:unconfined overlay-test / bin / bash
overlay-test$
id
uid=1000 gid=1000 groups=1000
overlay-test$
mount | grep'/ mnt / overlay-test'
overlay on /mnt/overlay-test type overlay (rw,relatime,lowerdir=lower,upperdir=upper/data,workdir=upper/work)
overlay-test$
pwd
/mnt/overlay-test
overlay-test$
ls -Al | sed'/ ^ t / d'
-rw-r - r-- 1 1000 1000 0 Oct 24 03:54 FOO
overlay-test$
touch BAR
overlay-test$
ls -Al | sed'/ ^ t / d'
-rw-r - r-- 1 1000 1000 0 Oct 24 04:21 BAR -rw-r - r-- 1 1000 1000 0 Oct 24 03:54 FOO
overlay-test$
ls -Al / var / overlay-test / {lower /,upper / *} | sed'/ ^ t / d'
ls: cannot open directory /var/overlay-test/upper/work: Permission denied /var/overlay-test/lower: -rw-r--r-- 1 1000 1000 0 Oct 24 03:54 FOO /var/overlay-test/upper/data: -rw-r--r-- 1 1000 1000 0 Oct 24 04:21 BAR
到目前为止这么好…让我们尝试从另一个容器导入卷:
overlay-test$
exit
host$
docker run --rm --user =“$(id -u):$(id -g)”--volumes-from = overlay-test debian:jessie / bin / bash -c“ls -Al / var / overlay-test / upper / * | sed'/ ^ t / d'“
ls: cannot open directory /var/overlay-test/upper/work: Permission denied /var/overlay-test/upper/data: -rw-r--r-- 1 1000 1000 0 Oct 24 05:32 BAR
成功! 注意,你也可以在你的Dockerfile
RUN echo
mount规格>> /etc/fstab
,然后在入口点脚本中mount -a
,但是这个方法在我的经验中是古怪的。 我不确定为什么,但是由于这两种方法之间没有function上的区别,所以我没有进一步调查。
清理: host$
docker rm -v overlay-test && docker rmi overlay-test
Docker中的容器运行时安全文档:
https://docs.docker.com/reference/run/#security-configuration https://docs.docker.com/reference/run/#runtime-privilege-linux-capabilities-and-lxc-configuration