docker支持多种graphDriver,包括vfs、devicemapper、overlay、overlay2、aufs等等,其中最常用的就是aufs了,但随着linux内核3.18把overlay纳入其中,overlay的地位变得更重目前docker默认的存储类型就是overlay2,docker版本是1.8,如下
docker默认的存储目录是/var/lib/docker
,下面我们简单打印一下这个目录:
[root@docker2 ~]# ll /var/lib/docker 总用量 24 drwx------. 2 root root 24 5月 15 2019 builder drwx------. 4 root root 92 5月 15 2019 buildkit drwx------. 3 root root 78 3月 8 11:14 containers drwx------. 3 root root 22 5月 15 2019 image drwxr-x---. 3 root root 19 5月 15 2019 network drwx------. 165 root root 16384 3月 8 11:14 overlay2 drwx------. 4 root root 32 5月 15 2019 plugins drwx------ 2 root root 6 3月 8 11:10 runtimes drwx------. 4 root root 83 3月 8 11:10 swarm drwx------ 2 root root 6 3月 8 11:10 tmp drwx------. 2 root root 6 5月 15 2019 trust drwx------. 21 root root 4096 8月 11 2019 volumes
只关心image和overlay2,image:主要存放镜像中layer层的元数据
和overlay2:各层的具体信息
。
做这个实验之前,我们应该先启动一个容器,在这里使用nginx作为实验:
[root@docker2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 88984d1d86a9 nginx "nginx -g 'daemon of…" 45 hours ago Up 5 hours 0.0.0.0:80->80/tcp nginx "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 80/tcp practical_vaughan
可以看到新启动的nginx容器的id是88984d1d86a9
,我们继续往下看。
上面说了,我们只需要关心/var/lib/docker/image
和/var/lib/docker/overlay2
,可以先到/var/lib/docker/image
打印一下:
[root@docker2 ~]# cd /var/lib/docker/image/ [root@docker2 image]# ll 总用量 0 drwx------. 5 root root 81 3月 6 19:29 overlay2
我们只能看到overlay2这个目录,docker会在/var/lib/docker/image
目录下给使用的存储驱动创建一个目录,如这里的overlay2
。
接下来,使用tree
命令浏览一下这个目录:
[root@docker2 image]# tree -L 2 overlay2/ overlay2/ ├── distribution │ ├── diffid-by-digest │ └── v2metadata-by-diffid ├── │ ├── content │ └── metadata ├── │ ├── mounts │ ├── sha256 │ └── tmp └── repositories.json
这里的关键地方是imagedb
和layerdb
目录,看这个目录名字,很明显就是专门用来存储元数据的地方,那为什么区分image和layer呢?因为在docker中,image是由多个layer组合而成的,换句话就是layer是一个共享的层,可能有多个image会指向某个layer。
那如何才能确认image包含了哪些layer呢?答案就在imagedb
这个目录中去找。比如上面启动的nginx容器,我们可以先找到这个容器对应的镜像:
[root@docker2 image]# docker images nginx REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 6678c7c2e56c 3 days ago 127MB nginx 1.13.7-alpine 22f5726c6dc0 2 years ago 15.5MB
可以看到,imageID是6678c7c2e56c
,再次记住这个id,我们打印/var/lib/docker/image/overlay2/imagedb/content/sha256
这个目录:
[root@docker2 sha256]# ll |grep 6678c7c2e56c -rw------- 1 root root 6666 3月 6 19:29 6678c7c2e56c970388f8d5a398aa30f2ab60e85f20165e101053c3d3a11e6663
第一行的6678c7c2e56c970388f8d5a398aa30f2ab60e85f20165e101053c3d3a11e6663
正是记录我们nginx
镜像元数据的文件,接下来cat一下这个文件,得到一个长长的json:
[root@docker2 sha256]# cat 6678c7c2e56c970388f8d5a398aa30f2ab60e85f20165e101053c3d3a11e6663 |python -mjson.tool 。。。。。。 "rootfs": { "diff_ids": [ "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da", "sha256:71f2244bc14dacf7f73128b4b89b1318f41a9421dffc008c2ba91bb6dc2716f1", "sha256:55a77731ed2630d9c092258490b03be3491d5f245fe13a1c6cb4e21babfb15b7" ], "type": "layers"
由于篇幅原因,我只展示最关键的一部分,也就是rootfs
。可以看到rootfs的diff_ids是一个包含了3个元素的数组,其实这3个元素正是组成nginx
镜像的3个layerID,从上往下看,就是底层到顶层,也就是说f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da
是image的最底层。既然得到了组成这个image的所有layerID,那么我们就可以带着这些layerID去寻找对应的layer了。
接下来,我们返回到上一层的layerdb
中,先打印一下这个目录:
[root@docker2 layerdb]# ll 总用量 20 drwxr-xr-x. 3 root root 78 3月 8 11:14 mounts drwxr-xr-x. 162 root root 16384 3月 6 19:29 sha256 drwxr-xr-x. 2 root root 6 3月 6 19:29 tmp
在这里我们只管mounts
和sha256
两个目录,再打印一下sha256
目录:
[root@docker2 layerdb]# ll sha256/ |grep f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da drwx------ 2 root root 71 3月 6 19:27 f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da
在这里,我们仅仅发现f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da
这个最底层的layer,那么剩余两个layer为什么会没有呢?那是因为docker使用了chainID的方式去保存这些layer,简单来说就是chainID=sha256sum(H(chainID) diffid),也就是f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da..
的上一层的sha256 id是:
[root@docker2 sha256]# echo -n "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da sha256:71f2244bc14dacf7f73128b4b89b1318f41a9421dffc008c2ba91bb6dc2716f1" |sha256sum - 1541955a517830d061b79f2b52b1aed297d81c009ce7766a15527979b6e719c4 -
这个时候,你能看到f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da
这个layer层的目录了吧?依次类推,我们就能找出所有的layerID的组合。
但是上面我们也说了,/var/lib/docker/image/overlay2/layerdb
存的只是元数据,那么真实的rootfs到底存在哪里呢?其中cache-id
就是我们关键所在了。我们打印一下/var/lib/docker/image/overlay2/layerdb/sha256/f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da/cache-id
:
[root@docker2 layerdb]# cat sha256/1541955a517830d061b79f2b52b1aed297d81c009ce7766a15527979b6e719c4/cache-id f77d281af55651a70e5fc8f31de840d5b5461f36d930545db39f01bc839e4097
没错,这个id就是对应/var/lib/docker/overlay2/f77d281af55651a70e5fc8f31de840d5b5461f36d930545db39f01bc839e4097
。因此,以此类推,更高一层的layer对应的cache-id也能找到对应的rootfs,当这些rootfs的diff目录通过联合挂载的方式挂载到某个目录,就能完整整个容器需要的rootfs了。
[root@docker2 overlay2]# ll f77d281af55651a70e5fc8f31de840d5b5461f36d930545db39f01bc839e4097
总用量 8
drwxr-xr-x 7 root root 61 3月 6 19:29 diff
-rw-r--r-- 1 root root 26 3月 6 19:29 link
-rw-r--r-- 1 root root 28 3月 6 19:29 lower
drwx------ 2 root root 6 3月 6 19:29 work