【问题标题】:Can I mount docker host directory as copy on write/overlay?我可以在写入/覆盖时挂载 docker 主机目录作为副本吗?
【发布时间】:2015-04-09 23:21:22
【问题描述】:

我想在 docker 中挂载一个主机目录,该目录在外部实际上是只读的。但我希望它以读/写的形式出现在容器内。

这样文件/目录可以写入但不能在外部更改。这可能使用某种覆盖过程吗?

【问题讨论】:

  • 您希望能够在容器运行时挂载卷,COPY在映像创建期间不选择目录?
  • 最后我就是这么做的。
  • 我也想做同样的事情,COPY 在我的情况下并不理想,因为数据超过 40gb。
  • 我需要在 CoreOS 上构建内核模块。但我希望 docker 容器能够从主机中查看所有内容,并创建一个新的 modules.conf 并填充所有内容。最后我不得不复制。但是,如果它不是内核模块目录,则接受的答案对我有用。它实际上不适用于内核模块目录。
  • 有同事指出Podman在挂载volume时有一个:O选项,代表Overlay Volume Mount

标签: docker


【解决方案1】:

编辑:查看@javabrett 的评论:

尽管此解决方案已日落,但仍表示支持。请参阅有关在 4.8 内核和更高版本上禁用 overlay-upperdir-on-overlay 的答案。

见:https://stackoverflow.com/a/50917037/644504


这就是我的工作:

在主机上:

将目录加载为只读。

docker run --privileged -v /path/on/host:/path/on/client-read-only:ro -it ubuntu /bin/bash

在客户端:

在客户端使用 OverlayFS 覆盖从主机挂载的只读目录。

mount -t overlayfs none -o lowerdir=/path/on/client-read-only,upperdir=/path/on/client /path/on/client

然后使用/path/on/client 读取/写入文件。

编辑:如果您的主机上有 3.18+ 内核,您可能更喜欢在客户端上使用它:

mount -t overlay overlay -o lowerdir=/path/on/client-read-only,upperdir=/path/on/client,workdir=/path/on/client-workdir /path/on/client

这不是overlayfs。对于overlayfs,我遇到了无法使用rm 的问题。 overlay 为我解决了这个问题。

【讨论】:

  • 我一直在尝试使用此解决方案,但我收到错误消息:“错误的 fs 类型、错误的选项、覆盖上的超级块错误、缺少代码页或帮助程序或其他错误(对于多个文件系统(例如 nfs、cifs)您可能需要 /sbin/mount. 帮助程序)在某些情况下,可以在 syslog 中找到有用的信息 - 尝试 dmesg | tail 左右”。此解决方案是否有任何模块或限制?
  • 我遇到了与 @GustavoMeira 相同的问题,ubuntu 14.04 主机,4.2 内核和 docker 1.11。
  • RE:“错误的 fs 类型,错误的选项”我发现这是因为我的上层目录是由 aufs 提供的(参见“stat -f /path/to/lowerdir”并注意“类型”)。我通过创建一个新的 tmpfs 挂载来保存我的更改来解决这个问题:“mount -t tmpfs tmpfs /tmp/overlay && mkdir -p /tmp/overlay/{upper,work}”然后使用它们。
  • @Woxxy:您能评论一下挂载需要哪些功能吗?看来--cap-add=SYS_ADMIN不够用。
  • 赞成尽管此解决方案已日落,请参阅有关在 4.8 内核和更新版本上禁用 overlay-upperdir-on-overlay 的 anwser。
【解决方案2】:

您可以使用本地卷驱动程序在不运行特权容器和任何其他第三方工具的情况下执行此操作。本地卷驱动程序会将任何选项传递给 mount 系统调用,因此您可以使用 mount 做的任何事情都可以作为 docker 中的卷来执行。唯一的前提是您提前创建覆盖目录并自己清理它们。

首先,让我们创建目录和一些只读数据:

$ mkdir -p {ro-data,upper1,upper2,upper3,work1,work2,work3}

$ ls
ro-data  upper1  upper2  upper3  work1  work2  work3

$ vi ro-data/data.txt

$ cat ro-data/data.txt
This is a data file.
It should be read-only on the host upper dir.

接下来,让我们使用覆盖选项创建一个命名卷并使用它运行一个容器:

$ docker volume create --driver local --opt type=overlay \
  --opt o=lowerdir=${PWD}/ro-data,upperdir=${PWD}/upper1,workdir=${PWD}/work1 \
  --opt device=overlay overlay1
overlay1

$ docker container run -d --rm -v overlay1:/data --name cont1 busybox tail -f /dev/null
a6269cb6c68469aa4f57aae554c5f0823f1103715334b3719c5567abc7d55daa

然后,让我们对运行--mount 选项执行相同的操作,由于嵌套的逗号分隔字符串,它会稍微复杂一些。转义引号可以解决这个问题:

$ docker run -d --rm \
  --mount type=volume,dst=/data,volume-driver=local,volume-opt=type=overlay,\"volume-opt=o=lowerdir=${PWD}/ro-data,upperdir=${PWD}/upper2,workdir=${PWD}/work2\",volume-opt=device=overlay \
  --name cont2 busybox tail -f /dev/null
7329ae4ba4046782166b045611ecccb129f5e557df7eb4da95ec9063a0fe234e

最后,让我们编写一个文件:

$ vi docker-compose.yml

$ cat docker-compose.yml
version: '3'

volumes:
  overlay3:
    driver: local
    driver_opts:
      type: overlay
      o: lowerdir=${PWD}/ro-data,upperdir=${PWD}/upper3,workdir=${PWD}/work3
      device: overlay

services:
  overlay3:
    image: busybox
    command: tail -f /dev/null
    container_name: cont3
    volumes:
    - overlay3:/data

$ docker-compose up -d
Creating network "vol-overlay_default" with the default driver
Creating volume "vol-overlay_overlay3" with local driver
Creating cont3 ... done

一切都在运行,让我们验证数据文件是否存在:

$ docker exec cont1 ls -l /data
total 4
-rw-r--r--    1 1000     1000            67 Nov  8 16:29 data.txt

$ docker exec cont2 ls -l /data
total 4
-rw-r--r--    1 1000     1000            67 Nov  8 16:29 data.txt

$ docker exec cont3 ls -l /data
total 4
-rw-r--r--    1 1000     1000            67 Nov  8 16:29 data.txt

接下来,我们可以对容器1中的目录进行一些修改,并删除容器2中的文件:

$ echo "container 1 adds lines" | docker exec -i cont1 tee -a /data/data.txt
container 1 adds lines

$ echo "writing to another file" | docker exec -i cont1 tee -a /data/container1.txt
writing to another file

[11:48:30] [bmitch@bmitch-asusr556l:~/data/docker/test/vol-overlay] [master]
$ docker exec cont2 rm /data/data.txt

验证每个容器是否有变化:

$ docker exec cont1 ls -l /data
total 8
-rw-r--r--    1 root     root            24 Nov  8 16:48 container1.txt
-rw-r--r--    1 1000     1000            90 Nov  8 16:47 data.txt

$ docker exec cont2 ls -l /data
total 0

$ docker exec cont3 ls -l /data
total 4
-rw-r--r--    1 1000     1000            67 Nov  8 16:29 data.txt

$ docker exec cont1 cat /data/data.txt
This is a data file.
It should be read-only on the host upper dir.
container 1 adds lines

$ docker exec cont3 cat /data/data.txt
This is a data file.
It should be read-only on the host upper dir.

并显示主机目录不变:

$ ls -l ro-data
total 4
-rw-r--r-- 1 bmitch bmitch 67 Nov  8 11:29 data.txt

$ cat ro-data/data.txt
This is a data file.
It should be read-only on the host upper dir.

所有更改都只针对上层目录:

$ ls -l upper*
upper1:
total 8
-rw-r--r-- 1 root   root   24 Nov  8 11:48 container1.txt
-rw-r--r-- 1 bmitch bmitch 90 Nov  8 11:47 data.txt

upper2:
total 0
c--------- 1 root root 0, 0 Nov  8 11:48 data.txt

upper3:
total 0

删除容器和卷后,您需要手动删除上层目录。就像 docker 不会为你创建它们一样,它也不会删除它们,就像你自己运行 mount 命令一样。

【讨论】:

  • 你救了我的命。谢谢,完美运行。
【解决方案3】:

容器内部不再是一个选项(可能是因为在 ~4.4 kernels 中禁用了overlay-over-overlay)

$ uname -a && \
  docker run --privileged --rm debian:latest sh -c "mkdir upper lower work merged && mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged/; dmesg|tail -1"


Linux preprod 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64 GNU/Linux

mount: wrong fs type, bad option, bad superblock on overlay,
       missing codepage or helper program, or other error

       In some cases useful info is found in syslog - try
       dmesg | tail or so.

[288426.860631] overlayfs: filesystem on 'upper' not supported as upperdir

无论如何 另一种方法是在 host 上创建叠加层并将其绑定到来宾:

$ mkdir upper lower work merged && \
  touch upper/up lower/low && \
  sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged/ && \
  docker run --rm -v $(pwd)/merged:/tmp/merged debian:latest sh -c "touch /tmp/merged/new-from-container"

$ ls upper/ lower/ merged/

lower/:
low

merged/:
low  new-from-container  up

upper/:
new-from-container  up

【讨论】:

    【解决方案4】:

    如果您避免将upperdir 设置为本地目录(即已经是覆盖),这是可能的。 但您可以改用 tmpfs(在内核 4.9 上测试):

    # On the host to run the container
    docker run --cap-add=SYS_ADMIN -i -t -v ~/host-folder-to-mount:/root/folder-ro:ro ubuntu
    
    # Inside the container
    # Need to create the upper and work dirs inside a tmpfs.
    mkdir -p /tmp/overlay && \
    mount -t tmpfs tmpfs /tmp/overlay && \
    mkdir -p /tmp/overlay/{upper,work} && \
    mkdir -p /root/folder && \
    mount -t overlay overlay -o lowerdir=/root/folder-ro,upperdir=/tmp/overlay/upper,workdir=/tmp/overlay/work /root/folder
    

    所有学分都归https://gist.github.com/detunized/7c8fc4c37b49c5475e68ef9574587eee

    【讨论】:

      【解决方案5】:

      我会建议你看看你的文件系统是否支持overlayfs;并且可以通过

      进行验证
        $> grep overlayfs /proc/filesystems
        $> overlayfs overlay
      

      如果是这样,那么我建议您在主机中创建 overlayfs 并将合并目录挂载到 Docker 容器,以便您可以从主机管理事物,而不是一些在主机上和一些在 Docker 容器上。

      我按照以下步骤来实现这一点:让我举个例子;我有源代码,我想为 i386、x86_64 和 amd64 等多个平台构建它;所有平台的源代码将保持不变;每个平台的可执行文件(.obj 和 exe)会有所不同;所以我们需要每个特定平台目录中的可执行文件

       sudo  mount -t overlay overlay -o lowerdir=/home/viswesn/source-code,upperdir=/home/viswesn/i386_executable,workdir=/i386 /home/viswesn/i386_merged
      
       sudo  mount -t overlay overlay -o lowerdir=/home/viswesn/source-code,upperdir=/home/viswesn/x86_64_executable,workdir=/x86_64 /home/viswesn/x86_64_merged
      

      它说,任何由源文件创建的目标文件或可执行文件都将保留在 /home/viswesn/X_executable 目录中,而源代码将保留在 /home/viswesn/source-code 中;其中 /home/viswesn/X_merged/ 将包含特定平台的源代码和可执行文件;

      现在我们应该将 X_merged 目录作为卷挂载到 Docker 容器中,以便为每个平台构建源代码

      对于 i386:

       sudo docker run --privileged -v /home/viswesn/i386_merged/:/source-code -it ubuntu-trusty:14:01 /bin/bash
      

      对于 amd64:

      sudo docker run --privileged -v /home/viswesn/amd64_merged/:/source-code -it ubuntu-amd64:14:01 /bin/bash
      

      这样,相同的源代码可以同时为所有平台并行构建,而无需多个源代码副本。

      【讨论】:

        猜你喜欢
        • 2019-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-04
        • 1970-01-01
        • 2016-06-23
        • 1970-01-01
        • 2015-05-04
        相关资源
        最近更新 更多