容器镜像仓库笔记

Posted on January 11, 2018

1. 镜像层

Docker v1.10 之前

  • image ID是随机生成的,与内容无关。这一方面很容易导致image ID被伪造,也容易引发冲突

  • image与layer没有严格的区别

在v1.10 之后:

  • image与layer是严格区分的。image ID与layer ID是两个不同的对象,生成的算法也不一样,但都是根据内容(content-addressable)生成的

镜像层在客户端和distribution端的不同:

  • 客户端: 存储? 使用hashes of uncompressed data

  • distribution: 存储的layer是压缩文件, 使用 hashes of compressed data

    但是,每个push生成的distribution hashes可能会不一样,因为同一个tar文件,每次压缩生成的文件可能会有区别 ??


2. Distribution 存储分析

标识:

  • IMAGE ID: 本地由Docker根据镜像的描述文件计算的,并用于imagedb的目录名称 SHA256hex(imageConfigJSON)
  • Tag Digest: 同 Docker-Content-Digest 由registry端根据manifest计算而来
  • Layer Digest: Distribution根据layer compressed data计算的,并用于Distribution的存储目录名称
  • Manifest Digest: 同 Docker-Content-Digest
  • layer.DiffID: 本地由Docker根据layer uncompressed data计算的DiffID = SHA256hex(uncompressed layer tar data)。layer.ChainID只用本地,根据layer.DiffID计算,并用于layerdb的目录名称, 本地inspect 后通过 RootFS.Layers可以看到
  • layer.ChainID: TODO
  • layer.cacheID: TODO

客户端拉取镜像:

docker pull localhost:5000/my-ubuntu
Using default tag: latest
latest: Pulling from my-ubuntu
50aff78429b1: Pull complete 这些都是镜像层digest
f6d82e297bce: Pull complete
275abb2c8a6f: Pull complete
9f15a39356d6: Pull complete
fc0342a94c89: Pull complete
Digest: sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663 这是tag digest
Status: Downloaded newer image for localhost:5000/my-ubuntu:latest

客户端查看镜像:

% docker images localhost:5000/my-ubuntu --digests
REPOSITORY                 TAG                 DIGEST(这是Tag Digest)                                                    IMAGE ID            CREATED             SIZE
localhost:5000/my-ubuntu   latest              sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663   00fd29ccc6f1        3 weeks ago         111MB

distribution的存储结构:

  • blobs: 存储实际的layer数据
  • repositories: 存储image/tag相关的信息
├── blobs
│   └── sha256
│       ├── 00
│       │   └── 00fd29ccc6f167fa991580690a00e844664cb2381c74cd14d539e36ca014f043 [IMAGE ID]
│       │       └── data json 文件, image的具体信息
│       ├── 27
│       │   └── 275abb2c8a6f1ce8e67a388a11f3cc014e98b36ff993a6ed1cc7cd6ecb4dd61b
│       │       └── data 二进制层
│       ├── 50
│       │   └── 50aff78429b146489e8a6cb9334d93a6d81d5de2edc4fbf5e2d4d9253625753e
│       │       └── data 二进制层
│       ├── 9f
│       │   └── 9f15a39356d6fc1df0a77012bf1aa2150b683e46be39d1c51bc7a320f913e322
│       │       └── data 二进制层
│       ├── f6
│       │   └── f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f
│       │       └── data 二进制层
│       ├── f8
│       │   └── f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663 [Tag Digest] 指向manifest
│       │       └── data  这个tag digest下的data是一个json文件, 包括层关系, 见下
│       └── fc
│           └── fc0342a94c89e477c821328ccb542e6fb86ce4ef4ebbf1098e85669e051ef0dd
│               └── data 二进制层
└── repositories
    └── my-ubuntu  镜像仓库名
        ├── _layers
        │   └── sha256 以下是各layers的digest, 也包括image digest(客户端的IMAGE ID)
        │       ├── 00fd29ccc6f167fa991580690a00e844664cb2381c74cd14d539e36ca014f043 [IMAGE ID]
        │       │   └── link 内容sha256:加上上面ID
        │       ├── 275abb2c8a6f1ce8e67a388a11f3cc014e98b36ff993a6ed1cc7cd6ecb4dd61b
        │       │   └── link 内容sha256:加上上面ID
        │       ├── 50aff78429b146489e8a6cb9334d93a6d81d5de2edc4fbf5e2d4d9253625753e
        │       │   └── link 内容sha256:加上上面ID
        │       ├── 9f15a39356d6fc1df0a77012bf1aa2150b683e46be39d1c51bc7a320f913e322
        │       │   └── link 内容sha256:加上上面ID
        │       ├── f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f
        │       │   └── link 内容sha256:加上上面ID
        │       └── fc0342a94c89e477c821328ccb542e6fb86ce4ef4ebbf1098e85669e051ef0dd
        │           └── link 内容sha256:加上上面ID
        ├── _manifests
        │   ├── revisions
        │   │   └── sha256
        │   │       └── f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663 [Tag Digest]
        │   │           └── link 内容sha256:加上上面ID
        │   └── tags 该镜像仓库下的各个tag的信息
        │       └── latest
        │           ├── current
        │           │   └── link 内容sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663
        │           └── index
        │               └── sha256
        │                   └── f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663 [Tag Digest]
        │                       └── link 内容sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663
        └── _uploads

查看镜像层关系文件(tag->image+layers)cat blobs/sha256/f8/f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663/data

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": 3615,
      "digest": "sha256:00fd29ccc6f167fa991580690a00e844664cb2381c74cd14d539e36ca014f043" [IMAGE ID]
   },
   "layers": [ 以下是镜像层信息
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 42743207,
         "digest": "sha256:50aff78429b146489e8a6cb9334d93a6d81d5de2edc4fbf5e2d4d9253625753e"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 846,
         "digest": "sha256:f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 621,
         "digest": "sha256:275abb2c8a6f1ce8e67a388a11f3cc014e98b36ff993a6ed1cc7cd6ecb4dd61b"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 854,
         "digest": "sha256:9f15a39356d6fc1df0a77012bf1aa2150b683e46be39d1c51bc7a320f913e322"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 170,
         "digest": "sha256:fc0342a94c89e477c821328ccb542e6fb86ce4ef4ebbf1098e85669e051ef0dd"
      }
   ]
}

查看镜像文件信息: cat blobs/sha256/00/00fd29ccc6f167fa991580690a00e844664cb2381c74cd14d539e36ca014f043/data 其中包括镜像层的diff ID

{
	"architecture": "amd64",
	"config": {
		"Hostname": "",
		"Domainname": "",
		"User": "",
		"AttachStdin": false,
		"AttachStdout": false,
		"AttachStderr": false,
		"Tty": false,
		"OpenStdin": false,
		"StdinOnce": false,
		"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],
		"Cmd": ["/bin/bash"],
		"ArgsEscaped": true,
		"Image": "sha256:34474a3a3cc6e7214fac71230369eb5178b5645acd8db7755c030037099b536a",
		"Volumes": null,
		"WorkingDir": "",
		"Entrypoint": null,
		"OnBuild": null,
		"Labels": null
	},
	"container": "d512da9df07b186ea9bbad0424b1111fef17c10836ce9c5fdbf252544508803b",
	"container_config": {
		"Hostname": "d512da9df07b",
		"Domainname": "",
		"User": "",
		"AttachStdin": false,
		"AttachStdout": false,
		"AttachStderr": false,
		"Tty": false,
		"OpenStdin": false,
		"StdinOnce": false,
		"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],
		"Cmd": ["/bin/sh", "-c", "#(nop) ", "CMD [\"/bin/bash\"]"],
		"ArgsEscaped": true,
		"Image": "sha256:34474a3a3cc6e7214fac71230369eb5178b5645acd8db7755c030037099b536a",
		"Volumes": null,
		"WorkingDir": "",
		"Entrypoint": null,
		"OnBuild": null,
		"Labels": {}
	},
	"created": "2017-12-14T20:59:48.244728969Z",
	"docker_version": "17.06.2-ce",
	"history": [{
		"created": "2017-12-14T20:59:45.307546564Z",
		"created_by": "/bin/sh -c #(nop) ADD file:f5a2d04c3f3cafada15eb32e4e8d971e48ef11724939c399a8664bf498111e67 in / "
	}, {
		"created": "2017-12-14T20:59:46.089739785Z",
		"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": "2017-12-14T20:59:46.735863349Z",
		"created_by": "/bin/sh -c rm -rf /var/lib/apt/lists/*"
	}, {
		"created": "2017-12-14T20:59:47.411048575Z",
		"created_by": "/bin/sh -c sed -i 's/^#\\s*\\(deb.*universe\\)$/\\1/g' /etc/apt/sources.list"
	}, {
		"created": "2017-12-14T20:59:48.062144391Z",
		"created_by": "/bin/sh -c mkdir -p /run/systemd && echo 'docker' > /run/systemd/container"
	}, {
		"created": "2017-12-14T20:59:48.244728969Z",
		"created_by": "/bin/sh -c #(nop)  CMD [\"/bin/bash\"]",
		"empty_layer": true
	}],
	"os": "linux",
	"rootfs": {
		"type": "layers",
		"diff_ids": ["sha256:48e0baf45d4dfd028eab0a7d444309b436cac01ae879805ac0cfdf5aaf1ff93a", "sha256:d2f8c05d353b2d55e191eccba65b72d72fd230c6fbef9cac97d5be5499bcd939", "sha256:5a876f8f1a3d04b1f9735e38e5111e6f11cbf6cad2a44dc3ca6d394dd93caa5f", "sha256:6458f770d435ace5bfba5b99460059c08e7dba66e8606e70ecf941dc1f705077", "sha256:f17fc24fb8d0efef646c75c2977fd41e6816922322944fa3683eeac3aaeec80f"]
	}
}

manifest文件

获取tag的manifest文件: http://127.0.0.1:5000/v2/my-ubuntu/manifests/latest

Docker-Content-Digest: sha256:d64cc6858a7bc61cc44b00b6d2b3a11859dbd683da0066d77f5b2b85cc157f7c 这个是manifest文件的 digest

Existing Manifests

curl -I -X HEAD http://127.0.0.1:5000/v2/my-ubuntu/manifests/latest

同样返回manifest文件的 digest

HTTP/1.1 200 OK
Content-Length: 6049
Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
Docker-Content-Digest: sha256:d64cc6858a7bc61cc44b00b6d2b3a11859dbd683da0066d77f5b2b85cc157f7c
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:d64cc6858a7bc61cc44b00b6d2b3a11859dbd683da0066d77f5b2b85cc157f7c"

3, Distribution 交互

3.1 Pulling an Image Manifest

GET /v2/<name>/manifests/<reference>

reference 是tag name, 或者tag digest(需要加上 sha256:)

http://127.0.0.1:5000/v2/my-ubuntu/manifests/sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663

  • Image Manifest Version 2, Schema 1
{
   "schemaVersion": 1,
   "name": "my-ubuntu",
   "tag": "latest",
   "architecture": "amd64",
   "fsLayers": [
      {
         "blobSum": "sha256:fc0342a94c89e477c821328ccb542e6fb86ce4ef4ebbf1098e85669e051ef0dd"
      },
      {
         "blobSum": "sha256:9f15a39356d6fc1df0a77012bf1aa2150b683e46be39d1c51bc7a320f913e322"
      },
      {
         "blobSum": "sha256:275abb2c8a6f1ce8e67a388a11f3cc014e98b36ff993a6ed1cc7cd6ecb4dd61b"
      },
      {
         "blobSum": "sha256:f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f"
      },
      {
         "blobSum": "sha256:50aff78429b146489e8a6cb9334d93a6d81d5de2edc4fbf5e2d4d9253625753e"
      }
   ],
   "history": [
      {
         "v1Compatibility": "{\"architecture\":\"amd64\",\"config\":{\"Hostname\":\"\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/bash\"],\"ArgsEscaped\":true,\"Image\":\"sha256:34474a3a3cc6e7214fac71230369eb5178b5645acd8db7755c030037099b536a\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"container\":\"d512da9df07b186ea9bbad0424b1111fef17c10836ce9c5fdbf252544508803b\",\"container_config\":{\"Hostname\":\"d512da9df07b\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) \",\"CMD [\\\"/bin/bash\\\"]\"],\"ArgsEscaped\":true,\"Image\":\"sha256:34474a3a3cc6e7214fac71230369eb5178b5645acd8db7755c030037099b536a\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":{}},\"created\":\"2017-12-14T20:59:48.244728969Z\",\"docker_version\":\"17.06.2-ce\",\"id\":\"c1ea3b5d13dd9eca42872a9787f51f6d09bbd2d56f364f231b1833d2fb08d04c\",\"os\":\"linux\",\"parent\":\"7d016c45d574ae04a42372f23ad8a8ce380d186c762fc9e1e2e6bad93fd54741\",\"throwaway\":true}"
      },
      {
         "v1Compatibility": "{\"id\":\"7d016c45d574ae04a42372f23ad8a8ce380d186c762fc9e1e2e6bad93fd54741\",\"parent\":\"6d26059fef3f9bbffe3231079b8a24996f9ff6b6373bbdfa635bb92a4e4294ad\",\"created\":\"2017-12-14T20:59:48.062144391Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c mkdir -p /run/systemd \\u0026\\u0026 echo 'docker' \\u003e /run/systemd/container\"]}}"
      },
      {
         "v1Compatibility": "{\"id\":\"6d26059fef3f9bbffe3231079b8a24996f9ff6b6373bbdfa635bb92a4e4294ad\",\"parent\":\"43ea2a37afe784b6f64b2f86aedacfe3b37d7295f31c5c61a7a75b8fd2eec74b\",\"created\":\"2017-12-14T20:59:47.411048575Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c sed -i 's/^#\\\\s*\\\\(deb.*universe\\\\)$/\\\\1/g' /etc/apt/sources.list\"]}}"
      },
      {
         "v1Compatibility": "{\"id\":\"43ea2a37afe784b6f64b2f86aedacfe3b37d7295f31c5c61a7a75b8fd2eec74b\",\"parent\":\"c4cc29c71ec176e64c42194057c46d2ef4f6907f2665069bd75c07d51766582e\",\"created\":\"2017-12-14T20:59:46.735863349Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c rm -rf /var/lib/apt/lists/*\"]}}"
      },
      {
         "v1Compatibility": "{\"id\":\"c4cc29c71ec176e64c42194057c46d2ef4f6907f2665069bd75c07d51766582e\",\"parent\":\"d4bcfe3fb921825ac69184ce2dc1d4e56f49f6584e82d8b8d8e6b1b81be689be\",\"created\":\"2017-12-14T20:59:46.089739785Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c set -xe \\t\\t\\u0026\\u0026 echo '#!/bin/sh' \\u003e /usr/sbin/policy-rc.d \\t\\u0026\\u0026 echo 'exit 101' \\u003e\\u003e /usr/sbin/policy-rc.d \\t\\u0026\\u0026 chmod +x /usr/sbin/policy-rc.d \\t\\t\\u0026\\u0026 dpkg-divert --local --rename --add /sbin/initctl \\t\\u0026\\u0026 cp -a /usr/sbin/policy-rc.d /sbin/initctl \\t\\u0026\\u0026 sed -i 's/^exit.*/exit 0/' /sbin/initctl \\t\\t\\u0026\\u0026 echo 'force-unsafe-io' \\u003e /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \\t\\t\\u0026\\u0026 echo 'DPkg::Post-Invoke { \\\"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\\\"; };' \\u003e /etc/apt/apt.conf.d/docker-clean \\t\\u0026\\u0026 echo 'APT::Update::Post-Invoke { \\\"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\\\"; };' \\u003e\\u003e /etc/apt/apt.conf.d/docker-clean \\t\\u0026\\u0026 echo 'Dir::Cache::pkgcache \\\"\\\"; Dir::Cache::srcpkgcache \\\"\\\";' \\u003e\\u003e /etc/apt/apt.conf.d/docker-clean \\t\\t\\u0026\\u0026 echo 'Acquire::Languages \\\"none\\\";' \\u003e /etc/apt/apt.conf.d/docker-no-languages \\t\\t\\u0026\\u0026 echo 'Acquire::GzipIndexes \\\"true\\\"; Acquire::CompressionTypes::Order:: \\\"gz\\\";' \\u003e /etc/apt/apt.conf.d/docker-gzip-indexes \\t\\t\\u0026\\u0026 echo 'Apt::AutoRemove::SuggestsImportant \\\"false\\\";' \\u003e /etc/apt/apt.conf.d/docker-autoremove-suggests\"]}}"
      },
      {
         "v1Compatibility": "{\"id\":\"d4bcfe3fb921825ac69184ce2dc1d4e56f49f6584e82d8b8d8e6b1b81be689be\",\"created\":\"2017-12-14T20:59:45.307546564Z\",\"container_config\":{\"Cmd\":[\"/bin/sh -c #(nop) ADD file:f5a2d04c3f3cafada15eb32e4e8d971e48ef11724939c399a8664bf498111e67 in / \"]}}"
      }
   ],
   "signatures": [
      {
         "header": {
            "jwk": {
               "crv": "P-256",
               "kid": "R5SQ:AFOK:5PGB:CRKQ:PN6T:3S5K:6MJS:EHNY:NNV5:3PEZ:B5SA:S7AW",
               "kty": "EC",
               "x": "w3jy1n61gifPk6O-QWB-Q1sHJ12nWA8W6jjLYrlNcaQ",
               "y": "uLAu6xnS9JpvVDX8iOC_4N4aiYrseKu6HaTEBH7m-5s"
            },
            "alg": "ES256"
         },
         "signature": "zUTSLR-9x73czupXu2nEZxjXChIJ4MfwadgYSg01j-hZ_9FAFXeEDGy7DlsLb49Ev5SNJAK66VBcxAwm7nKefw",
         "protected": "eyJmb3JtYXRMZW5ndGgiOjU0MDIsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxOC0wMS0xMlQwMzowNjowMVoifQ"
      }
   ]
}
  • Image Manifest Version 2, Schema 2
{
schemaVersion: 2,
mediaType: "application/vnd.docker.distribution.manifest.v2+json",
config: {
mediaType: "application/vnd.docker.container.image.v1+json",
size: 3615,
digest: "sha256:00fd29ccc6f167fa991580690a00e844664cb2381c74cd14d539e36ca014f043" IMAGE ID config
},
layers: [
{
mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
size: 42743207,
digest: "sha256:50aff78429b146489e8a6cb9334d93a6d81d5de2edc4fbf5e2d4d9253625753e"
},
{
mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
size: 846,
digest: "sha256:f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f"
},
{
mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
size: 621,
digest: "sha256:275abb2c8a6f1ce8e67a388a11f3cc014e98b36ff993a6ed1cc7cd6ecb4dd61b"
},
{
mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
size: 854,
digest: "sha256:9f15a39356d6fc1df0a77012bf1aa2150b683e46be39d1c51bc7a320f913e322"
},
{
mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip",
size: 170,
digest: "sha256:fc0342a94c89e477c821328ccb542e6fb86ce4ef4ebbf1098e85669e051ef0dd"
}
]
}

3.2 Pulling a Layer

GET /v2/<name>/blobs/<digest> digest 要加上sha256:

curl -I -X GET http://127.0.0.1:5000/v2/my-ubuntu/blobs/sha256:f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=31536000
Content-Length: 846
Content-Type: application/octet-stream
Docker-Content-Digest: sha256:f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f
Docker-Distribution-Api-Version: registry/2.0
Etag: "sha256:f6d82e297bce031a3de1fa8c1587535e34579abce09a61e37f5a225a8667422f"
Date: Fri, 19 Jan 2018 07:46:23 GMT
  • 307?
  • 要支持缓存协商
  • 要支持ETag
  • 考虑增加incremental下载
  • 需要支持 Range

3.3 Pushing An Image Layer

启动上传

POST /v2/<name>/blobs/uploads/ 末尾斜杠不能省

服务端会返回202 Accepted, 响应在 Location头信息中返回上传 URL

HTTP/1.1 202 Accepted
Content-Length: 0
Docker-Distribution-Api-Version: registry/2.0
Docker-Upload-Uuid: 626fd4d6-38db-48e3-ba73-45af0bfa5678
Location: http://127.0.0.1:5000/v2/foxtest/blobs/uploads/626fd4d6-38db-48e3-ba73-45af0bfa5678?_state=oE1NVRPEyI8JA-QS7az_At832y71v4-iPQ6rK9bGHVp7Ik5hbWUiOiJmb3h0ZXN0IiwiVVVJRCI6IjYyNmZkNGQ2LTM4ZGItNDhlMy1iYTczLTQ1YWYwYmZhNTY3OCIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxOC0wMS0xOVQwNzo1Njo1Ni40NDM4NTdaIn0%3D
Range: 0-0
Date: Fri, 19 Jan 2018 07:56:56 GMT
Content-Type: text/plain; charset=utf-8

如果客户端需要关联本地上传状态与远程上传状态,Docker-Upload-UUID头信息的内容应该被使用。这样的 id ,在实施可恢复的上传时,可以被用作最后用到的位置头信息的关键字

TODO _state 是啥

在服务端会生成:

└── repositories
    ├── foxtest
    │   └── _uploads
    │       └── 626fd4d6-38db-48e3-ba73-45af0bfa5678
    │           ├── data
    │           ├── hashstates
    │           │   └── sha256
    │           │       └── 0
    │           └── startedat

上传进度检查

GET /v2/<name>/blobs/uploads/<uuid> 需要把上面返回的_state带上

curl -I -X GET http://127.0.0.1:5000/v2/foxtest/blobs/uploads/626fd4d6-38db-48e3-ba73-45af0bfa5678?_state=oE1NVRPEyI8JA-QS7az_At832y71v4-iPQ6rK9bGHVp7Ik5hbWUiOiJmb3h0ZXN0IiwiVVVJRCI6IjYyNmZkNGQ2LTM4ZGItNDhlMy1iYTczLTQ1YWYwYmZhNTY3OCIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxOC0wMS0xOVQwNzo1Njo1Ni40NDM4NTdaIn0%3D
HTTP/1.1 204 No Content
Docker-Distribution-Api-Version: registry/2.0
Docker-Upload-Uuid: 626fd4d6-38db-48e3-ba73-45af0bfa5678
Location: http://127.0.0.1:5000/v2/foxtest/blobs/uploads/626fd4d6-38db-48e3-ba73-45af0bfa5678?_state=ISOcuCMWgI9dncvUZ58evhe3JvOW9dd_Wcuam7Ps6xF7Ik5hbWUiOiJmb3h0ZXN0IiwiVVVJRCI6IjYyNmZkNGQ2LTM4ZGItNDhlMy1iYTczLTQ1YWYwYmZhNTY3OCIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxOC0wMS0xOVQwNzo1Njo1NloifQ%3D%3D
Range: 0-0
Date: Fri, 19 Jan 2018 08:09:59 GMT

存在性检测

HEAD /v2/<name>/blobs/<digest>

整体上传(Monolithic Upload

块上传(Chunked Upload)

完整的上传(Completed Upload)

取消上传(Canceling an Upload)

DELETE /v2/<name>/blobs/uploads/<uuid>

该请求发送后,相关上传的 uuid 会失效,并且 registry 服务器会删除所有相关数据。在上传没有完成并要超时的情况下,如果遇到一个致命错误但仍有发送 http 请求的能力,客户端会发出这个请求


参考资料