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 JSONapplication/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提供了容器镜像的配置和镜像层的信息:
{
"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
: 其代表了文件的类型,详情看上方的mediaTypesize
:对象的字节大小。存在此字段,以便客户端在验证之前具有预期的内容大小。如果检索到的内容的长度与指定的长度不匹配,则不应信任该内容。digest
:代表了一个文件的sha256的哈希校验值。其实就是对一个HTTP请求的返回结果进行sha256。
layers
: 包含了所有所有镜像层mediaType
:引用对象的MIME类型。通常应该是application/vnd.docker.image.rootfs.diff.tar.gzip
size
:对象的字节大小。存在此字段,以便客户端在验证之前具有预期的内容大小。如果检索到的内容的长度与指定的长度不匹配,则不应信任该内容。digest
:代表了镜像层的sha256的哈希校验值。在下面的演示中可以明确的看到
Manifest List
我们都知道镜像有amd64
、arm
、ppc64le
等架构的镜像,而且还会区分操作系统,但是我们在拉去镜像的时候并没有标明拉去amd64
还是arm64
的已经linux
,这就是靠manifest list文件来实现的。
在我们拉去镜像的时候,docker引擎会先去获取Manifest List文件,查看有没有符合CPU架构和OS等要求的镜像,然后拉去相应的镜像。
Ubuntu
镜像的manifest list
文件:
{
"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
# 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
<realm>
替换为上个请求Www-Authenticate
返回的realm的值<service>
替换为上个请求Www-Authenticate
返回的service的值repository:
后面替换为 镜像的仓库/镜像名称:pull
下面的操作以library/ubuntu:latest
为例
# 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
# 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
# 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的配置信息
# 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我做了格式化处理。
获取镜像层的信息
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