Docker实战04|Union File System

发布时间:2024年01月06日

在上一文《Docker实战03|Cgroups》中主要介绍了Cgroups基本原理以及实现。相信读完以后可以更加深入的了解Linux Cgroups的底层实现原理了。

本文继续针对Docker 在构建时都干了哪些事情做一些详细的讲解。

本系列所有代码均已经开源。关公众号回复「Go语言实现Docker」即可获得。

具体分析

以构建镜像方式演示以下 docker 是如何使用 overlayfs 的。

先拉一下 Ubuntu:20.04 的镜像:

~# docker pull ubuntu:20.04
20.04: Pulling from library/ubuntu
527f5363b98e: Pull complete 
Digest: sha256:f2034e7195f61334e6caff6ecf2e965f92d11e888309065da85ff50c617732b8
Status: Downloaded newer image for ubuntu:20.04
docker.io/library/ubuntu:20.04

然后写个简单的 Dockerfile :

 FROM ubuntu:20.04

 RUN echo "Hello world" > /tmp/newfile

开始构建:

docker build -t hello-ubuntu .


使用docker history命令,查看镜像使用的 image layer 情况:


带 missing 标记的 layer 是自 Docker 1.10 之后,一个镜像的 image layer image history 数据都存储在 个文件中导致的,这是 Docker 官方认为的正常行为。

可以看到,c9afac9d4fa7 这一层在最上面,只用了 12Bytes,而下面的两层都是共享的,这也证明了 AUFS 是如何高效使用磁盘空间的。

然后去找一下具体的文件:

docker 默认的存储目录是/var/lib/docker,具体如下:


在这里,我们只关心image和overlay2就足够了。

  • image:镜像相关
  • overlay2:docker 文件所在目录,也可能不叫这个名字,具体和文件系统有关,比如可能是 aufs 等。

先看 image目录:

docker 会在/var/lib/docker/image目录下按每个存储驱动的名字创建一个目录,如这里的overlay2。


这里的关键地方是imagedb和layerdb目录,看这个目录名字,很明显就是专门用来存储元数据的地方。

  • layerdb:docker image layer 信息
  • imagedb:docker image 信息

因为 docker image 是由 layer 组成的,而 layer 也已复用,所以分成了 layerdb 和 imagedb。

先去 imagedb 看下刚才构建的镜像:


可以看到,都是 64 位的 ID,这些就是具体镜像信息,刚才构建的镜像 ID 为c9afac9d4fa7,所以就找c9afac9d4fa7开头的文件:


这就是 image 的 metadata,这里主要关注 rootfs:

"rootfs":{"type":"layers","diff_ids":["sha256:3a03f09d212915b240e9d216069aba5652ed4765c7e4b098c65e71860d47b8e1","sha256:f37c6b555bc81f96fc6352f3d6be66f6c24f043feab35b15eb2bdad09a8c6a0f"]}}

可以看到 rootfs 的 diff_ids 是一个包含了两个元素的数组,这两个元素就是组成 hello-ubuntu 镜像的两个 Layer 的diffID。

从上往下看,就是底层到顶层,即3a03f09d212915b…是 image 的最底层。

然后根据 layerID 去layerdb目录寻找对应的 layer:

# tree -L 2 layerdb/
layerdb/
├── mounts
├── sha256
└── tmp

在这里我们只管mounts和sha256两个目录,先打印以下 sha256 目录

可以看到,layer 里也是 64 位随机 ID 构成的目录,找到刚才 hello-ubuntu 镜像的最底层 layer:


文件含义如下:

  • cache-id:为具体/var/lib/docker/overlay2/存储路径
  • diff:diffID,用于计算 ChainID
  • size:当前 layer 的大小

docker 使用了 chainID 的方式来保存 layer,layer.ChainID 只用本地,根据 layer.DiffID 计算,并用于 layerdb 的目录名称。

chainID 唯一标识了一组(像糖葫芦一样的串的底层)diffID 的 hash 值,包含了这一层和它的父层(底层),

  • 当然这个糖葫芦可以有一颗山楂,也就是 chainID(layer0)==diffID(layer0);
  • 对于多颗山楂的糖葫芦,ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))。
# cat diff
sha256:3a03f09d212915b240e9d216069aba5652ed4765c7e4b098c65e71860d47b8e1
文章来源:https://blog.csdn.net/efheoihfe/article/details/135422632
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。