将镜像tar包通过API直接push到registry仓库

共 3578字,需浏览 8分钟

 ·

2020-08-09 05:41

为了实现docker tar包能够直接通过页面上传,调研了一下registry的api,以及如何解析tar包(其实就是docker daemon程序实现的部分)。

要想实现,首先要了解docker tar包中结构组成:

tar包结构

拿了一个包含一个镜像的tar包进行解压:

.
├── 1ecf8bc84a7c3d60c0a6bbdd294f12a6b0e17a8269616fc9bdbedd926f74f50c
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── 6f4ec1f3d7ea33646d491a705f94442f5a706e9ac9acbca22fa9b117094eb720.json
├── aaac5bde2c2bcb6cc28b1e6d3f29fe13efce6d6b669300cc2c6bfab96b942af4
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── b63363f0d2ac8b3dca6f903bb5a7301bf497b1e5be8dc4f57a14e4dc649ef9bb
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── c453224a84b8318b0a09a83052314dd876899d3a1a1cf2379e74bba410415059
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── dd8ef1d42fbcccc87927eee94e57519c401b84437b98fcf35505fb6b7267a375
│   ├── VERSION
│   ├── json
│   └── layer.tar
├── manifest.json
└── repositories

文件说明:

「manifest.json文件」

[
    {
        "Config":"6f4ec1f3d7ea33646d491a705f94442f5a706e9ac9acbca22fa9b117094eb720.json",
        "RepoTags":[
            "alpine:filebeat-6.8.7-arm64"
        ],
        "Layers":[
            "aaac5bde2c2bcb6cc28b1e6d3f29fe13efce6d6b669300cc2c6bfab96b942af4/layer.tar",
            "dd8ef1d42fbcccc87927eee94e57519c401b84437b98fcf35505fb6b7267a375/layer.tar",
            "c453224a84b8318b0a09a83052314dd876899d3a1a1cf2379e74bba410415059/layer.tar",
            "b63363f0d2ac8b3dca6f903bb5a7301bf497b1e5be8dc4f57a14e4dc649ef9bb/layer.tar",
            "1ecf8bc84a7c3d60c0a6bbdd294f12a6b0e17a8269616fc9bdbedd926f74f50c/layer.tar"
        ]
    }
]

manifest.json 包含了对这个tar包的描述信息,比如image config文件地址,tags说明,镜像layer信息,在解析的时候也是根据这个文件去获取关联的文件。

「image config文件」

比如:6f4ec1f3d7ea33646d491a705f94442f5a706e9ac9acbca22fa9b117094eb720.json文件:

内容太多就不贴了 这里包含了镜像运行的信息,比如env,执行参数,以及镜像历史等。

「layer层文件:layer.tar」

镜像的每一层的文件信息都打包在了一个单独的layer.tar包中,也是在上传的时候需要用到的。

registry api

「流程:」

  • 1、获取鉴权信息
  • 2、检查layer.tar是否已经存在
  • 3、上传layer.tar
  • 4、上传image config
  • 5、上传manifest(非包中的manifest.json而是Manifest struct)

这里只列出了在上传的时候需要用的api

1、获取鉴权信息

这里跟registry仓库选择的鉴权方式有关,可选basic auth或者token鉴权。这里我是以最基本的basic auth为例子,如果是token鉴权的方式参考这里:https://docs.docker.com/registry/spec/auth/jwt/

2、检查上传

HEAD /v2/image/blobs/

若返回200 OK 则表示存在,不用上传

3、开始上传服务 我这里是以分块上传的方式进行

POST /v2/image/blobs/uploads/

如果post请求返回202 accepted,一个url会在location字段返回.

     202 Accepted
     Location: /v2/\/blobs/uploads/\
     Range: bytes=0-
     Content-Length: 0
     Docker-Upload-UUID:  # 可以用来查看上传状态和实现断点续传

4、分块上传 根据上一步获取的url,以PATCH的方式提交分块数据。如果是最后一块数据上传,则以PUT的方式提交,如下:

 > PUT /v2//blob/uploads/?digest=
 > Content-Length: 
 > Content-Range: -
 > Content-Type: application/octet-stream
   

上传layer,image config,manifests信息都是一样的。

我暂时只用到了以上api,更多的api参考:https://docs.docker.com/registry/spec/api/

实现

上面说API没啥感觉,还是看代码比较明白,所以实现了这么一个工具:https://github.com/silenceper/docker-tar-push

「Usage:」

push your docker tar archive image without docker.

Usage:
  docker-tar-push [flags]

Flags:
  -h, --help              help for docker-tar-push
      --log-level int     log-level, 0:Fatal,1:Error,2:Warn,3:Info,4:Debug (default 3)
      --password string   registry auth password
      --registry string   registry url
      --skip-ssl-verify   skip ssl verify
      --username string   registry auth username

「Example:」

docker-tar-push alpine:latest --registry=http://localhost:5000

「参考」

  • https://www.jianshu.com/p/6a7b80122602
  • https://github.com/Razikus/dockerregistrypusher
  • https://docs.docker.com/registry/spec/auth/jwt/
  • https://github.com/docker/distribution/





推荐阅读



学习交流 Go 语言,扫码回复「进群」即可


站长 polarisxu

自己的原创文章

不限于 Go 技术

职场和创业经验


Go语言中文网

每天为你

分享 Go 知识

Go爱好者值得关注


浏览 147
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报