【harbor 学习笔记】docker push 接口详情

本贴最后更新于 1811 天前,其中的信息可能已经物是人非

docker push 接口详情

dockerpush.png

step 1. Api 版本确认

registry 服务器会通过 /v2/ 接口根据返回的状态码来提供 api 的版本信息,请求格式如下

GET /v2
  • 如果返回 200 OK 则表明 registry 实现了 V2 接口,并且客户端可以安全的去使用其他所有的 v2 接口
  • 如果返回 401 Unauthorized, 则表示客户端需要根据 WWW-Authenticate header 重新请求接口。根据访问控制设置,用户即使这里通过验证,在访问不同的资源的时候可能仍需身份验证
  • 如果返回 404 NOT FOUND ,则客户端应认为 registry 未实现 v2 接口

step 2. 校验 layer 是否存在

可以通过一个 HEAD 请求来校验一个 layer 是否存在。 请求格式如下:

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

如果返回的状态码为 200 OK ,则表示指定的 layer 已存在,若已存在则 client 则跳过该 layer 的上传。由于 HEAD 请求根据 HTTP 规范没有 body,因此 HEADER 中带了以下信息

200
Content-Length: <length of blob>
Docker-Content-Digest: <digest> 

以下为抓包的结果:

pushhead.png

step 3. 发送 post 请求

该请求的参数是镜像命名空间,layer 将在该命名空间被链接。该请求的格式是:

POST  /v2/<name>/blobs/uploads/

如果返回 202 Accepted 则表明请求成功,其 HEADER 携带了以下信息:

202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: bytes=0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>
  • 其中 Location 返回下一步镜像上传的地址,其 API 格式为 /v2/<name>/blobs/uploads/<uuid>
  • 如果本地客户端想和远程 registry 的上传状态相关联,可以使用 Docker-Upload-UUID 中的值。这个 id 可以作为上一次 location header 的 key 来实现可恢复上传。

抓包结果:

POST /v2/hello-world/blobs/uploads/ HTTP/1.1
Host: hub.vic.com
User-Agent: docker/17.12.0-ce go/go1.9.2 git-commit/c97c6d6 kernel/3.10.0-693.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/17.12.0-ce \(linux\))
Content-Length: 0
Accept-Encoding: gzip
Content-Type: 
X-Forwarded-For: 172.17.0.1, 192.168.79.136
X-Forwarded-Proto: https
X-Real-Ip: 172.17.0.1

HTTP/1.1 202 Accepted
Content-Length: 0
Docker-Distribution-Api-Version: registry/2.0
Docker-Upload-Uuid: 87399c24-26ba-4f39-a1db-ca8b5469133d
Location: https://hub.vic.com/v2/hello-world/blobs/uploads/87399c24-26ba-4f39-a1db-ca8b5469133d?_state=uog2S7ReISUOCxLS2uU3Z3S2h1_aV4Sq8T5CmA09B_p7Ik5hbWUiOiJoZWxsby13b3JsZCIsIlVVSUQiOiI4NzM5OWMyNC0yNmJhLTRmMzktYTFkYi1jYThiNTQ2OTEzM2QiLCJPZmZzZXQiOjAsIlN0YXJ0ZWRBdCI6IjIwMTktMTEtMThUMTY6MzA6MzMuMTI4NzA5NTE1WiJ9
Range: 0-0
X-Content-Type-Options: nosniff
Date: Mon, 18 Nov 2019 16:30:33 GMT

step 4. 分块上传

客户端可以通过携带包含 range 的 Header 和该 layer 的文件,来完成对应分块的上传:

PATCH /v2/<name>/blobs/uploads/<uuid>
Content-Length: <size of chunk>
Content-Range: <start of range>-<end of range>
Content-Type: application/octet-stream

<Layer Chunk Binary Data>

抓包结果:

PATCH /v2/hello-world/blobs/uploads/87399c24-26ba-4f39-a1db-ca8b5469133d?_state=uog2S7ReISUOCxLS2uU3Z3S2h1_aV4Sq8T5CmA09B_p7Ik5hbWUiOiJoZWxsby13b3JsZCIsIlVVSUQiOiI4NzM5OWMyNC0yNmJhLTRmMzktYTFkYi1jYThiNTQ2OTEzM2QiLCJPZmZzZXQiOjAsIlN0YXJ0ZWRBdCI6IjIwMTktMTEtMThUMTY6MzA6MzMuMTI4NzA5NTE1WiJ9 HTTP/1.1
Host: hub.vic.com
User-Agent: docker/17.12.0-ce go/go1.9.2 git-commit/c97c6d6 kernel/3.10.0-693.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/17.12.0-ce \(linux\))
Content-Length: 977
Accept-Encoding: gzip
X-Forwarded-For: 172.17.0.1, 192.168.79.136
X-Forwarded-Proto: https
X-Real-Ip: 172.17.0.1

...........U.k.U.>.l.0......cY..f2.lS	U..q.T../.....;...].=.M|.!>....W|..
...,.? D..'.C`...Ig....A......}..1s.F<.%<].:.w....
........ng.J...w
~.....\Wn.&........G..w...5.'.9x.Lt.....=..?...
hB...|...Q..x.~...0.l.?....+}..K..~..........K.......c..
.Y....w.../|.v..`..o}y.....}....*...Ea.....Mk...7...t...........	....?.........7&...<....Z\.....m:]:.......K_....
'.W...i......7...J&x]..\...DBc..fC.:.c..1.}.)..&....L..F.).$..8.jW.C..R<.x.u...C.r..#Ut.6....H....c96|M|.7.............L.....d...Od.:.6C).q...._....X.8.."1...W....:...Y.nt_wp.4.@qf.`..qQ.H.*..Y.q$..U..).\... #...............|.... S......,...u.{Z=..gI.'.R.d..b.m[.6...WD.x..U"R..O..>j.p..cI...._...n...,5.!K.....U.1..m:....np+.0+.>...|..&.I.6..db^..*
b96giX.6z.p..IC.].t0".....(.."...d.q..*.|.%...\K...6..ZP...@W.CN+f...W.'.....}.....s.,,.m.w.y..;.N_..cs.......r...:........;L3..D....\.{...!#...>.(.pp....l....v......Y....Y._43..r..{....j..Z...2....Z...Y<...........5.b-..gsecv.....~.q......k...........g.............

HTTP/1.1 202 Accepted
Content-Length: 0
Docker-Distribution-Api-Version: registry/2.0
Docker-Upload-Uuid: 87399c24-26ba-4f39-a1db-ca8b5469133d
Location: https://hub.vic.com/v2/hello-world/blobs/uploads/87399c24-26ba-4f39-a1db-ca8b5469133d?_state=lkoT88kcYkqkNrIHRetc7JVpbPvK690THF_WixElh4J7Ik5hbWUiOiJoZWxsby13b3JsZCIsIlVVSUQiOiI4NzM5OWMyNC0yNmJhLTRmMzktYTFkYi1jYThiNTQ2OTEzM2QiLCJPZmZzZXQiOjk3NywiU3RhcnRlZEF0IjoiMjAxOS0xMS0xOFQxNjozMDozM1oifQ%3D%3D
Range: 0-976
X-Content-Type-Options: nosniff
Date: Mon, 18 Nov 2019 16:30:33 GMT

服务器必须顺序的接受每一个分块,但是不限制每个 layer 是如何分割的。服务器可能设置了一个最小块的大小。如果服务器无法接收这个 chunk,则会返回 416 的状态码,并在 HEADER 中返回一个 Range 标识当前的状态

416 Requested Range Not Satisfiable
Location: /v2/<name>/blobs/uploads/<uuid>
Range: 0-<last valid range>
Content-Length: 0
Docker-Upload-UUID: <uuid>

如果返回的值为 202 Accepted 客户端需要从最后一个有效的 range 开始上传后续的分块。

202 Accepted
Location: /v2/<name>/blobs/uploads/<uuid>
Range: bytes=0-<offset>
Content-Length: 0
Docker-Upload-UUID: <uuid>

step 5. 完成 yayer 上传

客户端发送一个 PUT 请求并携带 deigest 参数来告诉服务器上传完成。如果不发送该接口,上传将会被视为没有完成:

PUT /v2/<name>/blobs/uploads/<uuid>?digest=<digest>
Content-Length: <size of chunk>
Content-Range: <start of range>-<end of range>
Content-Type: application/octet-stream

<Last Layer Chunk Binary Data>

如果对应的 layer 已经存在,可以发送一个 Content-Length 为 0 的请求。当最后的 chunk 被接收并验证通过将会返回 302 Created 状态:


201 Created
Location: /v2/<name>/blobs/<digest>
Content-Length: 0
Docker-Content-Digest: <digest>

HEADER 的 Location 将会携带一个可以验证当前接收的 layer 存在的地址。Docker-Content-Digest 将会提供当前 blob 的 digest,它可能会和提供的 digest 不同

PUT /v2/hello-world/blobs/uploads/83f294f5-2886-4d3b-bc9a-cc6c1ab93101?_state=EMZiJZM0HP1kElDmi_IuN3GbJ1JfEnn6XcYp_3FYlLl7Ik5hbWUiOiJoZWxsby13b3JsZCIsIlVVSUQiOiI4M2YyOTRmNS0yODg2LTRkM2ItYmM5YS1jYzZjMWFiOTMxMDEiLCJPZmZzZXQiOjE1MTAsIlN0YXJ0ZWRBdCI6IjIwMTktMTEtMThUMTY6MzA6MzNaIn0%3D&digest=sha256%3Afce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e HTTP/1.1
Host: hub.vic.com
User-Agent: docker/17.12.0-ce go/go1.9.2 git-commit/c97c6d6 kernel/3.10.0-693.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/17.12.0-ce \(linux\))
Content-Length: 0
Accept-Encoding: gzip
X-Forwarded-For: 172.17.0.1, 192.168.79.136
X-Forwarded-Proto: https
X-Real-Ip: 172.17.0.1

HTTP/1.1 201 Created
Content-Length: 0
Docker-Content-Digest: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e
Docker-Distribution-Api-Version: registry/2.0
Location: https://hub.vic.com/v2/hello-world/blobs/sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e
X-Content-Type-Options: nosniff
Date: Mon, 18 Nov 2019 16:30:33 GMT

step 6. push 镜像的 manifest

当所有的 layer 都上传完成了,客户端需要发送一个 PUT 请求并提供镜像的 manifest:

PUT /v2/<name>/manifests/<reference>
Content-Type: <manifest media type>
{
   "name": <name>,
   "tag": <tag>,
   "fsLayers": [
      {
         "blobSum": <digest>
      },
      ...
    ]
   ],
   "history": <v1 images>,
   "signature": <JWS>,
   ...
}

url 中的 namereference 必须和下面的 body 中的字段对应。reference 可以是 tag 或者 digest

PUT /v2/hello-world/manifests/1.0 HTTP/1.1
Host: hub.vic.com
User-Agent: docker/17.12.0-ce go/go1.9.2 git-commit/c97c6d6 kernel/3.10.0-693.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/17.12.0-ce \(linux\))
Content-Length: 524
Accept-Encoding: gzip
Content-Type: application/vnd.docker.distribution.manifest.v2+json
X-Forwarded-For: 172.17.0.1, 192.168.79.136
X-Forwarded-Proto: https
X-Real-Ip: 172.17.0.1

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": 1510,
      "digest": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e"
   },
   "layers": [
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 977,
         "digest": "sha256:1b930d010525941c1d56ec53b97bd057a67ae1865eebf042686d2a2d18271ced"
      }
   ]
}

HTTP/1.1 201 Created
Docker-Content-Digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
Docker-Distribution-Api-Version: registry/2.0
Location: https://hub.vic.com/v2/hello-world/manifests/sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
X-Content-Type-Options: nosniff
Date: Mon, 18 Nov 2019 16:30:33 GMT
Content-Length: 0

这个接口返回 201 后整个 push 流程就结束了~

  • registry
    4 引用
  • harbor
    4 引用
  • HTTP
    75 引用 • 128 回帖 • 1 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    491 引用 • 917 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...