JAVA实现镜像tar包上传到harbor镜像仓库

前言

  使用harbor过程中,一直想使用harbor的api实现镜像的上传功能,但是实际上harbor是直接调用了docker registry的api,harbor层只是做了一个透传的功能,这个可以参考《harbor权威指南》这本书,参考官网接口以及网上大佬的思想,实现了一个Java版本,主要是实现了docker daemon上传的逻辑。

docker镜像tar包结构

实现上传首先需要将镜像的tar包解压,读取目录结构,一个典型的docker镜像包(使用docker save命令)结构如下:

.
├── 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

清单文件manifet.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信息,在解析的时候也是根据这个文件去获取关联的文件

上传流程

  1. 获取鉴权信息
  2. 检查layer.tar是否已经存在
  3. 上传layer.tar
  4. 上传image config
  5. 上传manifest(非包中的manifest.json而是Manifest struct)
  1. 核心实现类DockerImageUploadBiz.java
    /**
     * @author Administrator
     */
    @Service
    @Slf4j
    public class DockerImageUploadBiz {
        
        //远程仓库
        @Value("${docker.remote.repo}")
        private String targetRepoAddress;
        
        //本地解压路径
        @Value("${docker.upload.extractPath}")
        private String tarPath;
        
        //harbor用户名
        @Value("${docker.harbor.userName}")
        private String userName;
        
        //密码
        @Value("${docker.harbor.password}")
        private String password;
        
        /**
        * @param sourceTar 上传的镜像文件
        * @param project 项目
        */
        public void push(File sourceTar, String project) {
            if (!sourceTar.exists()) {
                log.warn("Error!file is not exist!path:{}", sourceTar);
                return;
            }
            try {
                String unTarPath = FileUtil.doUnArchiver(sourceTar, tarPath);
                String manifest = FileUtil.readJsonFile(unTarPath + File.separator + "manifest.json");
                JSONArray jsonArray = JSONObject.parseArray(manifest);
                if (Objects.isNull(jsonArray)) {
                    log.warn("manifest convert error!path:{},content:{}", unTarPath + File.separator + "manifest.json", manifest);
                    return;
                }
                for (Object arr : jsonArray) {
                    JSONObject jsonObject = (JSONObject) arr;
                    JSONArray repoTags = jsonObject.getJSONArray("RepoTags");
                    for (Object repoTag : repoTags) {
                        String repo = repoTag.toString();
                        String substring = repo.substring(repo.lastIndexOf('/') + 1);
                        String[] split = substring.split(":");
                        String imageName = split[0];
                        String tag = split[1];
                        log.info("imageName:{},tag:{}", imageName, tag);
                        JSONArray layers = jsonObject.getJSONArray("Layers");
                        //1.上传layer
                        log.info("========================STEP:1/3===============================");
                        log.info("PUSHING LAYERS STARTING...");
                        List<String> layerPathList = new ArrayList<>(layers.size());
                        int i = 1;
                        for (Object layer : layers) {
                            String layerPath = unTarPath + File.separator + layer.toString();
                            log.info("PUSHING LAYER:{}-{} ...", i, layers.size());
                            layerPathList.add(layerPath);
                            pushLayer(project, layerPath, imageName);
                            i++;
                        }
                        log.info("PUSHING LAYERS ENDED...");
    
                        log.info("========================STEP:2/3===============================");
                        //2.上传config
                        log.info("PUSHING CONFIG STARTING...");
                   
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值