在Dockerfile中使用mount命令时出错

时间:2015-09-10 20:09:52

标签: docker dockerfile

以下Dockerfile在构建时会引发错误。有没有办法在构建容器时能够mountoverlay一起使用?

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启动,则命令有效。

1 个答案:

答案 0 :(得分:2)

  

在构建容器时,有没有办法可以mountoverlay一起使用?

简短回答:No, and there won't be any time soon

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

请记住, docker build 通过使用(松散)这些操作完成Dockerfile中的每个步骤/图层来工作:

  1. 将最后一步/图层的图像作为新容器运行
  2. 完成容器中当前步骤/图层的操作
  3. 将容器(包括新状态)提交到新图像
  4. 重复任何进一步的步骤
  5. 因此,在这种情况下,特权构建操作显然可以突破临时容器并触摸主机。没有bueno。

    那么,做什么?

    解决方案1(烘焙装载)

    更新 - 2015-10-24:失败。请参阅下面的解决方案2以了解正常工作。

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

    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 commit 将装载物烘焙成图像。 /proc文件系统,其中内核(更具体地来说,/proc/self/mounts从容器内部写入安装元数据的文件表示),看起来根本不会被Docker持久化。据我所知,无论如何 - /var/lib/docker/overlay/<container-root-lower>/root/proc为空,/var/lib/docker/overlay/<container-root-upper>/upper/proc不存在。

    我认为/proc可以通过卷进行操作,并且确实找到了一些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由内核管理,更不用说不可写,这可能永远不可能。希望我能忽视某些事情,有人可以指出我正确的方向。

    <德尔> 如果您*必须*在图像编译期间执行此操作,您可以通过执行以下操作来滚动自己的构建器脚本: - 可选地,首先创建一个`Dockerfile`并使用stock builder:     来自mybaseimg | scratch     COPY ./a / tmp / a     RUN foo     ... `docker build -t mynewimg .` - 使用以下组合编写shell脚本:`CID = $(docker create mynewimg)`,[`docker cp ...`](https://docs.docker.com/reference/commandline/cp/),`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]`(或者最好是放松必要限制的AppArmor配置文件,而不是“unconfined”)。我不确定`SELinux`。

    解决方案2(运行时安装)

    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&amp;&amp; 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 overlay-test ./

    Successfully built 582352b90f53

    好的,让我们测试吧!

    注意:在Ubuntu 15.04主机下,我无法通过容器内的安装目录删除(覆盖whiteout)lowerdir中存在的所有文件。这个bug似乎是罪魁祸首: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1480411 - 编辑:rm突然工作,我可以在upper/data中看到char文件,所以我只能假设这是固定的,并且我收到了更新的包。

    host$ docker run -it --name = overlay-test --env =&#34; DUID = $(id -u)&#34; --env =&#34; DGID = $(id -g)&#34; --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&#39; / mnt / overlay-test&#39;

    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&#39; / ^ t / d&#39;

    -rw-r--r-- 1 1000 1000    0 Oct 24 03:54 FOO
    

    overlay-test$ 触摸BAR

    overlay-test$ ls -Al | sed&#39; / ^ t / d&#39;

    -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&#39; / ^ t / d&#39;

    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$ 出口

    host$ docker run --rm --user =&#34; $(id -u):$(id -g)&#34; --volumes-from = overlay-test debian:jessie / bin / bash -c&#34; ls -Al / var / overlay-test / upper / * | sed&#39; / ^ t / d&#39;&#34;

    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
    

    成功!请注意,您还可以在RUN echo>> /etc/fstab安装规范Dockerfile,然后在入口点脚本中mount -a,但根据我的经验,这种方法很奇怪。我不确定原因,但由于两种方法之间没有功能差异,我没有进一步调查。

    清理: host$ docker rm -v overlay-test&amp;&amp; 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