docker push 接口详情
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>
以下为抓包的结果:
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 中的 name
和 reference
必须和下面的 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 流程就结束了~
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于