在上一遍文章中我们 get 到了 crane pull 的过程,然而好奇的我仍然有个疑问,那就是 tar archive 中并未定义了 layer 的 stack 关系,如此 docker load 如何能正确组织 image 的 fs changeset 呢 ?
docker load
https://docs.docker.com/engine/reference/commandline/load/
docker (moby)
https://github.com/moby/moby
Layer 是如何串联起来的
https://www.hi-linux.com/posts/44544.html
Study
按说理论上每层,应有镜像层 id,并且有指向 parent layer 的指针,当然基础镜像没有 parent layer
否则无法将 layer 组织起来
既然如此那在 image tar archive 中,是如何体现这种 layer stack 关系的 ?
docker save
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | . ├── 2daafd635a629218204652bd3b10ddd23ae5e33abe1ebc3c26c01103e33369de │   ├── VERSION │   ├── json │   └── layer.tar ├── 9fbc75679caed833594370d2effbdbba4e09eb6ee7a87f9d2e94b41627d56831 │   ├── VERSION │   ├── json │   └── layer.tar ├── e81eb098537d6c4a75438eacc6a2ed94af74ca168076f719f3a0558bd24d646a.json ├── ecfed8505473c79ab6831d6272a1adff68a42cd102e9992e60b2f8925df01927 │   ├── VERSION │   ├── json │   └── layer.tar ├── manifest.json └── repositories 3 directories, 12 files
   | 
 
可见 docker save 时会将 layer 的 metadata 文件输出,查看 json 文件后发现其的确有 parent 的定义
1 2 3 4 5
   | {     "id": "2daafd635a629218204652bd3b10ddd23ae5e33abe1ebc3c26c01103e33369de",     "parent": "9fbc75679caed833594370d2effbdbba4e09eb6ee7a87f9d2e94b41627d56831",     "created": "2018-11-16T13:32:10.147294787Z" }
  | 
 
我还做了个实验,将每层的 json, VERSION 及 repositories 文件删除,检查是否仍然能继续 docker load,呃当然是肯定的
1 2 3 4 5 6 7 8 9 10
   | . ├── 2daafd635a629218204652bd3b10ddd23ae5e33abe1ebc3c26c01103e33369de │   └── layer.tar --- Layer File ├── 9fbc75679caed833594370d2effbdbba4e09eb6ee7a87f9d2e94b41627d56831 │   └── layer.tar --- Layer File ├── e81eb098537d6c4a75438eacc6a2ed94af74ca168076f719f3a0558bd24d646a.json --- Config file ├── ecfed8505473c79ab6831d6272a1adff68a42cd102e9992e60b2f8925df01927 │   └── layer.tar --- Layer File └── manifest.json --- Image Tar Archive Description 3 directories, 5 files
   | 
 
docker load 一把
1 2 3 4 5 6
   | tar -cf nginx-new.tar * > docker load -i nginx-new.tar ef68f6734aa4: Loading layer [==================================================>]  58.44MB/58.44MB 876456b96423: Loading layer [==================================================>]  54.38MB/54.38MB 9a8f339aeebe: Loading layer [==================================================>]  3.584kB/3.584kB Loaded image: nginx:latest
   | 
 
docker load 各 layer, 其中左侧的 hex 值为 layer sha256 hash value
可见的确未受影响,所以 docker load 并未依赖 docker save 时保留的 layer metadata 信息
1 2 3 4 5 6 7 8 9
   | "os": "linux", "rootfs": {     "type": "layers",     "diff_ids": [         "sha256:ef68f6734aa485edf13a8509fe60e4272428deaf63f446a441b79d47fc5d17d3",         "sha256:876456b964239fb297770341ec7e4c2630e42b64b7bbad5112becb1bd2c72795",         "sha256:9a8f339aeebe1e8bcef322376e1274360653fb802abd4b94c69ea45a54f71a2b"     ] }
   | 
 
另外对于镜像 Config file 中说明的 rootfs.diff_ids, 其中的 sha256 hash 值均为各 layer 的 sha256 hash 值
1 2 3
   | ef68f6734aa485edf13a8509fe60e4272428deaf63f446a441b79d47fc5d17d3  ecfed8505473c79ab6831d6272a1adff68a42cd102e9992e60b2f8925df01927/layer.tar 876456b964239fb297770341ec7e4c2630e42b64b7bbad5112becb1bd2c72795  9fbc75679caed833594370d2effbdbba4e09eb6ee7a87f9d2e94b41627d56831/layer.tar 9a8f339aeebe1e8bcef322376e1274360653fb802abd4b94c69ea45a54f71a2b  2daafd635a629218204652bd3b10ddd23ae5e33abe1ebc3c26c01103e33369de/layer.tar
   | 
 
https://www.huweihuang.com/article/docker/docker-commands-principle/
如果你要持久化一个镜像,可以使用 docker save 指令
它与 docker export 的区别在于其保留了所有元数据和历史层
另外 docker export 用于容器,而不是镜像
docker inspect 用于查看镜像最顶层的 metadata
docker images -a 该指令用作列出镜像的所有镜像层。镜像层的排序以每个顶层镜像 ID 为首,依次列出每个镜像下的所有镜像层
docker history 查看该镜像 ID 下的所有历史镜像
Summary
对比发现,其实在 Image Tar Archive 中,layer 的 parent-child 关系实际上就是定义于镜像 Config file 中的 rootfs.diff_ids 顺序
[0] <- [1] <- [2] <- …
以 nginx:latest 为例
- ef68f6734aa485edf13a8509fe60e4272428deaf63f446a441b79d47fc5d17d3 (base layer)
 
- 876456b964239fb297770341ec7e4c2630e42b64b7bbad5112becb1bd2c72795
 
- 9a8f339aeebe1e8bcef322376e1274360653fb802abd4b94c69ea45a54f71a2b
 
- …
 
这下就恍然大悟了