在 Dockerfile 中使用 mount 命令时出错

Enz*_*zey 5 docker dockerfile

以下 Dockerfile 在构建时会引发错误。有没有办法在构建容器时使用mountwith ?overlay

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
Run Code Online (Sandbox Code Playgroud)

错误

...

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
Run Code Online (Sandbox Code Playgroud)

笔记

我尝试在容器内运行以下安装命令,ubuntu:15.10但它给出了相同的错误。如果容器已启动,则--privileged该命令有效。

Adr*_*ter 4

\n

有没有办法能够mount使用overlay在构建容器时

\n
\n\n

简短的回答:不,而且很快不会有

\n\n

似乎一致认为,构建期间的任何类型的特权操作都会破坏映像可移植性合同,因为它可能会修改主机系统。如果不同的系统随后拉取并运行这样的映像而不是从源构建它,则从生成的容器的角度来看,主机将处于无效状态。

\n\n

请记住,docker build通过完成中的每个步骤/层来工作Dockerfile

\n\n
    \n
  1. 将最后一步/层的图像作为新容器运行
  2. \n
  3. 完成容器内当前步骤/层的操作
  4. \n
  5. 将容器(包括新状态)提交到新映像
  6. \n
  7. 重复执行任何进一步的步骤
  8. \n
\n\n

因此,在这种情况下,特权构建操作显然有可能突破临时容器并接触主机。没有布埃诺。

\n\n

那么,该怎么办呢?

\n\n
\n\n

解决方案1(烘烤安装)

\n\n

更新 \xe2\x80\x94 2015-10-24:失败。请参阅下面的解决方案 2 以了解可行的实现。

\n\n

注意:YMMV 取决于 Docker 版本、存储/图形驱动程序等。这是我的docker info,用于比较:

\n\n
Containers: 12\nImages: 283\nStorage Driver: overlay\n Backing Filesystem: extfs\nExecution Driver: native-0.2\nLogging Driver: json-file\nKernel Version: 4.1.10-040110-generic\nOperating System: Ubuntu 15.04\nCPUs: 4\nTotal Memory: 7.598 GiB\nName: agthinkpad\nID: F6WH:LNV4:HH66:AHYY:OGNI:OTKN:UALY:RD52:R5L5:ZTGA:FYBT:SWA4\nWARNING: No swap limit support\n
Run Code Online (Sandbox Code Playgroud)\n\n

好吧,我惊讶地发现几乎不可能通过docker commit. 文件/proc系统中,挂载元数据的文件表示是由内核写入的(更具体地说/proc/self/mounts,是从容器内写入的),但 Docker 似乎根本没有保留该文件系统。据我所知,无论如何 \xe2\x80\x94/var/lib/docker/overlay/<container-root-lower>/root/proc是空的,并且/var/lib/docker/overlay/<container-root-upper>/upper/proc不存在。

\n\n

我认为/proc可以通过卷进行操作,并且确实找到了一些 2 年多的引用来绑定安装/proc:/proc以实现可能没有人应该尝试的事情(就像这样,可能吗?),但看起来这不起作用一切都不再了。尝试将挂载绑定/proc到主机目录,甚至只是创建一个卷,现在都是一个致命错误,即使使用docker run --privileged

\n\n
Code: System error\n\nMessage: "/var/lib/docker/overlay/c091a331f26bed12f22f19d73b139ab0c5b9971ea24aabbfad9c6482805984c9/merged/proc"\n cannot be mounted because it is located inside "/proc"\n\nFrames:\n---\n0: setupRootfs\nPackage: github.com/opencontainers/runc/libcontainer\nFile: rootfs_linux.go@37\n---\n1: Init\nPackage: github.com/opencontainers/runc/libcontainer.(*linuxStandardInit)\nFile: standard_init_linux.go@52\n---\n2: StartInitialization\nPackage: 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"\n
Run Code Online (Sandbox Code Playgroud)\n\n

就不需要mount \xe2\x80\xa6通过启动/入口点脚本在图像生成的容器内运行的方法而言,我真的不确定从现在开始该往哪里走。因为/proc/self/mounts是由内核管理的,更别说不可写了,这可能永远不可能。希望我忽略了一些事情,有人可以指出我正确的方向。

\n\n\n如果您*必须*在映像编译期间执行此操作,您可以通过执行类似以下操作来滚动自己的构建器脚本:\n\n\xe2\x80\x94 或者,首先创建一个“Dockerfile”并使用库存构建器:\ n\n FROM mybaseimg|scratch\n\n 复制 .​​/a /tmp/a\n RUN foo\n \xe2\x80\xa6\n\n`docker build -t mynewimg 。`\n\n\xe2\ x80\x94 使用以下组合编写 shell 脚本:`CID=$(docker create mynewimg)`, [`docker cp \xe2\x80\xa6`](https://docs.docker.com/reference/commandline/ cp/)、`docker start $CID`、`docker exec|run \xe2\x80\xa6 $CID \xe2\x80\xa6`、`docker stop $CID`、`docker commit $CID mynewimg` 等 * (编辑:最好使用[API](https://docs.docker.com/reference/api/remote_api_client_libraries/)!)*\n\n当你需要应用特权操作时,可以升级`docker run ` 命令,但是 `--privileged` 在这里完全是多余的。如果您*认为*您不应该需要`--privileged`来完成您几乎肯定*不需要*的事情。对于 OverlayFS/AuFS 挂载,您需要使用 `--cap-add=[SYS_ADMIN]` 初始化 `docker run`,对于具有 `AppArmor` 的 Ubuntu(可能还有其他)主机,您还需要 `--security- opt=[apparmor:unconfined]` (或者最好是放宽必要限制的 AppArmor 配置文件,而不是 `unconfined`)。我不确定“SELinux”。\n\n\n
\n\n

方案2(运行时挂载)

\n\n

host$uname -a

\n\n
\n

Linux agthinkpad 4.1 .10-040110-generic #201510030837 SMP 10 月 3 日星期六 12:38:41 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

\n
\n\n

host$mkdir /tmp/overlay-test && cd /tmp/overlay-test

\n\n

./Dockerfile

\n\n
FROM debian:jessie\n\nRUN apt-get update && apt-get install -y curl jq\n\nWORKDIR /usr/local/sbin\n\n# Locate and fetch the latest version of gosu\nRUN ["/bin/bash", "-c", "curl -o ./gosu -sSL \\"$( \\\n      curl -s https://api.github.com/repos/tianon/gosu/releases/latest \\\n      | jq --raw-output \\\n        \'.assets[] | select(.name==\\"gosu-\'$(dpkg --print-architecture)\'\\") | .browser_download_url\' \\\n    )\\" && chmod +x ./gosu"]\n\nCOPY ./entrypoint.sh ./entrypoint\nRUN chmod +x ./entrypoint\n\n# UPPERDIR and WORKDIR **MUST BE ON THE SAME FILESYSTEM**, so\n#  instead of creating a VOLUME for UPPERDIR we have to create a \n#  parent directory for both UPPERDIR and WORKDIR, and then make\n#  it the VOLUME. \nRUN ["/bin/bash", "-c", "mkdir -p /var/overlay-test/{lower,upper/{data,work}} /mnt/overlay-test"]\nVOLUME /var/overlay-test/upper\n\n# Create a file named FOO in the lower/root branch\nRUN touch /var/overlay-test/lower/FOO\n\nENTRYPOINT ["entrypoint"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

./entrypoint.sh

\n\n
#!/bin/bash\nset -e\n\ncd /var/overlay-test\nmount -t overlay -o lowerdir=lower,upperdir=upper/data,workdir=upper/work overlay /mnt/overlay-test\nchown -R "$DUID":"$DGID" ./\nchown root: ./upper/work\nchmod 0750 ./upper/work\n\ncd /mnt/overlay-test\nexec gosu "$DUID":"$DGID" $@\n
Run Code Online (Sandbox Code Playgroud)\n\n

host$docker build -t overlay-test ./

\n\n

Successfully built 582352b90f53

\n\n

好啦,我们来测试一下吧!

\n\n

注意:在 Ubuntu 15.04 主机下,我无法通过lowerdir容器内的挂载目录删除(覆盖白色)任何存在于其中的文件。这个错误似乎是罪魁祸首:\n https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1480411 \xe2\x80\x94编辑:rm突然起作用,我可以看到字符文件upper/data,所以我只能假设这个问题已修复并且我收到了更新的包。

\n\n

host$docker run -it --name=overlay-test --env="DUID=$(id -u)" --env="DGID=$(id -g)" --cap-add=SYS_ADMIN --security-opt=apparmor:unconfined overlay-test /bin/bash

\n\n

overlay-test$id

\n\n

uid=1000 gid=1000 groups=1000

\n\n

overlay-test$mount | grep \'/mnt/overlay-test\'

\n\n

overlay on /mnt/overlay-test type overlay (rw,relatime,lowerdir=lower,upperdir=upper/data,workdir=upper/work)

\n\n

overlay-test$pwd

\n\n

/mnt/overlay-test

\n\n

overlay-test$ls -Al | sed \'/^t/d\'

\n\n
\n-rw-r--r-- 1 1000 1000 0 10 月 24 日 03:54 FOO\n
\n\n

overlay-test$touch BAR

\n\n

overlay-test$ls -Al | sed \'/^t/d\'

\n\n
\n-rw-r--r-- 1 1000 1000 0 10 月 24 日 04:21 BAR\n-rw-r--r-- 1 1000 1000 0 10 月 24 日 03:54 FOO\n
\n\n

overlay-test$ls -Al /var/overlay-test/{lower/,upper/*} | sed \'/^t/d\'

\n\n
ls: cannot open directory /var/overlay-test/upper/work: Permission denied\n\n/var/overlay-test/lower:\n-rw-r--r-- 1 1000 1000 0 Oct 24 03:54 FOO\n\n/var/overlay-test/upper/data:\n-rw-r--r-- 1 1000 1000 0 Oct 24 04:21 BAR\n
Run Code Online (Sandbox Code Playgroud)\n\n

到目前为止一切顺利\xe2\x80\xa6let\尝试从另一个容器导入卷:

\n\n

overlay-test$exit

\n\n

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\'"

\n\n
ls: cannot open directory /var/overlay-test/upper/work: Permission denied\n\n/var/overlay-test/upper/data:\n-rw-r--r-- 1 1000 1000 0 Oct 24 05:32 BAR\n
Run Code Online (Sandbox Code Playgroud)\n\n

成功!请注意,您也可以在入口点脚本中添加RUN echo挂载规范,但根据我的经验,这种方法很奇怪。我不知道为什么,但由于这两种方法之间没有功能差异,所以我没有费心进一步调查。>> /etc/fstabDockerfilemount -a

\n\n

清理:host$docker rm -v overlay-test && docker rmi overlay-test

\n\n
\n\n

Docker 中容器运行时安全性的文档:

\n\n

https://docs.docker.com/reference/run/#security-configuration \n https://docs.docker.com/reference/run/#runtime-privilege-linux-capability-and-lxc-configuration

\n