Description

描述如何使用dockerhub提供的API V2上传镜像,而不经过docker

Reference:

Steps

Auth

首先需要验证账号和密码。具体格式是base64($username:$password)。编码后的结果应当作为下一步的请求头

在获得正确的base64编码之后,应当向https://auth.docker.io/token?service=registry.docker.io&scope=repository:$reponame:$actions" 发送请求,其中$reponame:$actions为要访问的repo名称+请求的权限(一般是"push,pull"

Overview

要对dockerhub推送镜像,需要认证用户。在之后需要先逐层推送,然后上传manifest。

Auth

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UNAME=""
UPASS=""
TARPATH="test/85e601059a16cdd58f9b02de2c34b30f19464bc60e848da43b7daf5b1b1c2a8c/layer.tar"


getToken() {
local reponame=$1
local actions=$2
local headers
local response

if [ -n "$UNAME" ]; then
headers="Authorization: Basic $(echo -n "${UNAME}:${UPASS}" | base64)"
fi

response=$(curl -s -H "$headers" "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$reponame:$actions")

echo $response | jq '.token' | xargs echo

}

这里response返回一个对于该repo的token…?

Push layers

推送一个镜像层分两步:第一步通过下面的请求提起一个upload流程并获取一个URL

1
POST /v2/<name>/blobs/uploads/
  • name: 镜像所属的namespace,通常为用户名。

返回的示例如下:

1
2
3
4
5
6
7
8
9
10
11
$ curl -X POST -I 192.168.1.103:8021/v2/library/registry/blobs/uploads/
HTTP/1.1 202 Accepted
Server: nginx/1.11.5
Date: Thu, 13 Sep 2018 11:05:26 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 0
Connection: keep-alive
Docker-Distribution-Api-Version: registry/2.0
Docker-Upload-Uuid: 91cbb0a1-c335-45ae-b155-86bf06897d9d
Location: http://192.168.1.103:8021/v2/library/registry/blobs/uploads/91cbb0a1-c335-45ae-b155-86bf06897d9d?_state=YeQZM_9WTPi9Gxfgi6chPo7gZ0fRsJisqthEwHrrmTl7Ik5hbWUiOiJsaWJyYXJ5L3JlZ2lzdHJ5IiwiVVVJRCI6IjkxY2JiMGExLWMzMzUtNDVhZS1iMTU1LTg2YmYwNjg5N2Q5ZCIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxOC0wOS0xM1QxMTowNToyNi45NzI2MjE4ODhaIn0%3D
Range: 0-0

这里Location即为下一步上传layer需要的的URL

Chcek existance

1
HEAD /v2/<name>/blobs/<digest>
  • digest: 镜像层的sha256摘要

如果该层存在则会返回:

1
2
3
200 OK
Content-Length: <length of blob>
Docker-Content-Digest: <digest>

这时候不需要再次上传该层。有时候在之前的tag中上传过,也会提示存在。

这个检测范围有多少?如果是同一个人别的镜像呢?如果是别人的镜像呢?更离谱,别人的私人镜像呢?

Pushing layer

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

这里调用上面得到的URL,用PUT方法,例如:

1
curl -X PUT -H "Content-Type: application/octet-stream" -H -I --upload-file /root/image/layers/06ba8e23299fcf9dd9efb3c5acd4c9d03badac5392953001c75d38197113a63a.tar.gz http://192.168.1.103:8021/v2/library/registry/blobs/uploads/91cbb0a1-c335-45ae-b155-86bf06897d9d?_state=YeQZM_9WTPi9Gxfgi6chPo7gZ0fRsJisqthEwHrrmTl7Ik5hbWUiOiJsaWJyYXJ5L3JlZ2lzdHJ5IiwiVVVJRCI6IjkxY2JiMGExLWMzMzUtNDVhZS1iMTU1LTg2YmYwNjg5N2Q5ZCIsIk9mZnNldCI6MCwiU3RhcnRlZEF0IjoiMjAxOC0wOS0xM1QxMTowNToyNi45NzI2MjE4ODhaIn0%3D\&digest=sha256:06ba8e23299fcf9dd9efb3c5acd4c9d03badac5392953001c75d38197113a63a

如果成功会返回Code201

当docker push在上传镜像的时候,如果一个repository有两个tag,那么上传第二个tag时,重复的layer就不会上传。但如果两个镜像的repository不一样,那么即使它们有重复的layer,也会各自上传一次。