基于docker push原理进行tar镜像上传至harbor仓库(未分片)
深入解析Harbor镜像推送全流程实现
本文将基于开源Harbor镜像仓库,详细解析如何通过Java代码实现完整的Docker镜像推送流程。通过分析核心代码,揭示镜像推送背后的技术细节。
核心架构设计
HarborPushAllInOne类封装了完整的镜像推送功能:
- 使用Apache HttpClient处理HTTP请求
- 通过TarArchiveInputStream解析Docker镜像tar包
- 采用分步上传策略(Config/Layers/Manifest)
初始化参数说明:
public HarborPushAllInOne(String registry, String user, String pwd, String project, String repo) {this.registry = registry.trim().replaceAll("/$", "");this.project = project;this.repo = repo;this.basic = "Basic " + Base64.getEncoder().encodeToString((user + ":" + pwd).getBytes());
}
镜像上传三步曲
tar包解析与文件提取
private Map<String, byte[]> extractTar(String path) throws Exception {Map<String, byte[]> map = new HashMap<>();try (TarArchiveInputStream tis = new TarArchiveInputStream(Files.newInputStream(Paths.get(path)))) {TarArchiveEntry e;while ((e = tis.getNextTarEntry()) != null) {if (!e.isDirectory()) {byte[] buf = new byte[(int)e.getSize()];int read = 0, total = 0;while (total < buf.length && (read = tis.read(buf, total, buf.length - total)) >= 0) {total += read;}map.put(e.getName(), buf);fileSizes.put(e.getName(), total);}}}return map;
}
分层上传策略
- 配置文件上传
- 镜像层文件上传
- 合并生成manifest
public void uploadTarImage(String tarPath, String repo, String tag) throws Exception {Map<String, byte[]> files = extractTar(tarPath);JSONObject mf = new JSONArray(new String(files.get("manifest.json"))).getJSONObject(0);// Config文件处理String configName = mf.getString("Config");String configDigest = pushBlob(files.get(configName));// Layers处理List<String> layerDigests = new ArrayList<>();List<Integer> layerSizes = new ArrayList<>();for (Object o : mf.getJSONArray("Layers")) {String layerName = (String)o;String digest = pushBlob(files.get(layerName));layerDigests.add(digest);layerSizes.add(fileSizes.get(layerName));}// 最终manifest生成pushManifest(configDigest, files.get(configName).length, layerDigests, layerSizes, repo, tag);
}
关键技术实现
Blob上传优化
采用检查-上传两步策略避免重复上传:
private String pushBlob(byte[] blob) throws Exception {String digest = "sha256:" + sha256(blob);String check = registry + "/v2/" + project + "/" + repo + "/blobs/" + digest;if (exists(check)) {System.out.println("Blob 已存在 " + digest);return digest;}// 分段上传逻辑...
}
安全认证处理
使用Basic认证并自动生成Header:
private final String basic = "Basic " + Base64.getEncoder().encodeToString((user + ":" + pwd).getBytes());// 在请求中设置
post.setHeader(HttpHeaders.AUTHORIZATION, basic);
实际应用示例
完整的上传调用示例:
public static void main(String[] args) throws Exception {HarborPushAllInOne pusher = new HarborPushAllInOne("https://your-harbor.com","admin","password","your-project","demo-repo");pusher.uploadTarImage("/path/to/image.tar", "demo-repo", "v1.0");
}
性能优化建议
- 增加并行上传层文件功能
- 实现断点续传机制
- 添加进度监控回调接口
- 优化内存管理,处理大文件分块
通过本文的分析可以看出,Docker镜像推送本质上是对分层存储系统和Registry API的精确调用。理解这些底层原理,有助于开发更高效的镜像管理工具。