docker作为一个容器平台,它有一套自己的存储系统。它支持的driver有overlay,overlay2, aufs等等。

这篇文章主要分析overlay和overlay2的区别。

overlay

启动docker,删除本地所有的镜像。进入/var/lib/docker/overlay目录,可以看到此时这个目录下面什么都没有,是空的。

然后按照下面的Dockerfile制作一个镜像:

[root@localhost ~]# echo aa>>aa
[root@localhost ~]# echo bb>>bb
[root@localhost ~]# echo cc>>cc
[root@localhost ~]# cat Dockerfile
FROM ubuntu
COPY aa /
COPY bb /
COPY cc /
[root@localhost ~]# docker build -t aabbcc .
Sending build context to Docker daemon 478.8 MB
Step 1/4 : FROM ubuntu
 ---> 7698f282e524
Step 2/4 : COPY aa /
 ---> cb97dcb8731f
Removing intermediate container 894ff7c4e4bb
Step 3/4 : COPY bb /
 ---> f073ea1ca7f3
Removing intermediate container 857c5cf0e128
Step 4/4 : COPY cc /
 ---> 9ace6ecb0953
Removing intermediate container e2a682d5cd56
Successfully built 9ace6ecb0953

上面的一系列操作制作了一个名字为aabbcc的image。此时可以在/var/lib/docker/overlay 下面观察到新的层已经生成了。这里每copy一个文件就会生成新的一层。

下面的代码框中红色标记的部分就是我们copy了三个文件, aa, bb,cc所生成的三层。

[root@localhost overlay]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
aabbcc              latest              9ace6ecb0953        14 hours ago        69.9 MB
docker.io/ubuntu    latest              7698f282e524        4 weeks ago         69.9 MB
[root@localhost overlay]# docker history aabbcc
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
9ace6ecb0953        14 hours ago        /bin/sh -c #(nop) COPY file:a79ff676c1e17f...   3 B                 
f073ea1ca7f3        14 hours ago        /bin/sh -c #(nop) COPY file:77c3ff995e3afe...   3 B                 
cb97dcb8731f        14 hours ago        /bin/sh -c #(nop) COPY file:f17d63ff0a8d89...   3 B                 
7698f282e524        4 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0 B                 
<missing>           4 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo '...   7 B                 
<missing>           4 weeks ago         /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B                 
<missing>           4 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' >...   745 B               
<missing>           4 weeks ago         /bin/sh -c #(nop) ADD file:1f4fdc61e133d2f...   69.9 MB             
[root@localhost overlay]#

观察一下/var/lib/docker/overlay/目录。aa文件出现了三次,bb文件出现了两次,cc文件只出现了一次,这也与我们拷贝它们的顺序相吻合。

层级结构一目了然。

[root@localhost overlay]# ls cfd414e52a3b25dade86fb2333d5cd84bb0632e55872914e42c0510cf7c211ea/root/
aa  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@localhost overlay]# ls 5b42d020f1bc93d2643e67c6fe7d86f3a20efd80767bf505853dd743d8b51a31/root/
aa  bb  bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@localhost overlay]# ls 00e5e192b42ad8923eda7d43016c56864fdb0c22c239cb141140c9959d138400/root/
aa  bb  bin  boot  cc  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

再观察一下几个aa文件的inode号

[root@localhost overlay]# find . -name aa|xargs ls -i
1057923 ./00e5e192b42ad8923eda7d43016c56864fdb0c22c239cb141140c9959d138400/root/aa  1057923 ./cfd414e52a3b25dade86fb2333d5cd84bb0632e55872914e42c0510cf7c211ea/root/aa
1057923 ./5b42d020f1bc93d2643e67c6fe7d86f3a20efd80767bf505853dd743d8b51a31/root/aa

我们可以看到,这里aa实际上是通过硬链接的方式链到不同的层里的。下面,我们尝试使用aabbcc运行一个容器。从中我们可以观察到,多出了一个aa文件,这实际上就是容器真正运行的rootfs(bfa602b98523bcc9d311e39729f1b4fd8a5046d5856b3d153886a67373a0f9f9/merged)。

通过mount指令,我们可以观察到内核将镜像和upper挂载到了指定的rootfs中了。

[root@localhost overlay]# find . -name aa|xargs ls -i
1057923 ./00e5e192b42ad8923eda7d43016c56864fdb0c22c239cb141140c9959d138400/root/aa  1057923 ./bfa602b98523bcc9d311e39729f1b4fd8a5046d5856b3d153886a67373a0f9f9/merged/aa
1057923 ./5b42d020f1bc93d2643e67c6fe7d86f3a20efd80767bf505853dd743d8b51a31/root/aa  1057923 ./cfd414e52a3b25dade86fb2333d5cd84bb0632e55872914e42c0510cf7c211ea/root/aa
[root@localhost overlay]# mount|grep overlay
/dev/mapper/fedora-root on /var/lib/docker/overlay type ext4 (rw,relatime,seclabel)
overlay on /var/lib/docker/overlay/bfa602b98523bcc9d311e39729f1b4fd8a5046d5856b3d153886a67373a0f9f9/merged type overlay (rw,relatime,context="system_u:object_r:container_file_t:s0:c286,c1020",lowerdir=/var/lib/docker/overlay/00e5e192b42ad8923eda7d43016c56864fdb0c22c239cb141140c9959d138400/root,upperdir=/var/lib/docker/overlay/bfa602b98523bcc9d311e39729f1b4fd8a5046d5856b3d153886a67373a0f9f9/upper,workdir=/var/lib/docker/overlay/bfa602b98523bcc9d311e39729f1b4fd8a5046d5856b3d153886a67373a0f9f9/work)
[root@localhost overlay]# ls

总结一下,overlay对于每一层都会构筑一个完整的镜像,镜像和镜像之间通过硬链接共享文件。当启动一个容器时,内核会union mount这个容器所

使用的镜像所对应的layer(lowerdir)和一个读写层(upperdir),并且lowerdir只有一层。

overlay2

用同样的Dockerfile构建一个叫aabbcc的image,观察/var/lib/docker/overlay2下面的文件,我们可以看到各个文件只有一个。

[root@localhost overlay2]# find . -name aa
./6e3c65cf94f4775224ee352074375629e368daaf9061681b08d2f5ab31c96a6d/diff/aa
[root@localhost overlay2]# find . -name bb
./6dd8011792252dea81cf322244e2ec78ced101c5b40c4750025d7b1aef7856f1/diff/bb
[root@localhost overlay2]# find . -name cc
./503efa11453748cadb1eaa7c0a2dde817047568d5ff7c255d0dfac885be6d557/diff/cc

进入到cc所在layer中,可以看到里面有四个文件/文件夹,diff里面存储了这一层所包含的文件,这里就只有cc这一个文件。link中存储的是这一层所对应的/var/lib/docker/overlay2/l/中的软连接。

lower文件中存储的是这一层所依赖的低层。它们用冒号隔开,每一条记录都是指向/var/lib/docker/overlay2/l/ 中的软连接。

[root@localhost 503efa11453748cadb1eaa7c0a2dde817047568d5ff7c255d0dfac885be6d557]# ls
diff  link  lower  work
[root@localhost 503efa11453748cadb1eaa7c0a2dde817047568d5ff7c255d0dfac885be6d557]# tree
.
├── diff
│   └── cc
├── link
├── lower
└── work

2 directories, 3 files
[root@localhost 503efa11453748cadb1eaa7c0a2dde817047568d5ff7c255d0dfac885be6d557]# cat link 
JYJ3FGGMPXESBF7GQL72HXOXRV
[root@localhost 503efa11453748cadb1eaa7c0a2dde817047568d5ff7c255d0dfac885be6d557]# cat lower 
l/C35GLEH6TWWOAX4BIZE6VT5KYG:l/7ODJACACJZTVZHL26VDQWAX3RS:l/2M2BNBIKMH7INTTHG2DVXM2YTM:l/2TH4LWHZM3V7UAVOSTQS6KY25A:l/52C2E2ZTZQUNS7YEWOIVT7RUOK

下面我们尝试运行一个容器,然后观察overlay2的挂载情况:

[root@localhost overlay2]# find . -name aa|xargs ls -i
921329 ./6e3c65cf94f4775224ee352074375629e368daaf9061681b08d2f5ab31c96a6d/diff/aa  921329 ./9151b049c61baa18cc19f2b2afddc12e08fac0f24af7f5d3a0f803a605482558/merged/aa
[root@localhost overlay2]# mount|grep overlay
overlay on /var/lib/docker/overlay2/9151b049c61baa18cc19f2b2afddc12e08fac0f24af7f5d3a0f803a605482558/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/MPGCJYXEJSAZHETJT64ETIGTZJ:/var/lib/docker/overlay2/l/JYJ3FGGMPXESBF7GQL72HXOXRV:/var/lib/docker/overlay2/l/C35GLEH6TWWOAX4BIZE6VT5KYG:/var/lib/docker/overlay2/l/7ODJACACJZTVZHL26VDQWAX3RS:/var/lib/docker/overlay2/l/2M2BNBIKMH7INTTHG2DVXM2YTM:/var/lib/docker/overlay2/l/2TH4LWHZM3V7UAVOSTQS6KY25A:/var/lib/docker/overlay2/l/52C2E2ZTZQUNS7YEWOIVT7RUOK,upperdir=/var/lib/docker/overlay2/9151b049c61baa18cc19f2b2afddc12e08fac0f24af7f5d3a0f803a605482558/diff,workdir=/var/lib/docker/overlay2/9151b049c61baa18cc19f2b2afddc12e08fac0f24af7f5d3a0f803a605482558/work)

从中可以看到,这个容器的rootfs是挂载到一个lowerdi为多层的rootfs上的。

总结

综上所述,overlay实际上通过硬链接在层和层之间共享文件,而overlay2的每一层都是完全独立的。如果容器启动的话,它会将多层lowerdir 挂载到它的rootfs。

这种设计就会带来一个问题,那就是linux系统会限制系统中硬链接的数量,如果用户下载了很多容器,那么docker就会在系统中到处创建硬链接,达到最大值后将无法创建新容器。

因此,我们应该使用overlay2作为docker的graph driver而不是overlay