四种方法将 Docker Registry 迁移至 Harbor

Registry

Docker Distribution

Docker Distribution 是第一个是实现了打包、发布、存储和镜像分发的工具,起到 docker registry 的作用。(目前 Distribution 已经捐赠给了 CNCF)。其中 Docker Distribution 中的 spec 规范后来也就成为了 OCI distribution-spec 规范。可以认为 Docker Distribution 实现了大部分 OCI 镜像分发的规范,二者在很大程度上也是兼容的。

OCI 的指导思想时先有工业界的实践,再将这些实践总结成技术规范,因此尽管 OCI 的 distribution-spec 规范还没有正式发布(目前版本是 v1.0.0-rc1),但以 Docker Distribution 作为基础的镜像仓库已经成为普遍采用的方案,docker registry http api v2 也就成为了事实上的标准。

Harbor

harbor 也是采用了 Docker Distribution (docker registry)作为后端镜像存储服务,在 harbor 2.0 之前的版本,镜像相关的功能大部分是由 Docker Distribution 来处理,镜像和 OCI 等制品的元数据是 harbor 组件从 docker registry 中提取出来的;harbor 在 2.0 版本之后,镜像等 OCI 制品相关的元数据由 harbor 自己来维护,而且元数据是在 PUSH 这些制品时写入到 harbor 的数据库中的。

正因得益于此,harbor 不再仅仅是个用来存储和管理镜像的服务,而一个云原生仓库服务,能够存储和管理符合 OCI 规范的 Helm Chart、CNAB、OPA Bundle 等多种 Artifact。

Docker Registry to Harbor

回到本文主题:如何将 docker registry 中的镜像迁移至 harbor?

假如内网环境中有两台机器,一台机器上运行着 docker registry,域名假设为 registry.k8s.li 。另一台机器运行着 harbor,假设域名为 harbor.k8s.li。现在 docker registry 中存放了五千个镜像。harbor 是刚刚部署的,里面还没有镜像。在磁盘和网络没有限制的情况下,如何高效地将 docker registry 中的镜像迁移到 harbor 中呢?

获取 Registry 所有镜像的列表

首先在迁移之前我们要获取一份 docker registry 中镜像的列表,这样我们才能保证迁移后没有镜像丢失。根据《 深入浅出容器镜像的一生》一文中提到的 registry 的存储目录结构。在 registry 存储目录中,每个镜像的 tag 都是由 current/index 这个文件指向该 tag 镜像的 manifests 文件的,由此我们可以通过遍历 registry 存储目录中 current/index 文件的方式来得到所有镜像的 tag,由此得到该 registry 中所有镜像的列表。注意,这样只能得到有 tag 的镜像,其他没 tag 的镜像无法获取到。

可通过如下命令在 registry 存储目录下获取镜像列表:

Harbor 创建 project

对于新部署的 harbor 来说,上面只会有一个默认的 library 的 project,需要手动在 harbor 上创建 docker registry 中对应的 project。docker registry 中镜像的 project 就是 registry 存储目录中 repositories 下的目录名。

得到了镜像列表,以及在 harbor 上完成了对应 project 的创建,我们就可以做正式的迁移工作啦。根据不同的场景,可使用如下几种方案:

方案一:docker retag

方案一可能是大多数人首先想到的办法,也是最简单粗暴的方法。就是在一台机器上使用 docker pull 下 docker registry 中的所有镜像,然后再 docker retag 一下,再 docker push 到 harbor 中。

如果之前看过我写的《深入浅出容器镜像的一生》和 《镜像搬运工 skopeo 初体验》,并且已经在日常生活中使用 skopeo ,一定会觉得这并不是个聪明的方案,因为 docker pull –> docker tag –> docker pull 的过程中会对镜像的 layer 进行解压缩。对于只是将镜像从一个 registry 复制到另一个 registry 来说,这些 docker 在这些过程中做了很多无用功。详细的原理可以参考上述两篇文章,在此不再赘述。

为了追求高效,我们不使用 docker retag 方案,下面看一下方案二:

方案二:skopeo

在《镜像搬运工 skopeo 初体验》一文中介绍过可以使用 skopeo copy 直接从一个 registry 中复制镜像原始 blobs 到另一个 registry 中,在此期间不会涉及镜像 layer 解压缩操作。在性能和耗时两个角度上,都比使用 docker 的方式高效很多。

  •  使用 skopeo copy

  •  使用 skopeo sync

无论是 docker 和 skopeo 本质上都是通过 registry 的 HTTP API 下载和上传镜像的,在这过程中还是多了不少 HTTP 请求的,如果走的是 HTTPS 的话,还涉及了 HTTPS 加密和解密的过程,这期间有很多无用功。那么还有没有更好的办法?

方案三:迁移存储目录

文章开头提到 harbor 的后端镜像存储也是使用的 docker registry,对于一个 registry 来说,只要是使用的是 Docker Distribution V2 ,它后端的存储目录结构都是一模一样的。那为什么不直接将 registry 的存储目录打包复制并解压到 harbor 的 registry 存储目录?这样又能保证所有的镜像都迁移过去,不会落下任何一个。

对于 harbor 1.x 版本来讲,将 docker registry 的存储目录直接迁移到 harbor 的 registry 存储目录,然后删除 harbor 的 redis 数据(因为 harbor 的 redis 缓存了镜像的元数据信息),重启 harbor 就好了。重启 harbor 之后,harbor 会调用后端的 registry 去提取镜像的元数据信息并存储到 redis 中。这样就完成了迁移的工作。

在 docker registry 机器上备份 registry 存储目录

备份完成之后将 docker.tar scp 到 harbor 机器上,然后在 harbor 机器上恢复 registry 存储目录

这样迁移之后可能会遇到无法往 harbor push 镜像的问题。因为 docker registry 容器内 registry 存储目录的所属和所属组为 root,而 harbor registry 容器内 registry 存储目录的所属和所属组为 10000:10000,二者权限并不相同,会导致 harbor 无法 push 镜像。因此在迁移完成之后需要修改一下 harbor registry 目录的所属和所属组。

方案四

对于 harbor 2.x 来讲,由于 harbor 强化了 Artifact 的元数据管理能力,即元数据要在 push 或者 sync 到 harbor 时写入到 harbor 自身的数据库中。在 harbor 看来只要数据库中没有这个 Artifact 的 manifest 信息或者没有这一层 layer 的信息,harbor 都会认为该 Artifact 或者 layer 不存在,返回 404 的错误。按照方案三直接而将 docker registry 存储目录解压到 harbor 的 registry 存储目录的方法行不通的。因为是将镜像解压到 registry 存储中的,虽然在 harbor 的 registry 容器看来是有镜像的,但因为 harbor 的数据库中没有镜像,harbor 就会认为没有镜像。那么现在看来只能通过方案二使用 skopeo 将镜像一个一个地 push 到 harbor 中了。

但对于某些特定的场景下,不能像方案二那样拥有一个 docker registry 的 HTTP 服务,只有一个 docker registry 的压缩包,这如何将 docker registry 的存储目录中的镜像迁移到 harbor 2.0 中呢?

在《镜像搬运工 skopeo 初体验》中提到过 skopeo 支持的镜像格式有如下几种:

需要注意的是,这几种镜像的名字,对应着镜像存在的方式,不同存在的方式对镜像的 layer 处理的方式也不一样,比如 docker:// 这种方式是存在 registry 上的;docker-daemon: 是存在本地 docker pull 下来的;再比如 docker-archive 是通过 docker save 出来的镜像;而 dir: 是镜像以文件夹的形式保存的。同一个镜像有这几种存在的方式就像水有气体、液体、固体一样。可以这样去理解,他们表述的都是同一个镜像,只不过是存在的方式不一样而已。

既然镜像是存放在 registry 存储目录里的,那么使用 dir 的形式直接从文件系统读取镜像,理论上来讲会比方案二要好一些。虽然 skopeo 支持 dir 格式的镜像,但 skopeo 目前并不支持直接使用 registry 的存储目录,所以还是需要想办法将 docker registry 存储目录里的每一个镜像转换成 skopeo dir 的形式。

skopeo dir

那么先来看一下 skopeo dir 是什么样子的?

为了方便测试方案的可行性,先使用 skopeo 命令先从 docker hub 上拉取一个镜像,并保存为 dir,命令如下:

使用 tree 命令查看一下 alpine 文件夹的目录结构,如下:

从文件名和大小以及文件的内省我们可以判断出,manifest 文件对应的就是镜像的 manifests 文件;类型为 ASCII text 的文件正是镜像的 image config 文件,里面包含着镜像的元数据信息。而另一个 gzip compressed data 文件不就是经过 gzip 压缩过的镜像 layer 嘛。看一下 manifest 文件的内容也再次印证了这个结论:

  •  镜像的 config 字段对应的正是 e50c909a8df2,而文件类型正是 image.v1+json 文本文件。
  •  镜像的 layer 字段对应的也正是 4c0d98bf9879 而文件类型正是 .tar.gzip gzip 压缩文件。

从 registry 存储目录中捞镜像出来

接下来到本文的较为精彩的地方了。如何从 registry 存储里“捞”镜像出来,转换成 skopeo 所支持的 dir 格式。

  •  首先要得到镜像的 manifests 文件,从 manifests 文件中可以得到该镜像的所有 blob 文件。例如对于 registry 存储目录中的 library/alpine:latest 镜像来讲,它在 registry 中是这样存放的:

1.通过 repositories/library/alpine/_manifests/tags/latest/current/link 文件得到 alpine 镜像 lasts 这个 tag 的 manifests 文件的 sha256 值,然后根据这个 sha256 值去 blobs 找到镜像的 manifests 文件;

2.根据 current/link 文件中的 sha256 值在 blobs 目录下找到与之对应的文件,blobs 目录下对应的 manifests 文件为 blobs/sha256/39/39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01/data;

3.使用正则匹配,过滤出 manifests 文件中的所有 sha256 值,这些 sha256 值就对应着 blobs 目录下的 image config 文件和 image layer 文件;

4.根据 manifests 文件就可以得到 blobs 目录中镜像的所有 layer 和 image config 文件,然后将这些文件拼成一个 dir 格式的镜像,在这里使用 cp 的方式将镜像从 registry 存储目录里复制出来,过程如下:

最终得到的镜像格式如下:

和上面的 skopeo copy 出来的 dir 文件夹对比一下,除了一个无关紧要的 version 文件,其他的都一摸一样。

5.再优化一下,将步骤 4 中的 cp 操作修改成硬链接操作,能极大减少磁盘的 IO 操作。需要注意:硬链接文件不能跨分区,所以要和 registry 存储目录在同一个分区下才行。

然后使用 skopeo copy 或者 skopeo sync 将捞出来的镜像 push 到 harbor

  •  使用 skopeo copy

  •  使用 skopeo sync 需要注意的是,skopeo sync 的方式是同步 project 级别的,镜像的 name 和 tag 就对应的是目录的名称

实现脚本

其实修改一下 skopeo 的源码应该也是可以无缝支持 registry 存储目录的。

对比

对比总结一下以上几种方案:

  •  方案一:上手成本低,适用于镜像数量比较多少,无需安装 skopeo 的情况,缺点是性能较差;
  •  方案二:适用于两个 registry 之间同步复制镜像,如将 docker hub 中的一些公共镜像复制到公司内网的镜像仓库中。
  •  方案三:适用于镜像仓库之间进行迁移,性能是所有方案里最好的,需要额外注意的是如果目的镜像仓库是 harbor 2.x,是无法使用这种方式的。
  •  方案四:是方案三的妥协版,为了适配 harbor 2.0 ,因为需要重新将镜像 push 到 harbor ,所以性能上要比方案三差一些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/337402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode 2788. 按分隔符拆分字符串

我们可以先自己模拟一下分隔字符串的过程。如果只是简单的,遇到分隔符,将分隔符前后的子串加入结果的List,那么很显然并没有考虑到一个String中有多个字符串的情况。一种比较容易想到的方法是: 先对List中每个字符串遍历&#xf…

HBase节点故障的容错方案

HBase节点故障的容错方案 1. Master高可用1.1 选主和HA切换逻辑 2. RS高可用2.1 感知RS节点异常2.2 异常DN上的数据处理 4. 疑问和思考5. 参考文档 本文主要探讨hbase集群的高可用容错方案和容错能力的探讨。涉及Master和RS相关组件,在出现单机故障时相关的容错方案…

Node.js Stream.pipeline() Method

Why Stream.pipeline 通过流我们可以将一大块数据拆分为一小部分一点一点的流动起来,而无需一次性全部读入,在 Linux 下我们可以通过 | 符号实现,类似的在 Nodejs 的 Stream 模块中同样也为我们提供了 pipe() 方法来实现。 未使用 Stream p…

实时云渲染服务:流式传输 VR 和 AR 内容

想象一下无需专用的物理计算机,甚至无需实物连接,就能获得高质量的 AR/VR 体验是种什么样的体验? 过去,与 VR 交互需要专用的高端工作站,并且根据头显、壁挂式传感器和专用的物理空间。VR 中的复杂任务会突破传感器范…

快速傅里叶变化检测轻微划痕

像这种轻微划痕,普通算法鲁棒性差,通用性也不是很好,通过一些特殊处理,基本上可以满足客户需求. 图像处理,检测无非这个几个步骤. 预处理----分割----筛选—满足设定条件NG read_image (Image, ‘轻微划痕.bmp’) dev_close_window() get_image_size(Image, Width, Height) dev…

Chatgpt+Comfyui绘图源码线上部署文档

源码仓库: https://gitee.com/BTYY/wailikeji-chatgpt 其他文档地址: ChatgptComfyui绘图源码运营文档 ChatgptComfyui绘图源码说明及本地部署文档 一、云服务器购买 (一)购买云服务 有两种部署方案,不同方案对服务…

【MongoDB】下载安装、指令操作

目录 1.下载安装 2.指令 2.1.基础操作指令 2.2.增加 2.3.查询 2.4.修改 2.5.删除 前言: 关于MongoDB的核心概念请移步: 【文档数据库】ES和MongoDB的对比-CSDN博客 1.下载安装 本文以安装Windows版本的mongodb为例,Linux版本的其实…

IP劫持的危害分析及应对策略

在当今数字化时代,网络安全问题备受关注,其中IP劫持是一种常见而危险的威胁。本文将深入探讨IP劫持的危害,并提供一些有效的应对策略。 第一部分:IP劫持的定义 IP劫持是指黑客通过各种手段获取并篡改目标IP地址的控制权&#xf…

如何在地图资源下载工具中下载和共享自定义资源

在获取GIS或遥感资源时,有时候可能会有一些您自己的下载资源!您也可以在地图资源下载工具增加这些下载资源!这样既可以方便以后下载,也可以与其它人分享下载资源! 设置方式如下: 下载方式如下:…

【汇编】 13.3 对int iret和栈的深入理解

书中示例 assume cs:codecode segment start:mov ax,csmov ds,axmov si,offset lpmov ax,0mov es,axmov di,200hmov cx,offset end0-offset lpcldrep movsb ;lp到end0的指令传送到0:200处mov ax,0mov es,axmov word ptr es:[7ch*4],200hmov word ptr es:[7ch*42],0 ;设置7c表项…

NeRF - 神经辐射场 原理分析与解释

标题:NeRF:Representing Scenes as Neural Radiance Fields for View Synthesis 顾名思义:通过NeRF 神经辐射场合成新视角来表达场景 这是一篇来源于伯克利大学的论文研究 摘要 论文提出了一种方法,可以通过优化一个连续体积场…

力扣每日一题---1547. 切棍子的最小成本

//当我们将棍子分段之后,我们是不是想到了怎么组合这些棍子 //并且这些棍子有一个性质就是只能与相邻的进行组合 //暴力搜索的话复杂度很高 //在思考暴力搜索的时候,我们发现一个规律 //比如棍子长度1 2 1 1 2 //那么与最后一个2组合的棍子有&#xff0c…

「绝世唐门」七怪一死六伤,98级玄子饕餮真身,伊莱克斯宣布神位

Hello,小伙伴们,我是拾荒君。 《斗罗大陆Ⅱ绝世唐门》第32期超前爆料,据透露史莱克监察团深入邪魂师的老巢,发现许多城中的百姓遭到残忍的毒手。为了对抗这些残忍的邪魂师,史莱克监察团成员纷纷发动武魂,展现出强大的…

人工智能原理实验2(1)——八数码问题(BFS、DFS、UCS、IDS、A*算法)

🧡🧡实验内容🧡🧡 要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态(左)到目标状态(右) 🧡🧡BFS、DFS实现🧡…

使用Scrapy 爬取“http://tuijian.hao123.com/”网页中左上角“娱乐”、“体育”、“财经”、“科技”、历史等名称和URL

一、网页信息 二、检查网页,找出目标内容 三、根据网页格式写正常爬虫代码 from bs4 import BeautifulSoup import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/53…

恢复因各种情况丢失的数据和文件的恢复软件汇集。

数据和文件恢复软件工具是直观的应用程序,可以从各种存储介质中恢复有价值且敏感的业务相关数据。这些宝贵的救生应用程序使企业能够恢复因不可预测的情况而丢失的数据。 存储介质解决方案可能会因网络攻击、病毒、数据泄露、硬盘故障等多种原因而丢失或损坏数据。…

Dart安装(Winodws)

Dart官网: https://dart.dev/ 一、命令行安装 https://dart.dev/get-dart You can install the Dart SDK using Chocolatey. error Important: These commands require administrator rights. Here’s one way to open a Command Prompt window that has admin …

ROS第 12 课 Launch 启动文件的使用方法

文章目录 第 12 课 Launch 启动文件的使用方法1.本节前言2.Lanuch 文件基本语法2.2 参数设置2.3 重映射嵌套 3.实操练习 第 12 课 Launch 启动文件的使用方法 1.本节前言 我们在前面的教程里面通过命令行来尝试运行新的节点。但随着创建越来越复杂的机器人系统中,打…

前后置、断言、提取变量、数据库操作功能

前置操作和后置操作都是 API 请求在发送和响应过程中执行的脚本,主要用于在发起 API 请求前和获得响应后完成验证或执行某些操作,目的是为了提高 API 调试和测试的效率,并确保接口的正确性。 前置操作​ 前置操作是在 API 请求之前执行的脚本…

[计算机网络]基本概念

目录 1.ip地址和端口号 1.1IP地址 1.2端口号 2.认识协议 2.1概念: 2.2知名协议的默认端口 3.五元组 4.协议分层 4.1分层的作用 4.2OSI七层模型 4.3TCP/IP五层(四层)模型 ​编辑4.4网络设备对应的分层: ​编辑以下为跨…