docker - docker image layer ids是如何派生的
问题描述
试图了解 docker 镜像层 id 是如何得出的。
在基于 linux 的 VM 上,我拉取了一个 ubuntu 20.04 映像,如下所示。
码头工人拉ubuntu:20.04
然后我将其保存为 tar 文件,然后将其解压缩。
码头工人保存 ubuntu:20.04 > ubuntu2004.tar
tar -xvf ubuntu2004.tar
我已经将一个文件夹安装到我的虚拟机,所以现在我在我的 Windows 机器上看到了提取的 tar,如下所示。
您可能知道 4 个文件夹包含图像的 4 层。看起来很长的文件夹名称是图层的 ID。在这些文件夹中,我们可以看到一个 json 文本文件,它有一个 json 对象。此 Json 对象也具有相同的图层 ID。所以 id 是 1c87ad44cc6b364480a5340ab1050b8dfb1691ed2abc85a1dbc3ee2fb5f2cf06
问题:这些 id 是如何获得的?
下面总结一下我在这方面所做的研究。
- 我读过的一篇文章说它们是随机生成的。
用于存储层内容的 diff 目录现在以随机生成的“缓存 ID”命名,Docker 引擎维护层与其缓存 ID 之间的链接,以便知道在磁盘上的何处定位层的内容。
我已经启动了多个虚拟机,提取了相同的 ubuntu:20.04 映像,然后提取到最终发现层 ID 完全相同。所以我得出结论,我的主机 VM 上的 docker 引擎一定不能随机生成这些 id。它必须要么使用一些逻辑来生成这些 ID。或者从中提取的存储库必须已经具有这些 ID。
Jessica G在这里深入研究了 docker 层并说了同样的话,即层 id 是随机生成的。
随着每一步,所创建的层都由其随机生成的 ID 列出。
- 在我遇到的这篇文章中,描述了chainid。首先,我能够按照那里的描述正确评估 imageId 和 diffids。现在为chainIds。对于底层,它表示链 id 与 diff id 相同。
对于底层:ChainID(layer0) = DiffID(layer0)
对于其他层:ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))
我观察到,对于任何层,id 都不同于 diff id。我是我在这里错过了一些东西。或者这篇文章可能已经过时了。
- Graham Jenson在这篇文章中总结道“文件名和文件夹结构无关紧要”。滚动到最后,你会看到。
所以到目前为止,我无法了解 docker 引擎是如何生成 id 的。还是推送的时候在repository生成,docker引擎拉取原样?我查看了此处描述的Moby 项目的shell 脚本。它将层的 id 生成为图像层 sha 的 sha256。首先获取layer.tar文件的sha256。我再次猜测 sha 是从那个 sha 中获得的,并用作图层的 id。但是这里的问题是这个层 id 与我提取后发现的不匹配。
任何指向正确方向的指针都将不胜感激。
解决方案
这有点解开,因为没有一个 id。首先,我建议查看OCI 规范,因为它介绍了图像清单是什么、配置和各个层。这就是您在注册表中看到的内容。以我拉下的 nginx 镜像为例,让我们来看看这些。
首先是 docker manifest 列表,或 OCI 索引:
$ regctl manifest get --list localhost:5000/library/nginx --format '{{jsonPretty .}}'
{
"manifests": [
{
"digest": "sha256:7250923ba3543110040462388756ef099331822c6172a050b12c7a38361ea46f",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 1570
},
{
"digest": "sha256:bb1416167bc0274d8ad2eadaef292880f59a9fa67dd3dd2149a48f9ab6f3bb79",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v5"
},
"size": 1570
},
{
"digest": "sha256:28511266c47574675169b06eddb33c759dd6b7964b87fc4b66460e24e20fdb92",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
},
"size": 1570
},
{
"digest": "sha256:bf6ac873f0bc7e0a3454ffea4ecf93145c712508a1ca4f125c82a004f5d798a5",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
"size": 1570
},
{
"digest": "sha256:387da9849102b73c06e645a8f0f40c72fae755f20d33391596041a4dcf8284a9",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "386",
"os": "linux"
},
"size": 1570
},
{
"digest": "sha256:44b406885395b1ded51fd3e2715de09f581fdaa3b8c43837bdc4f179dd7e91e8",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "mips64le",
"os": "linux"
},
"size": 1570
},
{
"digest": "sha256:1312ed2db68926470e224d61d7a9a6b77b9dc8061c6b71f0a7f634e184d7aa2a",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "ppc64le",
"os": "linux"
},
"size": 1570
},
{
"digest": "sha256:8ce8b5ec5634ff03911fb9d2548e9d112c79274de1a6d7192f2270b0d80e4d25",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "s390x",
"os": "linux"
},
"size": 1570
}
],
"mediaType": "application\/vnd.docker.distribution.manifest.list.v2+json",
"schemaVersion": 2
}
在那里,您可以看到指向此图像中包含的每个平台的每个清单的指针。此清单列表本身有一个摘要,因此如果您正在寻找图像摘要,请意识到可能有两个,一个用于索引,另一个用于您的平台特定图像:
$ docker image inspect localhost:5000/library/nginx
[
{
"Id": "sha256:87a94228f133e2da99cb16d653cd1373c5b4e8689956386c1c12b60a20421a02",
"RepoTags": [
"nginx:latest",
"localhost:5000/library/nginx:latest"
],
"RepoDigests": [
"nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36",
"localhost:5000/library/nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36"
],
...
$ regctl manifest get --list localhost:5000/library/nginx
Name: localhost:5000/library/nginx
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36
Manifests:
Name: localhost:5000/library/nginx@sha256:7250923ba3543110040462388756ef099331822c6172a050b12c7a38361ea46f
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/amd64
...
$ regctl manifest get --list localhost:5000/library/nginx \
--format raw-body | sha256sum
644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36 -
镜像本身是由一个配置和一个层数组组成的,它们在注册表中存储为 blob,这里的所有内容都是内容可寻址存储,您拉取的内容的 sha256sum 与您拉取的内容的名称相同.
$ regctl manifest get localhost:5000/library/nginx@sha256:7250923ba3543110040462388756ef099331822c6172a050b12c7a38361ea46f
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 7731,
"digest": "sha256:87a94228f133e2da99cb16d653cd1373c5b4e8689956386c1c12b60a20421a02"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 27139510,
"digest": "sha256:b380bbd43752f83945df8b5d1074fef8dd044820e7d3aef33b655a2483e030c7"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 26638539,
"digest": "sha256:fca7e12d1754baddbd07178dd1693c726e9d792c0c9659208e3f4b474dc41a7c"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 602,
"digest": "sha256:745ab57616cb3c803b3a00c3bd46fd0d94762bd5b9446eadc877cb7400fb6c11"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 894,
"digest": "sha256:a4723e260b6fedec963910b3ae53e939fd58cbad8232258576ba26765cdcf522"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 666,
"digest": "sha256:1c84ebdff6819c01d0dc43a59ee391cc2cb14f7aba20cac0af1b04fb78652fc9"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 1394,
"digest": "sha256:858292fd2e56e240ab472db6e9fabd5fd390486660978fcf8d65a06a04c00971"
}
]
}
$ regctl manifest get \
localhost:5000/library/nginx@sha256:7250923ba3543110040462388756ef099331822c6172a050b12c7a38361ea46f \
--format raw-body | sha256sum
7250923ba3543110040462388756ef099331822c6172a050b12c7a38361ea46f -
层本身是 tar+gz blob,您可以检查它们,正如您所期望的,它们是相同的内容可寻址存储:
$ regctl blob get \
localhost:5000/library/nginx sha256:b380bbd43752f83945df8b5d1074fef8dd044820e7d3aef33b655a2483e030c7 \
| tar -tvzf - | head
drwxr-xr-x 0/0 0 2021-10-10 20:00 bin/
-rwxr-xr-x 0/0 1168776 2019-04-18 00:12 bin/bash
-rwxr-xr-x 0/0 43744 2019-02-28 10:30 bin/cat
-rwxr-xr-x 0/0 64320 2019-02-28 10:30 bin/chgrp
-rwxr-xr-x 0/0 64288 2019-02-28 10:30 bin/chmod
-rwxr-xr-x 0/0 72512 2019-02-28 10:30 bin/chown
-rwxr-xr-x 0/0 146880 2019-02-28 10:30 bin/cp
-rwxr-xr-x 0/0 121464 2019-01-17 14:08 bin/dash
-rwxr-xr-x 0/0 109408 2019-02-28 10:30 bin/date
-rwxr-xr-x 0/0 76712 2019-02-28 10:30 bin/dd
$ regctl blob get \
localhost:5000/library/nginx sha256:b380bbd43752f83945df8b5d1074fef8dd044820e7d3aef33b655a2483e030c7 \
| sha256sum
b380bbd43752f83945df8b5d1074fef8dd044820e7d3aef33b655a2483e030c7 -
现在查看图像检查时,这些 id 将不匹配:
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:e81bff2725dbc0bf2003db10272fef362e882eb96353055778a66cda430cf81b",
"sha256:43f4e41372e42dd32309f6a7bdce03cf2d65b3ca34b1036be946d53c35b503ab",
"sha256:788e89a4d186f3614bfa74254524bc2e2c6de103698aeb1cb044f8e8339a90bd",
"sha256:f8e880dfc4ef19e78853c3f132166a4760a220c5ad15b9ee03b22da9c490ae3b",
"sha256:f7e00b807643e512b85ef8c9f5244667c337c314fa29572206c1b0f3ae7bf122",
"sha256:9959a332cf6e41253a9cd0c715fa74b01db1621b4d16f98f4155a2ed5365da4a"
]
},
那是因为拉取镜像后主机上的内容可寻址存储是基于解压层的:
$ regctl blob get \
localhost:5000/library/nginx sha256:b380bbd43752f83945df8b5d1074fef8dd044820e7d3aef33b655a2483e030c7 \
| gunzip - | sha256sum
e81bff2725dbc0bf2003db10272fef362e882eb96353055778a66cda430cf81b -
最后,还有两个更复杂的部分,docker 中的层目录名称和 save 中的文件名。查看代码,图层目录名称是随机生成的唯一 ID 。并且保存文件中的文件名基于一些v1 diff id,用于使用该点之前的层创建的图像配置以及在该配置上计算的摘要。这样做只是为了支持真正旧版本的 docker,并且您可以轻松创建具有不同文件名的保存文件,docker 只关心manifest.json
. 甚至可以将OCI 布局定义与 docker save 格式混合并让 docker 加载图像:
$ regctl image export \
localhost:5000/regclient/regctl:edge@sha256:76c041ed3bf9e4186327d2d63c9c597c648a7fbc07642d63f223c899e29f8d89 \
>export.tar
$ tar -tvf export.tar
-rw-r--r-- 0/0 30 1969-12-31 19:00 oci-layout
-rw-r--r-- 0/0 389 1969-12-31 19:00 index.json
-rw-r--r-- 0/0 1435 1969-12-31 19:00 manifest.json
drwxr-xr-x 0/0 0 1969-12-31 19:00 blobs/sha256
-rw-r--r-- 0/0 1152 1969-12-31 19:00 blobs/sha256/76c041ed3bf9e4186327d2d63c9c597c648a7fbc07642d63f223c899e29f8d89
-rw-r--r-- 0/0 3021 1969-12-31 19:00 blobs/sha256/bd45abf90c52fb2c13499bbd7bb845c106e0d5b924e65dd26c8e8e2de25e54f6
-rw-r--r-- 0/0 941 1969-12-31 19:00 blobs/sha256/f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14
-rw-r--r-- 0/0 122412 1969-12-31 19:00 blobs/sha256/92365f35877078c3e558e9a66ac083fe9a8d44bdb3150bdac058380054b05972
-rw-r--r-- 0/0 146 1969-12-31 19:00 blobs/sha256/fa98de7a23a1c3debba4398c982decfd8b31bcfad1ac6e5e7d800375cefbd42f
-rw-r--r-- 0/0 3536065 1969-12-31 19:00 blobs/sha256/24bfb25bb9426e2205338ab1480992e9a09bd6d2d9f248d3768f4feb12ad7d9e
$ tar -xvf export.tar manifest.json
manifest.json
$ cat manifest.json | jq .
[
{
"Config": "blobs/sha256/bd45abf90c52fb2c13499bbd7bb845c106e0d5b924e65dd26c8e8e2de25e54f6",
"RepoTags": [
"localhost:5000/regclient/regctl:edge"
],
"Layers": [
"blobs/sha256/f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14",
"blobs/sha256/92365f35877078c3e558e9a66ac083fe9a8d44bdb3150bdac058380054b05972",
"blobs/sha256/fa98de7a23a1c3debba4398c982decfd8b31bcfad1ac6e5e7d800375cefbd42f",
"blobs/sha256/24bfb25bb9426e2205338ab1480992e9a09bd6d2d9f248d3768f4feb12ad7d9e"
],
"LayerSources": {
"sha256:24bfb25bb9426e2205338ab1480992e9a09bd6d2d9f248d3768f4feb12ad7d9e": {
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:24bfb25bb9426e2205338ab1480992e9a09bd6d2d9f248d3768f4feb12ad7d9e",
"size": 3536065
},
"sha256:92365f35877078c3e558e9a66ac083fe9a8d44bdb3150bdac058380054b05972": {
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:92365f35877078c3e558e9a66ac083fe9a8d44bdb3150bdac058380054b05972",
"size": 122412
},
"sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14": {
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14",
"size": 941
},
"sha256:fa98de7a23a1c3debba4398c982decfd8b31bcfad1ac6e5e7d800375cefbd42f": {
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:fa98de7a23a1c3debba4398c982decfd8b31bcfad1ac6e5e7d800375cefbd42f",
"size": 146
}
}
}
]
$ docker load <export.tar
132414a5f587: Loading layer [==================================================>] 941B/941B
482fa2862396: Loading layer [==================================================>] 122.4kB/122.4kB
8e47dcad786a: Loading layer [==================================================>] 146B/146B
65131f050950: Loading layer [==================================================>] 3.536MB/3.536MB
The image localhost:5000/regclient/regctl:edge already exists, renaming the old one with ID sha256:5ec718d68e782ea7df08e19af7b84de3c1d34b81fabe48c89a43c3439c9063dd to empty string
Loaded image: localhost:5000/regclient/regctl:edge
(请注意,我在最后一个示例中切换到不同的图像,因为 docker 引擎已经具有 nginx 示例的层。)
推荐阅读
- python - Python 格式不能与浮点数一起正常工作
- c++ - 最小化递归函数中的变量副本
- python - 如何在 python 中使用 natsort 对文件夹名称进行排序?
- regex - 'rec-01-' 的正则表达式以在 Jenkins 视图中选择作业
- html - W3C HTML 验证错误:“Stray end tag”和“Start tag seen but an element of same type is already open”
- user-interface - 如何在 Linux 上将 ClearCase 的图形差异工具设置为非 root?
- java - 我得到错误的输出,我也需要一个简化的解决方案
- mysql - 计算 MySQL 中重叠日期范围的最大数量
- python - 将用户输入字符串拆分为每个字符的列表
- sql - 动态 SQL 将执行结果存储在一个变量中,并将该结果连接起来形成一个完整的查询