在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中的每个步骤/层来完成:

  1. 将最后一步/图层的图像作为新的容器运行
  2. 完成容器中当前步骤/图层的操作
  3. 提交容器(包括新状态)到一个新的图像
  4. 重复进一步的步骤

因此,在这种情况下,特权构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/)!)*当您需要应用特权操作时,可以升&#x7EA7;`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