0%

容器实现-overlay2

前言

玩过容器的同学肯定都知道,容器里所看到的文件系统和宿主机是不一样的。以docker为例,运行一个alpine的容器并进入:

1
2
3
4
5
[root@staight chmdocker]# ls /
bin boot cgroup data dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@staight chmdocker]# docker run -it --name=alpine alpine
/ # ls
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var

可以看到两者的根文件系统是不同的。如果是虚拟机,虚拟化一个硬盘文件可以达到这一目的;而在容器中,该文件系统则是真实存在于宿主机上的,可以使用inspect子命令查看:

1
2
3
4
[root@staight chmdocker]# docker inspect alpine | grep MergedDir
"MergedDir": "/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/merged",
[root@staight chmdocker]# ls /var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/merged
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var

如上,/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/merged目录即是alpine容器使用的根文件系统。

不过,如果使用每个镜像都需要一个独立的根文件系统的话,那想必磁盘早已拥挤不堪了;且一个镜像可以同时运行多个容器,每个容器对文件的改动该怎么办?

Linux提供了一种叫做联合文件系统的文件系统,它具备如下特性:

  • 联合挂载:将多个目录按层次组合,一并挂载到一个联合挂载点。
  • 写时复制:对联合挂载点的修改不会影响到底层的多个目录,而是使用其他目录记录修改的操作。

目前有多种文件系统可以被当作联合文件系统,实现如上的功能:overlay2,aufs,devicemapper,btrfs,zfs,vfs等等。而overlay2就是其中的佼佼者,也是docker目前推荐的文件系统:https://docs.docker.com/storage/storagedriver/select-storage-driver/

overlay2

overlay2是一个类似于aufs的现代的联合文件系统,并且更快。overlay2已被收录进linux内核,它需要内核版本不低于4.0,如果是RHEL或Centos的话则不低于3.10.0-514。

overlay2结构:

overlay2结构

如上,overlay2包括lowerdirupperdirmerged三个层次,其中:

  • lowerdir:表示较为底层的目录,修改联合挂载点不会影响到lowerdir。
  • upperdir:表示较为上层的目录,修改联合挂载点会在upperdir同步修改。
  • merged:是lowerdir和upperdir合并后的联合挂载点。
  • workdir:用来存放挂载后的临时文件与间接文件。

在运行容器后,可以通过mount命令查看其具体挂载信息:

1
2
[root@staight chmdocker]# mount | grep overlay
overlay on /var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/INEXQHCNWBDKYZLHC42SH33R43:/var/lib/docker/overlay2/l/H47VNXLFUBUVMHEAEGXMC6S3QJ,upperdir=/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/diff,workdir=/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/work)

如上,可以看到:

  • 联合挂载点merged:/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/merged
  • lowerdir:/var/lib/docker/overlay2/l/INEXQHCNWBDKYZLHC42SH33R43:/var/lib/docker/overlay2/l/H47VNXLFUBUVMHEAEGXMC6S3QJ,冒号分隔多个lowerdir,从左到右层次越低。
  • upperdir:/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/diff
  • workdir:/var/lib/docker/overlay2/16361198b12618b2234306c6998cd8eb1c55f577a02144913da60dba4ca0c6e5/work

实践

那么,尝试着挂载一个overlay2文件系统吧。

使用目录:

1
2
3
4
5
6
7
8
9
10
overlay2
├── lower1
│ ├── a
│ └── b
├── lower2
│ └── a
├── merged
├── upper
│ └── c
└── work

使用mount命令挂载:

1
[root@staight overlay2]# mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged

如上,挂载了一个名为overlay的overlay类型的文件系统,挂载点为merged目录。

查看merged目录的层次:

1
2
3
4
5
[root@staight overlay2]# tree merged/
merged/
├── a
├── b
└── c

查看这些文件的内容:

1
2
3
4
[root@staight overlay2]# for i in `ls merged`;do echo $i: `cat merged/$i`;done
a: in lower1
b: in lower1
c: in upper

可以看到,从merged视角,位于lower2的a文件被lower1的a文件覆盖;b文件位于lower1,c文件位于upper,符合从高到低upper->lower1->lower2的层次结构。

尝试在merged目录添加一个文件d:

1
2
3
4
5
6
7
8
9
[root@staight overlay2]# touch merged/d
[root@staight overlay2]# ls merged/
a b c d
[root@staight overlay2]# ls upper/
c d
[root@staight overlay2]# ls lower1
a b
[root@staight overlay2]# ls lower2
a

可以看到对merged目录的改动同步至upper目录中,并不会影响到lower目录。

实践完成~

参考文档

Use the OverlayFS storage driver:https://docs.docker.com/storage/storagedriver/overlayfs-driver/#how-the-overlay2-driver-works

Docker storage drivers:https://docs.docker.com/storage/storagedriver/select-storage-driver/

Docker存储驱动之–overlay2:https://www.jianshu.com/p/3826859a6d6e

深入理解overlayfs(二):使用与原理分析:https://blog.csdn.net/linshenyuan1213/article/details/82527712