Docker执行pull做了什么

Docker manifest

mediaType

在下面后面的文章中需要注意到mediaType对应的值,其代表了文件的类型,在规范中定义了以下类型:

  • application/vnd.docker.distribution.manifest.v1+json: 代表了第一个版本的manifest格式,已经出现了第二个版本了(schemaVersion = 1)
  • application/vnd.docker.distribution.manifest.v2+json: 代表了新版本的manifest格式 (schemaVersion = 2)
  • application/vnd.docker.distribution.manifest.list.v2+json: Manifest list,也就是上方示例的manifest list文件
  • application/vnd.docker.container.image.v1+json: Container config JSON
  • application/vnd.docker.image.rootfs.diff.tar.gzip: “Layer”, as a gzipped tar,代表了镜像层的压缩类型
  • application/vnd.docker.image.rootfs.foreign.diff.tar.gzip: “Layer”, as a gzipped tar that should never be pushed,
  • application/vnd.docker.plugin.v1+json: Plugin config JSON

Image Manifest

Image Manifest提供了容器镜像的配置和镜像层的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"config": {
"digest": "sha256:775349758637aff77bf85e2ff0597e86e3e859183ef0baba8b3e8fc8d3cba51c",
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 3411
},
"layers": [
{
"digest": "sha256:7ddbc47eeb70dc7f08e410a6667948b87ff3883024eb41478b44ef9a81bf400c",
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 26688847
},
{
"digest": "sha256:c1bbdc448b7263673926b8fe2e88491e5083a8b4b06ddfabf311f2fc5f27e2ff",
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 35362
},
{
"digest": "sha256:8c3b70e3904492c753652606df4726430426f42ea56e06ea924d6fea7ae162a1",
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 845
},
{
"digest": "sha256:45d437916d5781043432f2d72608049dcf74ddbd27daa01a25fa63c8f1b9adc4",
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 162
}
],
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"schemaVersion": 2
}

说明:

  • config:包含了镜像配置信息
    • mediaType: 其代表了文件的类型,详情看上方的mediaType
    • size:对象的字节大小。存在此字段,以便客户端在验证之前具有预期的内容大小。如果检索到的内容的长度与指定的长度不匹配,则不应信任该内容。
    • digest:代表了一个文件的sha256的哈希校验值。其实就是对一个HTTP请求的返回结果进行sha256。
  • layers: 包含了所有所有镜像层
    • mediaType:引用对象的MIME类型。通常应该是application/vnd.docker.image.rootfs.diff.tar.gzip
    • size:对象的字节大小。存在此字段,以便客户端在验证之前具有预期的内容大小。如果检索到的内容的长度与指定的长度不匹配,则不应信任该内容。
    • digest:代表了镜像层的sha256的哈希校验值。在下面的演示中可以明确的看到

Manifest List

我们都知道镜像有amd64armppc64le等架构的镜像,而且还会区分操作系统,但是我们在拉去镜像的时候并没有标明拉去amd64还是arm64的已经linux,这就是靠manifest list文件来实现的。
在我们拉去镜像的时候,docker引擎会先去获取Manifest List文件,查看有没有符合CPU架构和OS等要求的镜像,然后拉去相应的镜像。

Ubuntu镜像的manifest list文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{
"manifests": [
{
"digest": "sha256:134c7fe821b9d359490cd009ce7ca322453f4f2d018623f849e580a89a685e5d",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 1152
},
{
"digest": "sha256:349e3988c0241304b39218794b8263325f7dc517317e00be37d43c3bdda9449b",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
},
"size": 1152
},
{
"digest": "sha256:a8878539376d57d89dc7e8034dd8ecb16ebce4693da48b0d8ea2890efd097848",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
"size": 1152
},
{
"digest": "sha256:bcf9d02754f659706860d04fd261207db010db96e782e2eb5d5bbd7168388b89",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "386",
"os": "linux"
},
"size": 1152
},
{
"digest": "sha256:746e11f60338e1413daa698cdc052f5428fdbddacefb4bae23e4b6ae0c8231e5",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "ppc64le",
"os": "linux"
},
"size": 1152
},
{
"digest": "sha256:391556555751770ffbcebbce4ed539454cea660c0be0a726f801c96f353a22e0",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "s390x",
"os": "linux"
},
"size": 1152
}
],
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"schemaVersion": 2
}

在上方示例中,manifests列表中所有子项都代表了一个不同架构的镜像,每个镜像对应了上面讲的Image Manifest

platform描述了清单中的图像所运行的平台。有效的操作系统。
其他选项说明:

  • digest:代表了一个文件的sha256的哈希校验值。其实该值对应的就是上方说的Image Manifest整个文件的校验值。
  • size:对象字节大小,以便客户端在验证之前有一个预期的大小。
  • platform->architecture:描述了该镜像的CPU架构。
  • platform->os:描述了该镜像的操作系统。

建议去下面的官网参考链接简单的过一下。

参考:

拉取镜像的全部步骤

下面的例子以ubuntu:latest的镜像来演示

访问docker的公共仓库,会返回401认证错误,Www-Authenticate头会返回一个获取token的地址realm,已经service的字符串为registry.docker.io

1
2
3
4
5
6
7
8
9
10
11
12
# curl -i https://registry-1.docker.io/v2/
HTTP/1.1 200 Connection established

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io"
Date: Wed, 11 Dec 2019 07:35:02 GMT
Content-Length: 87
Strict-Transport-Security: max-age=31536000

{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":null}]}

访问上一步请求的realm地址,构造一个URL
<realm>?service=<service>&scope=repository:library/ubuntu:pull

  1. <realm>替换为上个请求Www-Authenticate返回的realm的值
  2. <service>替换为上个请求Www-Authenticate返回的service的值
  3. repository: 后面替换为 镜像的仓库/镜像名称:pull

下面的操作以library/ubuntu:latest为例

1
2
# curl 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ubuntu:pull'
{"token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlDK2pDQ0FwK2dBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakJHTVVRd1FnWURWUVFERXpzeVYwNVpPbFZMUzFJNlJFMUVVanBTU1U5Rk9reEhOa0U2UTFWWVZEcE5SbFZNT2tZelNFVTZOVkF5VlRwTFNqTkdPa05CTmxrNlNrbEVVVEFlRncweE9UQXhNVEl3TURJeU5EVmFGdzB5TURBeE1USXdNREl5TkRWYU1FWXhSREJDQmdOVkJBTVRPMUpMTkZNNlMwRkxVVHBEV0RWRk9rRTJSMVE2VTBwTVR6cFFNbEpMT2tOWlZVUTZTMEpEU0RwWFNVeE1Pa3hUU2xrNldscFFVVHBaVWxsRU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcjY2bXkveXpHN21VUzF3eFQ3dFplS2pqRzcvNnBwZFNMY3JCcko5VytwcndzMGtIUDVwUHRkMUpkcFdEWU1OZWdqQXhpUWtRUUNvd25IUnN2ODVUalBUdE5wUkdKVTRkeHJkeXBvWGc4TVhYUEUzL2lRbHhPS2VNU0prNlRKbG5wNGFtWVBHQlhuQXRoQzJtTlR5ak1zdFh2ZmNWN3VFYWpRcnlOVUcyUVdXQ1k1Ujl0a2k5ZG54Z3dCSEF6bG8wTzJCczFmcm5JbmJxaCtic3ZSZ1FxU3BrMWhxYnhSU3AyRlNrL2tBL1gyeUFxZzJQSUJxWFFMaTVQQ3krWERYZElJczV6VG9ZbWJUK0pmbnZaMzRLcG5mSkpNalpIRW4xUVJtQldOZXJZcVdtNVhkQVhUMUJrQU9aditMNFVwSTk3NFZFZ2ppY1JINVdBeWV4b1BFclRRSURBUUFCbzRHeU1JR3ZNQTRHQTFVZER3RUIvd1FFQXdJSGdEQVBCZ05WSFNVRUNEQUdCZ1JWSFNVQU1FUUdBMVVkRGdROUJEdFNTelJUT2t0QlMxRTZRMWcxUlRwQk5rZFVPbE5LVEU4NlVESlNTenBEV1ZWRU9rdENRMGc2VjBsTVREcE1VMHBaT2xwYVVGRTZXVkpaUkRCR0JnTlZIU01FUHpBOWdEc3lWMDVaT2xWTFMxSTZSRTFFVWpwU1NVOUZPa3hITmtFNlExVllWRHBOUmxWTU9rWXpTRVU2TlZBeVZUcExTak5HT2tOQk5sazZTa2xFVVRBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQXFOSXEwMFdZTmM5Z2tDZGdSUzRSWUhtNTRZcDBTa05Rd2lyMm5hSWtGd3dDSVFEMjlYdUl5TmpTa1cvWmpQaFlWWFB6QW9TNFVkRXNvUUhyUVZHMDd1N3ZsUT09Il19.eyJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6ImxpYnJhcnkvdWJ1bnR1IiwiYWN0aW9ucyI6WyJwdWxsIl19XSwiYXVkIjoicmVnaXN0cnkuZG9ja2VyLmlvIiwiZXhwIjoxNTc2MDUxNzYyLCJpYXQiOjE1NzYwNTE0NjIsImlzcyI6ImF1dGguZG9ja2VyLmlvIiwianRpIjoiRllrY3lBWVFGeUdNNXhtRmI2cjEiLCJuYmYiOjE1NzYwNTExNjIsInN1YiI6IiJ9.I_sr5aBFEluPyz8JKDnkgCQ3jKrnifNvBg1OD4Ny6PcKwqwCaNzbB3LWII1SrL3LvYp3ztAGG_sEAgzb8LbkCXbd51xzk1FmCKwV6rbd2TZ4AWmfE8OHaBvHuTR0IcvX2PBUC1VuE2LLTsr2Dt0leq3s4hi5-3A_8_XSmau6XRLtaEImhsR3HJUGPzDbupq5iL4LYUle-lW75wBm-QtANjjF9qsnjNMFltlij8XvWe0ADv-bYtGA_bGUAz_PVu2IIenNSsxMiuBzMNGTyXnCepBgAqXuoF8gFJHgZ0Cli2YakBDNsU9BA5STvtDxaLXQaUIncjo2KfJZtl19TVLOog","access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlDK2pDQ0FwK2dBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakJHTVVRd1FnWURWUVFERXpzeVYwNVpPbFZMUzFJNlJFMUVVanBTU1U5Rk9reEhOa0U2UTFWWVZEcE5SbFZNT2tZelNFVTZOVkF5VlRwTFNqTkdPa05CTmxrNlNrbEVVVEFlRncweE9UQXhNVEl3TURJeU5EVmFGdzB5TURBeE1USXdNREl5TkRWYU1FWXhSREJDQmdOVkJBTVRPMUpMTkZNNlMwRkxVVHBEV0RWRk9rRTJSMVE2VTBwTVR6cFFNbEpMT2tOWlZVUTZTMEpEU0RwWFNVeE1Pa3hUU2xrNldscFFVVHBaVWxsRU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcjY2bXkveXpHN21VUzF3eFQ3dFplS2pqRzcvNnBwZFNMY3JCcko5VytwcndzMGtIUDVwUHRkMUpkcFdEWU1OZWdqQXhpUWtRUUNvd25IUnN2ODVUalBUdE5wUkdKVTRkeHJkeXBvWGc4TVhYUEUzL2lRbHhPS2VNU0prNlRKbG5wNGFtWVBHQlhuQXRoQzJtTlR5ak1zdFh2ZmNWN3VFYWpRcnlOVUcyUVdXQ1k1Ujl0a2k5ZG54Z3dCSEF6bG8wTzJCczFmcm5JbmJxaCtic3ZSZ1FxU3BrMWhxYnhSU3AyRlNrL2tBL1gyeUFxZzJQSUJxWFFMaTVQQ3krWERYZElJczV6VG9ZbWJUK0pmbnZaMzRLcG5mSkpNalpIRW4xUVJtQldOZXJZcVdtNVhkQVhUMUJrQU9aditMNFVwSTk3NFZFZ2ppY1JINVdBeWV4b1BFclRRSURBUUFCbzRHeU1JR3ZNQTRHQTFVZER3RUIvd1FFQXdJSGdEQVBCZ05WSFNVRUNEQUdCZ1JWSFNVQU1FUUdBMVVkRGdROUJEdFNTelJUT2t0QlMxRTZRMWcxUlRwQk5rZFVPbE5LVEU4NlVESlNTenBEV1ZWRU9rdENRMGc2VjBsTVREcE1VMHBaT2xwYVVGRTZXVkpaUkRCR0JnTlZIU01FUHpBOWdEc3lWMDVaT2xWTFMxSTZSRTFFVWpwU1NVOUZPa3hITmtFNlExVllWRHBOUmxWTU9rWXpTRVU2TlZBeVZUcExTak5HT2tOQk5sazZTa2xFVVRBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQXFOSXEwMFdZTmM5Z2tDZGdSUzRSWUhtNTRZcDBTa05Rd2lyMm5hSWtGd3dDSVFEMjlYdUl5TmpTa1cvWmpQaFlWWFB6QW9TNFVkRXNvUUhyUVZHMDd1N3ZsUT09Il19.eyJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6ImxpYnJhcnkvdWJ1bnR1IiwiYWN0aW9ucyI6WyJwdWxsIl19XSwiYXVkIjoicmVnaXN0cnkuZG9ja2VyLmlvIiwiZXhwIjoxNTc2MDUxNzYyLCJpYXQiOjE1NzYwNTE0NjIsImlzcyI6ImF1dGguZG9ja2VyLmlvIiwianRpIjoiRllrY3lBWVFGeUdNNXhtRmI2cjEiLCJuYmYiOjE1NzYwNTExNjIsInN1YiI6IiJ9.I_sr5aBFEluPyz8JKDnkgCQ3jKrnifNvBg1OD4Ny6PcKwqwCaNzbB3LWII1SrL3LvYp3ztAGG_sEAgzb8LbkCXbd51xzk1FmCKwV6rbd2TZ4AWmfE8OHaBvHuTR0IcvX2PBUC1VuE2LLTsr2Dt0leq3s4hi5-3A_8_XSmau6XRLtaEImhsR3HJUGPzDbupq5iL4LYUle-lW75wBm-QtANjjF9qsnjNMFltlij8XvWe0ADv-bYtGA_bGUAz_PVu2IIenNSsxMiuBzMNGTyXnCepBgAqXuoF8gFJHgZ0Cli2YakBDNsU9BA5STvtDxaLXQaUIncjo2KfJZtl19TVLOog","expires_in":300,"issued_at":"2019-12-11T08:04:22.207624154Z"}

可以看到上面返回一大串json格式的字符出,只需要保留token对应的值即可,下面的所有请求都要在请求头中带上token对应的值

下面开始获取Manifest List文件

其实在操作时这一步是可以省略的,但是为了更好的理解对应关系,建议还是看下比较好!

获取Manifest List文件需要在Accept中设置mediaType,正是上面提过的mediaType,需要设置为application/vnd.docker.distribution.manifest.list.v2+json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# head_auth="Authorization: Bearer ${TOKEN}"                                           # 注意替换TOKEN的内容
# head_accept='Accept: application/vnd.docker.distribution.manifest.list.v2+json'
# curl -i -H "$head_auth" -H "$head_accept" 'https://registry-1.docker.io/v2/library/ubuntu/manifests/latest'
HTTP/1.1 200 Connection Established

HTTP/1.1 200 OK
Content-Length: 1418
Content-Type: application/vnd.docker.distribution.manifest.list.v2+json
Docker-Content-Digest: sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d"
Date: Wed, 11 Dec 2019 13:42:59 GMT
Strict-Transport-Security: max-age=31536000

{
"manifests": [
{
"digest": "sha256:134c7fe821b9d359490cd009ce7ca322453f4f2d018623f849e580a89a685e5d",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 1152
},
{
"digest": "sha256:349e3988c0241304b39218794b8263325f7dc517317e00be37d43c3bdda9449b",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
},
"size": 1152
},
{
"digest": "sha256:a8878539376d57d89dc7e8034dd8ecb16ebce4693da48b0d8ea2890efd097848",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
"size": 1152
},
{
"digest": "sha256:bcf9d02754f659706860d04fd261207db010db96e782e2eb5d5bbd7168388b89",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "386",
"os": "linux"
},
"size": 1152
},
{
"digest": "sha256:746e11f60338e1413daa698cdc052f5428fdbddacefb4bae23e4b6ae0c8231e5",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "ppc64le",
"os": "linux"
},
"size": 1152
},
{
"digest": "sha256:391556555751770ffbcebbce4ed539454cea660c0be0a726f801c96f353a22e0",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "s390x",
"os": "linux"
},
"size": 1152
}
],
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"schemaVersion": 2
}

注意:为了方便观看,上方返回的json我做了格式化处理。

说明:

  • 上方URL中的library/ubuntu替换为你的镜像仓库和镜像名称。
  • 上方URL中的latest为镜像的tag,替换成相应的即可。
  • 返回结果的Header中的Docker-Content-Digest,正是ubuntu:latest的Digest的值,那么这个值是从哪来的呢?正是本次请求返回内容的sha256的校验和。

其他该文件的具体内容也就不解释了,上方已经解释过了,这里需要注意一下amd64的digest,下面我们请求image manifest的返回的内容的sha256的校验和正是这个值。

获取Image Manifest

请求Image Manifest内容和请求Manifest的方式是一样的,只需要修改mediaType的类型为application/vnd.docker.distribution.manifest.v2+json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# head_accept='Accept: application/vnd.docker.distribution.manifest.v2+json'
# head_auth="Authorization: Bearer ${TOKEN}" # 注意替换TOKEN的内容
# curl -i -H "$head_auth" -H "$head_accept" 'https://registry-1.docker.io/v2/library/ubuntu/manifests/latest'
HTTP/1.1 200 Connection Established

HTTP/1.1 200 OK
Content-Length: 1152
Content-Type: application/vnd.docker.distribution.manifest.v2+json
Docker-Content-Digest: sha256:134c7fe821b9d359490cd009ce7ca322453f4f2d018623f849e580a89a685e5d
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:134c7fe821b9d359490cd009ce7ca322453f4f2d018623f849e580a89a685e5d"
Date: Wed, 11 Dec 2019 13:54:05 GMT
Strict-Transport-Security: max-age=31536000

{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 3411,
"digest": "sha256:775349758637aff77bf85e2ff0597e86e3e859183ef0baba8b3e8fc8d3cba51c"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 26688847,
"digest": "sha256:7ddbc47eeb70dc7f08e410a6667948b87ff3883024eb41478b44ef9a81bf400c"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 35362,
"digest": "sha256:c1bbdc448b7263673926b8fe2e88491e5083a8b4b06ddfabf311f2fc5f27e2ff"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 845,
"digest": "sha256:8c3b70e3904492c753652606df4726430426f42ea56e06ea924d6fea7ae162a1"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 162,
"digest": "sha256:45d437916d5781043432f2d72608049dcf74ddbd27daa01a25fa63c8f1b9adc4"
}
]
}

说明:

  • 上方URL中的library/ubuntu替换为你的镜像仓库和镜像名称。
  • 上方URL中的latest为镜像的tag,替换成相应的即可。
  • 可以看下Header中的Docker-Content-Digest对应的正是上个Manifest List文件中amd64对应的digest,该值也正是本次请求context的sha256的校验和。
  • 这里可以记住config下的digest,这个digest对应的正式存放镜像信息文件的sha256的校验和。

根据digest我们可以确定,在请求的URL中指明CPU的架构、OS等信息,但是仓库还是返回给了我们正确的镜像。

获取Image的配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# head_accept='Accept: application/vnd.docker.distribution.manifest.v2+json'
# head_auth="Authorization: Bearer ${TOKEN}" # 注意替换TOKEN的内容
# curl -i -L -H "$head_auth" -H "$head_accept" "https://registry-1.docker.io/v2/library/ubuntu/blobs/${img_digest}"
HTTP/1.1 200 Connection Established

HTTP/1.1 307 Temporary Redirect
Content-Type: application/octet-stream
Docker-Distribution-Api-Version: registry/2.0
Location: https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/77/775349758637aff77bf85e2ff0597e86e3e859183ef0baba8b3e8fc8d3cba51c/data?verify=1576077590-L0Qm7evLPvRGJXglsGLJgSjtyhQ%3D
Date: Wed, 11 Dec 2019 14:29:50 GMT
Content-Length: 0
Strict-Transport-Security: max-age=31536000

HTTP/1.1 200 Connection Established

HTTP/1.1 200 OK
Date: Wed, 11 Dec 2019 14:29:52 GMT
Content-Type: application/octet-stream
Content-Length: 3411
Connection: keep-alive
Set-Cookie: __cfduid=d378cc611e9b9c55da04c2a12a78593961576074592; expires=Fri, 10-Jan-20 14:29:52 GMT; path=/; domain=.production.cloudflare.docker.com; HttpOnly; Secure
CF-Ray: 54382738df9545a0-TPE
Accept-Ranges: bytes
Age: 1261208
Cache-Control: public, max-age=14400
ETag: "49915831e8a9bf47e493f67c9deb77d8"
Expires: Wed, 11 Dec 2019 18:29:52 GMT
Last-Modified: Thu, 31 Oct 2019 22:21:44 GMT
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
x-amz-id-2: UvQpRaIldmEaUN9dgURDCf1hv9RN0YE0YXW8znQemYCLDSxURtKfIatkyLfNPV13zKh4svjHA9U=
x-amz-request-id: CD58E96DAD72CD84
x-amz-version-id: UTOzvvgdyPt7amRFsm.T0wMyWYEx0RPE
Server: cloudflare
{
"architecture": "amd64",
"config": {
"ArgsEscaped": true,
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"/bin/bash"
],
"Domainname": "",
"Entrypoint": null,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Hostname": "",
"Image": "sha256:f0caea6f785de71fe8c8b1b276a7094151df6058aa3f22d2902fe6b51f1a7a8f",
"Labels": null,
"OnBuild": null,
"OpenStdin": false,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": null,
"WorkingDir": ""
},
"container": "4df7a03525342ee760076ade1c80bbdd041f236654f624ca581ada54310a1574",
"container_config": {
"ArgsEscaped": true,
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/bash\"]"
],
"Domainname": "",
"Entrypoint": null,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Hostname": "4df7a0352534",
"Image": "sha256:f0caea6f785de71fe8c8b1b276a7094151df6058aa3f22d2902fe6b51f1a7a8f",
"Labels": {},
"OnBuild": null,
"OpenStdin": false,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": null,
"WorkingDir": ""
},
"created": "2019-10-31T22:20:37.714423666Z",
"docker_version": "18.06.1-ce",
"history": [
{
"created": "2019-10-31T22:20:35.371741262Z",
"created_by": "/bin/sh -c #(nop) ADD file:a48a5dc1b9dbfc632f6cf86fe27b770b63f07a115c98c4465dc184e303a4efa1 in / "
},
{
"created": "2019-10-31T22:20:36.173590614Z",
"created_by": "/bin/sh -c [ -z \"$(apt-get indextargets)\" ]"
},
{
"created": "2019-10-31T22:20:36.882756782Z",
"created_by": "/bin/sh -c set -xe \t\t&& echo '#!/bin/sh' > /usr/sbin/policy-rc.d \t&& echo 'exit 101' >> /usr/sbin/policy-rc.d \t&& chmod +x /usr/sbin/policy-rc.d \t\t&& dpkg-divert --local --rename --add /sbin/initctl \t&& cp -a /usr/sbin/policy-rc.d /sbin/initctl \t&& sed -i 's/^exit.*/exit 0/' /sbin/initctl \t\t&& echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \t\t&& echo 'DPkg::Post-Invoke { \"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\"; };' > /etc/apt/apt.conf.d/docker-clean \t&& echo 'APT::Update::Post-Invoke { \"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\"; };' >> /etc/apt/apt.conf.d/docker-clean \t&& echo 'Dir::Cache::pkgcache \"\"; Dir::Cache::srcpkgcache \"\";' >> /etc/apt/apt.conf.d/docker-clean \t\t&& echo 'Acquire::Languages \"none\";' > /etc/apt/apt.conf.d/docker-no-languages \t\t&& echo 'Acquire::GzipIndexes \"true\"; Acquire::CompressionTypes::Order:: \"gz\";' > /etc/apt/apt.conf.d/docker-gzip-indexes \t\t&& echo 'Apt::AutoRemove::SuggestsImportant \"false\";' > /etc/apt/apt.conf.d/docker-autoremove-suggests"
},
{
"created": "2019-10-31T22:20:37.550873398Z",
"created_by": "/bin/sh -c mkdir -p /run/systemd && echo 'docker' > /run/systemd/container"
},
{
"created": "2019-10-31T22:20:37.714423666Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/bash\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"diff_ids": [
"sha256:cc967c529ced563b7746b663d98248bc571afdb3c012019d7f54d6c092793b8b",
"sha256:2c6ac8e5063e35e91ab79dfb7330c6154b82f3a7e4724fb1b4475c0a95dfdd33",
"sha256:6c01b5a53aac53c66f02ea711295c7586061cbe083b110d54dafbeb6cf7636bf",
"sha256:e0b3afb09dc386786d49d6443bdfb20bc74d77dcf68e152db7e5bb36b1cca638"
],
"type": "layers"
}
}

注意:为了方便观看,上方返回的json我做了格式化处理。

获取镜像层的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
HTTP/1.1 200 Connection Established

HTTP/1.1 307 Temporary Redirect
Content-Type: application/octet-stream
Docker-Distribution-Api-Version: registry/2.0
Location: https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/7d/7ddbc47eeb70dc7f08e410a6667948b87ff3883024eb41478b44ef9a81bf400c/data?verify=1576073179-ulfR1ZF4DybCnfmDhXunQSDzKN0%3D
Date: Wed, 11 Dec 2019 13:16:19 GMT
Content-Length: 0
Strict-Transport-Security: max-age=31536000

HTTP/1.1 200 Connection Established

HTTP/1.1 200 OK
Date: Wed, 11 Dec 2019 13:16:20 GMT
Content-Type: application/octet-stream
Content-Length: 26688847
Connection: keep-alive
Set-Cookie: __cfduid=d8c05cfa09534d091566b2dbc1cf57ca51576070180; expires=Fri, 10-Jan-20 13:16:20 GMT; path=/; domain=.production.cloudflare.docker.com; HttpOnly; Secure
CF-Ray: 5437bb871f2545a0-TPE
Accept-Ranges: bytes
Age: 1085759
Cache-Control: public, max-age=14400
ETag: "37579c3e2546a2e0a8e0a605d6c2feb2"
Expires: Wed, 11 Dec 2019 17:16:20 GMT
Last-Modified: Wed, 30 Oct 2019 00:25:34 GMT
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
x-amz-id-2: X5lLL2k44W7TGacV5AVP3mHYcnvCU1I4WEG43mWqQVzjZPEgdmqTV2wITJU+UguBbwm+z/E6i0k=
x-amz-request-id: A4151812AF621C16
x-amz-version-id: kvJ2j8c2kVmMRGKRYdGYsqTm7J__tttP
Server: cloudflare

总结

镜像对应data目录下面的镜像层