我想在docker中安装一个主机目录,该目录实际上只读/外。但是我希望它以可读/写的形式出现在容器中。
这样我可以写入文件/目录,但不能在外部进行更改。这可能是使用某种叠加过程吗?
答案 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
哪个不是overlayfs
。 overlayfs
我遇到了无法使用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