我可以将docker主机目录作为copy/overlay上的副本挂载吗?

Mat*_*att 28 docker

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

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

Wox*_*xxy 17

编辑:查看@ javabrett的评论:

尽管这个解决方案有一个日落,但观察到有关在4.8内核和更新版本上禁用overlay-upperdir-on-overlay的问题. - javabrett 7月23日5:55

请参阅:https://stackoverflow.com/a/50917037/644504


这就是我做的:

在主持人:

将目录加载为只读.

/path/on/client

在客户端:

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

overlayfs

然后overlayfs用来读/写文件.

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

rm

哪个不是overlay.随着/path/on/client我就暂时无法使用的问题overlayfs.overlayfs为我解决了这个问题.

  • RE:"错误的fs类型,错误的选项"我发现这是因为我的上层由aufs提供(cf"stat -f/path/to/lowerdir"并注意"type").我通过创建一个新的tmpfs挂载来解决这个问题,以保存我的更改:"mount -t tmpfs tmpfs/tmp/overlay && mkdir -p/tmp/overlay/{upper,work}"然后使用它们. (3认同)
  • 尽管这个解决方案有一个日落,但是在'4.8`内核和更新的内核上看到关于overlay-upperdir-on-overlay被禁用的情况. (2认同)

BMi*_*tch 16

您无需运行特权容器,也无需任何其他 3rd 方工具,即可使用本地卷驱动程序执行此操作。本地卷驱动程序会将任何选项传递给挂载系统调用,因此您可以使用挂载执行的任何操作都可以作为 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.
Run Code Online (Sandbox Code Playgroud)

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

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

然后,让我们用一个--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
Run Code Online (Sandbox Code Playgroud)

最后,让我们创建一个 compose 文件:

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

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

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

接下来,我们可以对容器 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
Run Code Online (Sandbox Code Playgroud)

验证每个容器看到的变化,或缺乏变化:

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

并显示主机目录不变:

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

更改都只对上层目录进行:

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

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


drz*_*raf 10

不再是容器内部的选项(可能是因为在 ~ 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
Run Code Online (Sandbox Code Playgroud)

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

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

$ ls upper/ lower/ merged/

lower/:
low

merged/:
low  new-from-container  up

upper/:
new-from-container  up
Run Code Online (Sandbox Code Playgroud)


wst*_*ven 5

如果您避免将 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
Run Code Online (Sandbox Code Playgroud)

所有学分均转到https://gist.github.com/detunized/7c8fc4c37b49c5475e68ef9574587eee