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

时间:2015-04-09 23:21:23

标签: docker

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

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

5 个答案:

答案 0 :(得分:14)

编辑:查看@ javabrett的评论:

  

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

请参阅: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

哪个不是overlayfsoverlayfs我遇到了无法使用rm的问题。 overlay为我解决了这个问题。

答案 1 :(得分:2)

不再从容器内部选择(可能是因为在〜4.4 kernels中禁用了叠加覆盖)

$ 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

<强> ANYWAY 另一种方法是在主机上创建叠加层并将其绑定到来宾:

$ 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

答案 2 :(得分:1)

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

进行验证
  $> cat /proc/filesystems | grep overlayfs
  $> 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

有了这个,同时为所有平台并行构建相同的源代码,没有多个源代码副本。

答案 3 :(得分:1)

使用本地卷驱动程序,可以在不运行特权容器且没有任何其他第三方工具的情况下执行此操作。本地卷驱动程序会将任何选项传递给mount syscall,因此您可以使用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命令一样。

答案 4 :(得分:0)

如果避免将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