Harbor记异常迁移恢复实践

[TOC]

0x00 记一次k8s集群搭建的Harbor私有仓库无法进行镜像拉取迁移恢复实践

描述: Harbor 是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源 Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。

前置知识了解:

环境说明: 由于Harbor是安装在Kubernetes集群内部,由于在调整集群的网络通信插件时, 无法通过浏览器访问工作节点+nodePort方式访问集群中的Harbor服务,同时外部也不能通过ingress来代理转发harbor,所以为了尽快的恢复镜像仓库,采用Skopeo工具以及如下方式进行镜像的迁移。

Kubernetes 版本: v1.22.2
  kubeadm version: &version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.2", GitCommit:"8b5a19147530eaac9476b0ab82980b4088bbc1b2", GitTreeState:"clean", BuildDate:"2021-09-15T21:37:34Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"}
skopeo 版本: 1.5.3-dev commit: df4d82b960572c19e9333381a203c0ac475766d7
Harbor 版本: v2.1.3-b6de84c5

$ kubectl get deploy -n harbor
  # NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
  # harbor-harbor-chartmuseum     1/1     1            1           300d
  # harbor-harbor-clair           1/1     1            1           300d
  # harbor-harbor-core            1/1     1            1           300d
  # harbor-harbor-jobservice      1/1     1            1           300d
  # harbor-harbor-notary-server   1/1     1            1           300d
  # harbor-harbor-notary-signer   1/1     1            1           300d
  # harbor-harbor-portal          1/1     1            1           300d
  # harbor-harbor-registry        1/1     1            1           300d

操作步骤:

Step 1.在工作节点上执行如下命令,查看仓库中存在的镜像信息。

# Harbor 默认用户和认证密钥(正式环境一定要更改哟)
USER="admin"
TOKEN="Harbor12345"

# 通过 Harbor API 查看镜像名称
curl --insecure -u ${USER}:${TOKEN} https://harbor.cloud/v2/_catalog 2>/dev/null|jq .repositories[]|tr -d '"' >> image_names.txt

# 查看 image_names.txt 输出结果
devops/bianmin
devops/bitnami-redis-cluster
devops/bmcx

Step 2.利用for循环获取Tags并拼接镜像与tag信息

for name in $(cat image_names.txt);do
  tags=`curl -u admin:Harbor12345 --insecure https://harbor.cloud/v2/${name}/tags/list 2>/dev/null|jq ".tags[]"|tr -d '"'`
  for tag in $tags;do echo $name:$tag >>image_tags.txt; done
done

# 查看 image_tags.txt 输出结果
devops/bianmin:1.0.7-SNAPSHOT
devops/bianmin:stress
devops/bitnami-redis-cluster:6.0.10-debian-10-r5
devops/bmcx:1.0.7-SNAPSHOT
devops/bmcx:1.1.0-SNAPSHOT
devops/bmcx:latest

Step 3.例如,我们找一个devops/bmcx:1.1.0-SNAPSHOT镜像分析其路径特征。

# 1.环境变量设置
REPO_DIR="docker/registry/v2/repositories"
BLOB_DIR="docker/registry/v2/blobs/sha256"
cd /storage/pvc/devops/harbor-harbor-harbor-registry-pvc-151479ef-44f1-44dd-960c-afcbf12ba8a8/

# 2.查看repositories目录中存在的所有镜像current路径
for image in $(find ${REPO_DIR} -type d -name "current"); do
echo ${image} >> repo_current.txt
done

# 3.查看指定bmcx:1.1.0-SNAPSHOT镜像的current路径
grep "1.1.0-SNAPSHOT" repo_current.txt

# 4.提取路径中的镜像相关信息
echo 'docker/registry/v2/repositories/devops/bmcx/_manifests/tags/1.1.0-SNAPSHOT/current' | awk -F '/' '{print $5"/"$6":"$9}'
# devops/bmcx:1.1.0-SNAPSHOT

# 5.查看该镜像link信息
cat 'docker/registry/v2/repositories/devops/bmcx/_manifests/tags/1.1.0-SNAPSHOT/current/link' | sed 's/sha256://'
  # 68acf0f6c61b11bb79d6787146ed3bd88850b9071b3b59d86439d55ae5e31928

# 6.查看该镜像link中各层
link=68acf0f6c61b11bb79d6787146ed3bd88850b9071b3b59d86439d55ae5e31928
cat docker/registry/v2/blobs/sha256/${link:0:2}/${link}/data
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
  "config": {
    "mediaType": "application/vnd.docker.container.image.v1+json",
    "size": 2429,
    "digest": "sha256:b938271c3bd17a187e5c95508adf49093f042cb176a3652c74a76e6d9770eb5b"
  },
  "layers": [
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 723146,
      "digest": "sha256:07a152489297fc2bca20be96fab3527ceac5668328a30fd543a160cd689ee548"
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 132,
      "digest": "sha256:8142e84f0be01a60008360c5d5592e3f02507968b548797513ef7d5080dd5d0c"
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 43984533,
      "digest": "sha256:702d51e3f3237c8ffbabeefec12934cc2a9e5b6f01fc414cf17f708ec1c09d0f"
    }
  ]
}

# 7.使用正则匹配出所有的 sha256 值然后排序去重
images_layer=docker/registry/v2/blobs/sha256/${link:0:2}/${link}/data
layers=$(grep -Eo "\b[a-f0-9]{64}\b" ${images_layer} | sort -n | uniq)
b938271c3bd17a187e5c95508adf49093f042cb176a3652c74a76e6d9770eb5b
07a152489297fc2bca20be96fab3527ceac5668328a30fd543a160cd689ee548   # 以此层为例
702d51e3f3237c8ffbabeefec12934cc2a9e5b6f01fc414cf17f708ec1c09d0f
8142e84f0be01a60008360c5d5592e3f02507968b548797513ef7d5080dd5d0c

# 8.查看镜像各层的数据压缩文件
layer=07a152489297fc2bca20be96fab3527ceac5668328a30fd543a160cd689ee548
ls ${BLOB_DIR}/${layer:0:2}/${layer}/data  # application/vnd.docker.image.rootfs.diff.tar.gzip

Step 4.将registry-v2存储的镜像转换为skopeo工具可以识别的目录架构, 即将 harbor 中的镜像导出为 skopeo dir 的形式。

# 定义生成 skopeo 目录
mkdir ./docker/skopeo/devops/bmcx:1.1.0-SNAPSHOT
ln ./docker/registry/v2/blobs/sha256/${link:0:2}/${link}/data ./docker/skopeo/devops/bmcx:1.1.0-SNAPSHOT/manifest.json

# 创建镜像各层硬链接
ln ./docker/registry/v2/blobs/sha256/b9/b938271c3bd17a187e5c95508adf49093f042cb176a3652c74a76e6d9770eb5b/data ./docker/skopeo/devops/bmcx:1.1.0-SNAPSHOT/b938271c3bd17a187e5c95508adf49093f042cb176a3652c74a76e6d9770eb5b

ln ./docker/registry/v2/blobs/sha256/07/
07a152489297fc2bca20be96fab3527ceac5668328a30fd543a160cd689ee548/data ./docker/skopeo/devops/bmcx:1.1.0-SNAPSHOT/07a152489297fc2bca20be96fab3527ceac5668328a30fd543a160cd689ee548

ln ./docker/registry/v2/blobs/sha256/70/702d51e3f3237c8ffbabeefec12934cc2a9e5b6f01fc414cf17f708ec1c09d0f/data ./docker/skopeo/devops/bmcx:1.1.0-SNAPSHOT/702d51e3f3237c8ffbabeefec12934cc2a9e5b6f01fc414cf17f708ec1c09d0f

ln ./docker/registry/v2/blobs/sha256/81/8142e84f0be01a60008360c5d5592e3f02507968b548797513ef7d5080dd5d0c

Step 5.最后利用如下skopeo copy命令将将 dir 格式的镜像复制到harbor中。

skopeo sync --insecure-policy --src-tls-verify=false --dest-tls-verify=false --src dir --dest docker ./docker/skopeo/devops/bmcx:1.1.0-SNAPSHOT harbor.weiyigeek.top/devops/bmcx:1.1.0-SNAPSHOT

Step 6.最后采用木子提供的shell脚本进行将k8s中harbor的registry数据进行批量同步操作。

#!/bin/bash
# Desc:Harbor v2.x
REGISTRY_DOMAIN="harbor.weiyigeek.top"
REGISTRY_PATH="/storage/pvc/devops/harbor-harbor-harbor-registry-pvc-151479ef-44f1-44dd-960c-afcbf12ba8a8"

# 切换到 registry 存储主目录下
cd ${REGISTRY_PATH}

# - 生成 skopeo sync 同步所需目录格式
gen_skopeo_dir() {
  # 定义 registry 存储的 blob 目录 和 repositories 目录,方便后面使用
  BLOB_DIR="docker/registry/v2/blobs/sha256"
  REPO_DIR="docker/registry/v2/repositories"

  # 定义生成 skopeo 目录
  SKOPEO_DIR="docker/skopeo"
  # 通过 find 出 current 文件夹可以得到所有带 tag 的镜像,因为一个 tag 对应一个 current 目录

  for image in $(find ${REPO_DIR} -type d -name "current"); do
    # 根据镜像的 tag 提取镜像的名字
    # 例如 image 的值为 "docker/registry/v2/repositories/devops/kubectl/_manifests/tags/1.16.6/current"
    name=$(echo ${image} | awk -F '/' '{print $5"/"$6":"$9}')
    link=$(cat ${image}/link | sed 's/sha256://')

    # 判断镜像是否需要同步,如不需则跳过,否则创建skopeo需要的对应目录。
    # flag=$(grep -c "${name}" /tmp/image_tags.txt)
    # 如果不行进行镜像过滤筛选则可以置为1即可。
    flag=1
    if [ $flag -ne 1 ];then
      echo "${name}" >> /tmp/not_push_image_tags.txt
      continue;
    else
      # 创建镜像的硬链接需要的目录
      mkdir -vp "${SKOPEO_DIR}/${name}"
      mfs="${BLOB_DIR}/${link:0:2}/${link}/data"
      # 硬链接镜像的 manifests 文件到目录的 manifest 文件
      ln ${mfs} ${SKOPEO_DIR}/${name}/manifest.json
      # 使用正则匹配出manifest.json文件中所有的 sha256 值,然后进行排序去重。
      layers=$(grep -Eo "\b[a-f0-9]{64}\b" ${mfs} | sort -n | uniq)
      # 遍历镜像各层的sha256编码,按照指定方式进行创建硬链接
      for layer in ${layers}; do
        # 硬链接 registry 存储目录里的镜像 layer 和 images config 到镜像的 dir 目录
        ln ${BLOB_DIR}/${layer:0:2}/${layer}/data ${SKOPEO_DIR}/${name}/${layer}
      done
    fi
  done
}

# - 使用 skopeo sync 将 dir 格式的镜像同步到 harbor
sync_image() {
  for project in $(ls ${SKOPEO_DIR}); do
    skopeo sync --insecure-policy --src-tls-verify=false --dest-tls-verify=false --src dir --dest docker ${SKOPEO_DIR}/${project} ${REGISTRY_DOMAIN}/${project}
  done
}

gen_skopeo_dir
sync_image

执行结果如下:

WeiyiGeek.skopeo 镜像同步

Step 7.镜像同步完成后,我们可以通过访问harbor前端UI界面进行查看同步后的镜像以及其tags信息。

WeiyiGeek.Harbor-UI

参考地址: https://blog.k8s.li/select-registry-images.html

原文地址:https://cloud.tencent.com/developer/article/2129893

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340