先上结论:Image = config.json(配置) + rootfs(文件系统).
接下来让我们一起拆箱一个 Image 。
先从 Dockerhub 上拉一个 alpine 下来,alpine 自夸小中王者,我们选中的这个镜像仅 2.59M。
docker pull alpine:3.15.0 # 捉出来看看 docker save -o alpine.tar alpine:3.15.0
存到本地后,解开看看里面都有啥,tree 一下可以发现里面有两层目录,共5个文件。
![](https://i-blog.csdnimg.cn/blog_migrate/517c3dd8996f093616bd9ccefdc3f016.png)
第一层目录
这层目录有3个条目:2个 json + 1个以 sha 值命名的目录 <25fe...>。
![](https://i-blog.csdnimg.cn/blog_migrate/833ebf951a3eff437d4f64209f1c618a.png)
① manifest.json
打开清单文件 ,里面列出了这个镜像的所有内容,非常简单,包括:Config(指示配置文件)、RepoTags(在镜像仓库里的 tag)、Layers(所有镜像层)。
![](https://i-blog.csdnimg.cn/blog_migrate/2df98f80e1291e0e22ad29c61a6e6e4e.png)
Config 指向了同一层级的另一个 json 文件 <c059...>.json。
Layers 则指向了 <25fe...> 目录下的 layer.tar 文件,因为我们下的这个镜像比较简单,只有一层,所以这里只有一条 layer 记录。如果有多条 layer 记录,每条 layer 记录中的 sha 值都会有一个对应的目录。
② <c059...>.json
这个 json 文件的文件名是它自己的 sha 值,也是我们看到的 Image ID,文件的内容就是镜像的配置。
![](https://i-blog.csdnimg.cn/blog_migrate/aedc8c3768ec3a7bee70ccbfd69136d8.png)
这里保存了镜像的配置,一目了然的不 BB。container_config、container 这两项记录了最后 commit 到镜像的容器的信息。我们知道,镜像是多层只读的文件层,而容器指最上层的可写文件层,将容器 commit 到镜像,就是把可写层提交为最新的一层只读层。
![](https://i-blog.csdnimg.cn/blog_migrate/9001370bad4182657d5ae0d2c2c9ea89.png)
config 列出从镜像启动为容器时的默认配置参数,Env、CMD、Entrypoint 这些。
![](https://i-blog.csdnimg.cn/blog_migrate/e19d0fa9136a94c04dc0be96882b7f87.png)
rootfs 主要放各层文件的标识——diff_ids,本处的 diff_id 是对 <25fe...>/layer.tar 做 sha 得到的。
![](https://i-blog.csdnimg.cn/blog_migrate/ccf3e98548190dec32f9671d3ba0cff2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bbbec62c46e002455ece3c699c0cf451.png)
③ 25fe.../
这是我们的镜像文件层,目录名称为 layer-chain-id,在 OCI 规范中 layer-chain-id 生成规则如下图所示。实际上在本地看到的 layer-chain-id 和 manifest.json 里 layers 记录的值并不相同,可能计算的是 registry 里存储的压缩文件的 sha,而非本地拉下来这个。
![](https://i-blog.csdnimg.cn/blog_migrate/566e3296611a17205d0d62a702bb4451.png)
打开看看第二层目录都有啥。
第二层目录
<25fe...>下有 1个版本文件 + 1个名为 json 的文件 + 1个 layer.tar 文件,接下来进入 <25fe...> 目录中,有三个文件:json、VERSION、layer.tar。
![](https://i-blog.csdnimg.cn/blog_migrate/16154e235fb0cf2aa90da70b272b369c.png)
④ json
这是本层镜像的配置文件,和我们在第一级目录看到的 <c059...>.json 差不多,都是配置参数。
![](https://i-blog.csdnimg.cn/blog_migrate/c54ce5a4311210e1337e583dd777bee9.png)
⑤ layer.tar
解开 layer.tar 可以发现这就是我们挂在嘴边的(应用运行所依赖的)操作系统环境。
![](https://i-blog.csdnimg.cn/blog_migrate/bd9c2d2ef2801c0492e18442c4fe9e16.png)
⑥ VERSION
保存了一个版本号。
![](https://i-blog.csdnimg.cn/blog_migrate/da804498cbdfbb73d4fe58a9a1f741af.png)
最后
再回到 manifest.json,1个 Config + 1个 layer.tar ≈ alpine image。
以上就是一个典型的镜像。
参考:
- https://github.com/opencontainers/image-spec/blob/main/config.md
- https://programmer.group/docker-learning-image-s-local-storage-architecture.html
- https://stackoverflow.com/questions/36216220/what-is-different-of-config-and-containerconfig-of-docker-inspect
- https://opensource.com/article/18/8/sysadmins-guide-containers