我可以在写入/覆盖时将docker主机目录装载为副本吗?

我可以在写入/覆盖时将docker主机目录装载为副本吗?,docker,Docker,我想在docker中挂载一个外部实际上是只读的主机目录。但是我希望它以读/写的形式出现在容器中 因此,文件/目录可以写入,但不能在外部更改。这是否可能使用某种覆盖过程?编辑:检查@javabrett的评论: 尽管这个解决方案有落日,但还是投票表决通过了。请参阅关于在4.8内核及更新版本上禁用overlay upperdir的答案 见: 我就是这么做的: 在主机上: 以只读方式加载目录 docker run --privileged -v /path/on/host:/path/on/clien

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


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

编辑:检查@javabrett的评论:


尽管这个解决方案有落日,但还是投票表决通过了。请参阅关于在4.8内核及更新版本上禁用overlay upperdir的答案

见:


我就是这么做的:

在主机上:

以只读方式加载目录

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
为我解决了这个问题。

我建议看看您的文件系统是否支持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中;其中as/home/viswesn/X_合并/将包含特定平台的源代码和可执行文件

现在,我们应该将X_合并目录作为卷装载到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

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

不再是容器内部的选项(可能是因为在~)中禁用了覆盖覆盖)

无论如何 另一种方法是在主机上创建覆盖,并将其绑定到来宾:

$ 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上/下/合并/

lower/:
low

merged/:
low  new-from-container  up

upper/:
new-from-container  up

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


所有信用卡都将转到

您可以使用本地卷驱动程序执行此操作,而无需运行特权容器,也无需任何其他第三方工具。本地卷驱动程序将向mount syscall传递任何选项,因此,您可以在docker中作为卷执行mount的任何操作。唯一的先决条件是预先创建覆盖目录,然后自己清理它们

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

$ 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命令一样。

如果您想在容器运行时装载卷,那么在映像创建过程中复制目录就不是一个选项了?最后,我就是这么做的。我也希望这样做,在我的例子中,
COPY
并不理想,因为数据超过40gb。我需要在CoreOS上进行操作来构建内核模块。但是我希望docker容器能够看到主机上的所有内容,并创建一个包含所有内容的新modules.conf。最后我只好抄了。但是,如果不是内核模块目录,那么接受的答案对我来说是有效的。它实际上不适用于内核模块目录。我一直在尝试使用此解决方案,但我遇到了一个错误:“错误的fs类型、错误的选项、覆盖上的错误超级块、缺少代码页或帮助程序,或者其他错误(对于多个文件系统(例如nfs、cifs),您可能需要/sbin/mount.helper程序)在某些情况下,可以在syslog中找到有用的信息—请尝试dmesg | tail或其他”。这个解决方案有任何模块或限制吗?我遇到了与@GustavoMeira相同的问题,Ubuntu14.04主机具有4.2内核和docker 1.11.RE:“错误的fs类型,错误的选项”我发现这是因为我的upperdir是由aufs提供的(cf“stat-f/path/to/lowerdir”并注意“类型”)。为了解决这个问题,我创建了一个新的tmpfs挂载来保存我的更改:“mount-t tmpfs tmpfs/tmp/overlay&&mkdir-p/tmp/overlay/{upper,work}”,然后使用这些挂载。@Woxxy:您能评论一下挂载需要哪些功能吗?似乎
--cap add=SYS_ADMIN
不够。尽管此解决方案有日落,但仍进行了升级,请参阅anwser关于在
4.8
内核和更新版本上禁用覆盖的覆盖upperdir。
$ 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