https://cloud.tencent.com/developer/article/2272892
Union File System
- 就是将多个目录合并到一个一个目录中去
- 使用一种称为 copy-on-write (COW)的机制。如果需要修改的文件位于只读层,UnionFS 会将该文件复制到最上面的可写层,然后在那里进行修改。这样就保证了底层的文件系统保持不变,而改动仅仅发生在顶层。
overlay 挂载
使用mount命令来挂载到某个位置,需要指定lowerdir ,upperdir,workdir,merged_dir
mount -t overlay overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work merged_dir
该命令将 lower1,lower2,lower3,和upper和work这些目录内的内容放到merged_dir目录中
lowerdir :只读层,对应到当前层之下的所有层的文件
upperdir:读写层,当前层的文件
workdir:不用管
merged_dir:合并后放的位置
此时如果修改某个文件的内容,如果该文件来自lowdir,那么该文件修改后,upperdir内会多出一个修改的内容的文件,但lowdir中的内容不会改变
此时如果修改删除merged_dir的一个文件,如果该文件来自lowdir,那么merged_dir修改后,upperdir内会多出一个whiteout的文件(就是标志该文件在已经没了),但lowdir中的文件没有变化
sudo docker info
查看docker相关配置信息
存储Docker镜像的文件系统为extfs。支持d_type为真。
Docker镜像和容器数据被储存在“/ var / snap / docker / common / var-lib-docker”目录中。具体来说,镜像位于“/ var / snap / docker / common / var-lib-docker / image”目录中,而容器数据和其他相关文件则位于“/ var / snap / docker / common / var-lib-docker”目录中。
docker 的overlay2
docker 拉取一个镜像,该镜像位置在
/var/snap/docker/common/var-lib-docker/overlay2
查看该目录
除了l目录其他都是镜像层
- diff:该镜像层的文件
- link:当前镜像层的diff 在 l 目录中的软连接名称
- lower:此镜像层之下的所有层的软链接名称(对于到diff,即之下所有镜像的所有文件)
镜像和容器和overlay2
实际上,/var/snap/docker/common/var-lib-docker/overlay2
下还能存放init层,和容器层,一个完整的容器分为3层:镜像层、init层和容器层,当docker创建一个容器时候就会创建init层和容器层
overlay2 通过联合挂载技术,将镜像层的diff、init层的diff与容器层的diff挂载到容器层的merged目录
- init层:做些容器需要的一些配置但因为镜像层是只读层不能被修改所以使用init来配置
- 镜像层:对应到为该容器层之下的各个镜像
- 容器层:对应到为挂载的merge所在的目录
此时该对应到的overlay挂载层次如下
- lowerdir:容器层之下的各个镜像的diff文件
- upperdir: 容器层的diff文件
- merged:容器层的merged
容器层将同名的init层和镜像层合并到容器层的merged层里
实操
https://github.com/FULLK/llkdocker/tree/main/unionfilesystem
建立五个文件夹
- lower1:1.txt
- lower2:2.txt
- upper:3.txt
- work:无
- merged:无
sudo mount -t overlay overlay -olowerdir=lower1:lower2,upperdir=upper,workdir=work merged
挂载到merged上去
然后分别删除merged里面1.txt的内容,发现diff多了一个whiteout的1.txt文件,修改merged里面2.txt的内容,发现diff多了一个修改后的2.txt文件,在到merge新建一个4.txt,upper也出现一个一模一样的4.txt
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ sudo tree -L 2
.
├── lower1
│ └── 1.txt
├── lower2
│ └── 2.txt
├── merged
│ ├── 1.txt
│ ├── 2.txt
│ └── 3.txt
├── upper
│ └── 3.txt
└── work
└── work
6 directories, 6 files
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ cat ./merged/1.txt
from lower 1
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ rm ./merged/1.txt
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ sudo tree -L 2
.
├── lower1
│ └── 1.txt
├── lower2
│ └── 2.txt
├── merged
│ ├── 2.txt
│ └── 3.txt
├── upper
│ ├── 1.txt
│ └── 3.txt
└── work
└── work
6 directories, 6 files
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ cd merged
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem/merged$ touch 4.txt
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem/merged$ sudo tree -L 2
.
├── 2.txt
├── 3.txt
└── 4.txt
0 directories, 3 files
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem/merged$ cd ../
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ sudo tree -L 2
.
├── lower1
│ └── 1.txt
├── lower2
│ └── 2.txt
├── merged
│ ├── 2.txt
│ ├── 3.txt
│ └── 4.txt
├── upper
│ ├── 1.txt
│ ├── 3.txt
│ └── 4.txt
└── work
└── work
6 directories, 8 files
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ editor merged/2.txt
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$ sudo tree -L 2
.
├── lower1
│ └── 1.txt
├── lower2
│ └── 2.txt
├── merged
│ ├── 2.txt
│ ├── 3.txt
│ └── 4.txt
├── upper
│ ├── 1.txt
│ ├── 2.txt
│ ├── 3.txt
│ └── 4.txt
└── work
└── work
6 directories, 9 files
llk@llk-virtual-machine:~/Desktop/docker/unionfilesystem$
疑问点
就是docker运行容器后,会将镜像层和init层和当前容器层的diff挂载到容器层的meged里,发现merged没有内容
而且mount | grep overlay2 也没有找到docker启动容器时候应该挂载的那个merged
大佬说需要参考源代码才能知道最新的流程,这里先留着,等以后搓的时候遇到如何实现后再回来看看
https://github.com/microsoft/docker/blob/master/volume/volume.go#L18
https://github.com/microsoft/docker/blob/master/daemon/graphdriver/overlay/overlay.go#L234