harbor拉取全部镜像

news/2025/3/1 14:45:58/

本脚本通过harbor v2.0 API请求,采用三层for循环,分别是project、repository、tag三层来将拉取全部镜像到本地,tag的名称列表输出到imagelist文件中。并有两三个优化改编版本。

文章目录

    • 拉取harbor仓库全部镜像
    • 拉取全部repository中最新的几个镜像
    • 拉取某个project下所有镜像
      • 用法
      • 脚本

拉取harbor仓库全部镜像

  • pull-whole-reg.sh
#!/bin/bash# Harbor 配置
HARBOR_URL="dockerhub.local:41104"
USERNAME="admin"
PASSWORD='<your_pass_word_here>'# 日志文件
LOGFILE="harbor_pull.log"
IMAGELIST="imagelist"# 清空日志文件和镜像列表
> "$LOGFILE"
> "$IMAGELIST"# 禁用缓冲并统一日志输出
exec > >(stdbuf -oL tee -a "$LOGFILE") 2>&1# 登录 Harbor
echo "Logging in to Harbor..."
if ! docker login "$HARBOR_URL" -u "$USERNAME" -p "$PASSWORD"; thenecho "[ERROR] Failed to login to Harbor. Check $LOGFILE for details."exit 1
fi# 获取总项目数量
TOTAL_PROJECTS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')
echo "Total projects: $TOTAL_PROJECTS"# 分页大小
PAGE_SIZE=10# 计算总页数
TOTAL_PAGES=$(( (TOTAL_PROJECTS + PAGE_SIZE - 1) / PAGE_SIZE ))# 获取所有项目
PROJECTS=""
for ((PAGE=1; PAGE<=TOTAL_PAGES; PAGE++)); doecho "Fetching projects (page $PAGE of $TOTAL_PAGES)..."PAGE_PROJECTS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects?page=$PAGE&page_size=$PAGE_SIZE" | jq -r '.[].name')PROJECTS="$PROJECTS $PAGE_PROJECTS"
done# 将字符串转换为数组
project_array=($PROJECTS)# 获取数组的长度
array_length=${#project_array[@]}# 遍历数组并输出索引和值
for ((index = 0; index < array_length; index++)); dovalue=${project_array[$index]}echo "[INFO] detect repository $((index+1)): $value"
done# 遍历每个项目
for PROJECT in $PROJECTS; doecho "Processing project: $PROJECT"# 获取项目下的所有镜像仓库(分页)TOTAL_REPOS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')REPO_PAGES=$(( (TOTAL_REPOS + PAGE_SIZE - 1) / PAGE_SIZE ))REPOS=""for ((REPO_PAGE=1; REPO_PAGE<=REPO_PAGES; REPO_PAGE++)); doecho "Fetching repositories for project $PROJECT (page $REPO_PAGE of $REPO_PAGES)..."PAGE_REPOS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories?page=$REPO_PAGE&page_size=$PAGE_SIZE" | jq -r '.[].name')REPOS="$REPOS $PAGE_REPOS"done# 遍历每个镜像仓库for REPO in $REPOS; doecho "Processing repository: $REPO"# 提取 repository_name 部分(去掉项目名称)REPO_NAME=$(echo "$REPO" | awk -F '/' '{print $2}')# 如果 repository_name 包含多层路径,则进行双重 URL 编码if [[ "$REPO" == */*/* ]]; thenREPO_NAME=$(echo "$REPO" | awk -F '/' '{print $2 "/" $3}' | sed 's|/|%252F|g')fi# 获取镜像仓库的所有 artifacts(分页)TOTAL_ARTIFACTS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')ARTIFACT_PAGES=$(( (TOTAL_ARTIFACTS + PAGE_SIZE - 1) / PAGE_SIZE ))ARTIFACTS=""for ((ARTIFACT_PAGE=1; ARTIFACT_PAGE<=ARTIFACT_PAGES; ARTIFACT_PAGE++)); doecho "Fetching artifacts for repository $REPO (page $ARTIFACT_PAGE of $ARTIFACT_PAGES)..."PAGE_ARTIFACTS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts?page=$ARTIFACT_PAGE&page_size=$PAGE_SIZE" | jq -r '.[].digest')ARTIFACTS="$ARTIFACTS $PAGE_ARTIFACTS"done# 遍历每个 artifact 并获取其 tagsfor ARTIFACT in $ARTIFACTS; doTAGS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts/$ARTIFACT/tags" | jq -r '.[].name')for TAG in $TAGS; doIMAGE_NAME="$HARBOR_URL/$REPO:$TAG"echo "Pulling image: $IMAGE_NAME"if docker pull "$IMAGE_NAME"; thenecho "Dumping tags to $IMAGELIST: $IMAGE_NAME"echo "$IMAGE_NAME" >> "$IMAGELIST"sync  # 强制写入磁盘elseecho "[ERROR] Failed to pull image: $IMAGE_NAME"fiecho "---------------------------------------------------------------"donedonedone
doneecho "All images have been pulled. Check $LOGFILE for details."

拉取全部repository中最新的几个镜像

有的时候太多的老的镜像版本并没有用,那么按照时间排序,最新的在最前面,每个repository拉取最新的几个。

比如

library/loki:v4
library/loki:v3
library/loki:v2
library/loki:v1

只要前三个也就是v2-v4, 此时使用如下脚本:

#!/bin/bash# 默认获取所有 artifacts
TOP_N="all"
DRY_RUN=false# 解析命令行参数
while [[ $# -gt 0 ]]; docase "$1" in-n|--topN)TOP_N="$2"shift 2;;--dry-run)DRY_RUN=trueshift;;*)echo "Unknown option: $1"exit 1;;esac
done# Harbor 配置
HARBOR_URL="dockerhub.local:41104"
USERNAME="admin"
PASSWORD='<your_pass_word_here>'# 日志文件
LOGFILE="harbor_pull.log"
ERR_LOGFILE="harbor_pull_err.log"
IMAGELIST="repo-TopN-imagelist"
STATISTIC_LOG="statistic.log"# 清空日志文件和镜像列表
> "$LOGFILE"
> "$IMAGELIST"
> "$ERR_LOGFILE"
> "$STATISTIC_LOG"# 禁用缓冲并统一日志输出
exec > >(stdbuf -oL tee -a "$LOGFILE") 2>&1# 登录 Harbor
echo "Logging in to Harbor..."
if ! docker login "$HARBOR_URL" -u "$USERNAME" -p "$PASSWORD"; thenecho "[ERROR] Failed to login to Harbor. Check $LOGFILE for details."exit 1
fi# 获取总项目数量
TOTAL_PROJECTS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')
echo "Total projects: $TOTAL_PROJECTS"
echo "Total projects: $TOTAL_PROJECTS" >> "$STATISTIC_LOG"# 分页大小
PAGE_SIZE=10# 计算总页数
TOTAL_PAGES=$(( (TOTAL_PROJECTS + PAGE_SIZE - 1) / PAGE_SIZE ))# 获取所有项目
PROJECTS=""
for ((PAGE=1; PAGE<=TOTAL_PAGES; PAGE++)); doecho "Fetching projects (page $PAGE of $TOTAL_PAGES)..."PAGE_PROJECTS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects?page=$PAGE&page_size=$PAGE_SIZE" | jq -r '.[].name')PROJECTS="$PROJECTS $PAGE_PROJECTS"
done# 将字符串转换为数组
project_array=($PROJECTS)# 获取数组的长度
array_length=${#project_array[@]}# 遍历数组并输出索引和值
for ((index = 0; index < array_length; index++)); dovalue=${project_array[$index]}echo "[INFO] detect repository $((index+1)): $value"
done# 长分隔符
SEPARATOR="================================================================================="# 遍历每个项目
for PROJECT in $PROJECTS; doecho "$SEPARATOR" >> "$STATISTIC_LOG"echo "Processing project: $PROJECT"echo "Processing project: $PROJECT" >> "$STATISTIC_LOG"# 获取项目下的所有镜像仓库(分页)TOTAL_REPOS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')REPO_PAGES=$(( (TOTAL_REPOS + PAGE_SIZE - 1) / PAGE_SIZE ))REPOS=""for ((REPO_PAGE=1; REPO_PAGE<=REPO_PAGES; REPO_PAGE++)); doecho "Fetching repositories for project $PROJECT (page $REPO_PAGE of $REPO_PAGES)..."PAGE_REPOS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories?page=$REPO_PAGE&page_size=$PAGE_SIZE" | jq -r '.[].name')REPOS="$REPOS $PAGE_REPOS"done# 统计项目下的镜像仓库数量echo "Total repositories in project $PROJECT: $(echo "$REPOS" | wc -w)" >> "$STATISTIC_LOG"# 遍历每个镜像仓库for REPO in $REPOS; doecho "Processing repository: $REPO"echo "  Repository: $REPO" >> "$STATISTIC_LOG"# 提取 repository_name 部分(去掉项目名称)REPO_NAME=$(echo "$REPO" | awk -F '/' '{print $2}')# 如果 repository_name 包含多层路径,则进行双重 URL 编码if [[ "$REPO" == */*/* ]]; thenREPO_NAME=$(echo "$REPO" | awk -F '/' '{print $2 "/" $3}' | sed 's|/|%252F|g')fi# 如果指定了 TOP_N,则只取最新的 N 个 artifactsif [[ "$TOP_N" != "all" ]]; thenecho "[INFO] fetching [$PROJECT/$REPO_NAME] $TOP_N tags..."elseTOP_N=10fiARTIFACTS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts?page=1&page_size=$TOP_N" | jq -r '.[].digest')# 统计镜像仓库下的 Tag 数量TAG_COUNT=0# 遍历每个 artifact 并获取其 tagsfor ARTIFACT in $ARTIFACTS; doTAGS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts/$ARTIFACT/tags" | jq -r '.[].name')for TAG in $TAGS; doIMAGE_NAME="$HARBOR_URL/$REPO:$TAG"echo "    Tag: $TAG" >> "$STATISTIC_LOG"if [[ "$DRY_RUN" == true ]]; thenecho "Dry-run: Found image: $IMAGE_NAME"echo "$IMAGE_NAME" >> "$IMAGELIST"elseecho "Pulling image: $IMAGE_NAME"if docker pull "$IMAGE_NAME"; thenecho "Dumping tags to $IMAGELIST: $IMAGE_NAME"echo "$IMAGE_NAME" >> "$IMAGELIST"sync  # 强制写入磁盘elseecho "[ERROR] Failed to pull image: $IMAGE_NAME" >> "$ERR_LOGFILE"fifiecho "---------------------------------------------------------------"TAG_COUNT=$((TAG_COUNT + 1))donedoneecho "  Total tags in repository $REPO: $TAG_COUNT" >> "$STATISTIC_LOG"done
doneecho "All images have been pulled. Check $LOGFILE for details."

拉取某个project下所有镜像

那么如果想要拉取某个project下所有镜像,一般一个系统的所有镜像都会放到一个项目中。

比如dockerhub.local:31104/test-sys/minio:v1test-sys就是一个project。

用法

bash pull-project-topN.sh -p test-sys -n 3

脚本

#!/bin/bash# 默认获取所有 artifacts
TOP_N="all"
DRY_RUN=false
SPECIFIC_PROJECT=""# 解析命令行参数
while [[ $# -gt 0 ]]; docase "$1" in-n|--topN)TOP_N="$2"shift 2;;--dry-run)DRY_RUN=trueshift;;-p|--project)SPECIFIC_PROJECT="$2"shift 2;;*)echo "Unknown option: $1"exit 1;;esac
done# Harbor 配置
HARBOR_URL="dockerhub.local:41104"
USERNAME="admin"
PASSWORD='<your_pass_word_here>'# 日志文件
LOGFILE="harbor_pull.log"
ERR_LOGFILE="harbor_pull_err.log"
IMAGELIST="repo-TopN-imagelist"
STATISTIC_LOG="statistic.log"# 分页大小
PAGE_SIZE=10# 检查 PAGE_SIZE 是否为 0
if [ "$PAGE_SIZE" -eq 0 ]; thenecho "[ERROR] PAGE_SIZE cannot be 0. Please set a valid value."exit 1
fi# 清空日志文件和镜像列表
> "$LOGFILE"
> "$IMAGELIST"
> "$ERR_LOGFILE"
> "$STATISTIC_LOG"# 禁用缓冲并统一日志输出
exec > >(stdbuf -oL tee -a "$LOGFILE") 2>&1# 登录 Harbor
echo "Logging in to Harbor..."
if ! docker login "$HARBOR_URL" -u "$USERNAME" -p "$PASSWORD"; thenecho "[ERROR] Failed to login to Harbor. Check $LOGFILE for details."exit 1
fi# 如果指定了特定项目,直接处理该项目,否则获取所有项目
if [ -n "$SPECIFIC_PROJECT" ]; thenPROJECTS="$SPECIFIC_PROJECT"echo "Processing specific project: $SPECIFIC_PROJECT"
else# 获取总项目数量TOTAL_PROJECTS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')echo "Total projects: $TOTAL_PROJECTS"echo "Total projects: $TOTAL_PROJECTS" >> "$STATISTIC_LOG"# 计算总页数TOTAL_PAGES=$(( (TOTAL_PROJECTS + PAGE_SIZE - 1) / PAGE_SIZE ))# 获取所有项目PROJECTS=""for ((PAGE=1; PAGE<=TOTAL_PAGES; PAGE++)); doecho "Fetching projects (page $PAGE of $TOTAL_PAGES)..."PAGE_PROJECTS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects?page=$PAGE&page_size=$PAGE_SIZE" | jq -r '.[].name')PROJECTS="$PROJECTS $PAGE_PROJECTS"done
fi# 将字符串转换为数组
project_array=($PROJECTS)# 获取数组的长度
array_length=${#project_array[@]}# 遍历数组并输出索引和值
for ((index = 0; index < array_length; index++)); dovalue=${project_array[$index]}echo "[INFO] detect repository $((index+1)): $value"
done# 长分隔符
SEPARATOR="================================================================================="# 遍历每个项目
for PROJECT in $PROJECTS; doecho "$SEPARATOR" >> "$STATISTIC_LOG"echo "Processing project: $PROJECT"echo "Processing project: $PROJECT" >> "$STATISTIC_LOG"# 获取项目下的所有镜像仓库(分页)TOTAL_REPOS=$(curl -s -X GET -I -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories" | grep -i "X-Total-Count" | awk '{print $2}' | tr -d '\r')# 计算仓库总页数REPO_PAGES=$(( (TOTAL_REPOS + PAGE_SIZE - 1) / PAGE_SIZE ))REPOS=""for ((REPO_PAGE=1; REPO_PAGE<=REPO_PAGES; REPO_PAGE++)); doecho "Fetching repositories for project $PROJECT (page $REPO_PAGE of $REPO_PAGES)..."PAGE_REPOS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories?page=$REPO_PAGE&page_size=$PAGE_SIZE" | jq -r '.[].name')REPOS="$REPOS $PAGE_REPOS"done# 统计项目下的镜像仓库数量echo "Total repositories in project $PROJECT: $(echo "$REPOS" | wc -w)" >> "$STATISTIC_LOG"# 遍历每个镜像仓库for REPO in $REPOS; doecho "Processing repository: $REPO"echo "  Repository: $REPO" >> "$STATISTIC_LOG"# 提取 repository_name 部分(去掉项目名称)REPO_NAME=$(echo "$REPO" | awk -F '/' '{print $2}')# 如果 repository_name 包含多层路径,则进行双重 URL 编码if [[ "$REPO" == */*/* ]]; thenREPO_NAME=$(echo "$REPO" | awk -F '/' '{print $2 "/" $3}' | sed 's|/|%252F|g')fi# 如果指定了 TOP_N,则只取最新的 N 个 artifactsif [[ "$TOP_N" != "all" ]]; thenecho "[INFO] fetching [$PROJECT/$REPO_NAME] $TOP_N tags..."elseTOP_N=10fiARTIFACTS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts?page=1&page_size=$TOP_N" | jq -r '.[].digest')# 统计镜像仓库下的 Tag 数量TAG_COUNT=0# 遍历每个 artifact 并获取其 tagsfor ARTIFACT in $ARTIFACTS; doTAGS=$(curl -s -u "$USERNAME:$PASSWORD" "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories/$REPO_NAME/artifacts/$ARTIFACT/tags" | jq -r '.[].name')for TAG in $TAGS; doIMAGE_NAME="$HARBOR_URL/$REPO:$TAG"echo "    Tag: $TAG" >> "$STATISTIC_LOG"if [[ "$DRY_RUN" == true ]]; thenecho "Dry-run: Found image: $IMAGE_NAME"echo "$IMAGE_NAME" >> "$IMAGELIST"elseecho "Pulling image: $IMAGE_NAME"if docker pull "$IMAGE_NAME"; thenecho "Dumping tags to $IMAGELIST: $IMAGE_NAME"echo "$IMAGE_NAME" >> "$IMAGELIST"sync  # 强制写入磁盘elseecho "[ERROR] Failed to pull image: $IMAGE_NAME" >> "$ERR_LOGFILE"fifiecho "---------------------------------------------------------------"TAG_COUNT=$((TAG_COUNT + 1))donedoneecho "  Total tags in repository $REPO: $TAG_COUNT" >> "$STATISTIC_LOG"done
doneecho "All images have been pulled. Check $LOGFILE for details."

http://www.ppmy.cn/news/1575791.html

相关文章

AF3 DataPipeline类process_multiseq_fasta 方法解读

AlphaFold3 data_pipeline 模块DataPipeline类的 process_multiseq_fasta 方法用于处理多序列 FASTA 文件,生成 AlphaFold3 结构预测所需的特征,适用于多链复合物的预测。它结合了 Minkyung Baek 在 Twitter 上提出的“AlphaFold-Gap”策略,即通过在多链 MSA 中插入固定长度…

大模型的参数长什么样子,ds回答

嗯&#xff0c;用户问的是大模型的参数长什么样子&#xff0c;还要举个例子。那我得先理解大模型的参数到底是什么样的结构。根据之前提供的搜索结果&#xff0c;比如参考‌12&#xff0c;大模型的参数主要包括权重矩阵、偏置向量等。比如说&#xff0c;像LLaMA或者baichuan这样…

TP-LINK路由器如何设置网段、网关和DHCP服务

目标 ①将路由器的网段由192.168.1.XXX改为192.168.5.XXX ②确认DHCP是启用的&#xff0c;并将DHCP的IP池的范围设置为排除自己要手动指定的IP地址&#xff0c;避免IP冲突。 01-复位路由器 路由器按住复位键10秒以上进行重置操作 02-进入路由器管理界面 电脑连接到路由器&…

win11编译pytorch cuda128版本流程

Geforce 50xx系显卡最低支持cuda128&#xff0c;torch cu128 release版本目前还没有释放&#xff0c;所以自己基于2.6.0源码自己编译wheel包。 1. 前置条件 1. 使用visual studio installer 安装visual studio 2022&#xff0c;工作负荷选择【使用c的桌面开发】,安装完成后将…

React 中 useState 的 基础使用

概念&#xff1a;useState 是一个React Hook&#xff08;函数&#xff09;&#xff0c;它允许我们向组件添加状态变量&#xff0c;从而影响组件的渲染结果。 本质&#xff1a;和普通JS变量不同的是&#xff0c;状态变量一旦发生变化&#xff0c;组件的视图UI也会跟着变化&…

构建逻辑思维链(CoT)为金融AI消除幻觉(保险赔付篇)

在上一篇文章中&#xff0c;我们介绍了如何利用亚马逊云科技的Amazon Bedrock GuardRails自动推理检查应用于​​​​金融行业中利用AI应用的保险赔付审核场景&#xff0c;提升该场景下审核准确性&#xff0c;消除幻觉。在本案例中&#xff0c;我们将探讨一个利用AI帮助提升保险…

springboot rocketmq配置生产者和消息者

在Spring Boot中集成RocketMQ&#xff0c;你需要进行以下步骤来配置生产者和消费者。下面是一个简化的流程&#xff1a; 1. 添加依赖 首先&#xff0c;在你的pom.xml文件中添加RocketMQ的依赖项。确保你使用的是与Spring Boot兼容的版本。 <dependencies><!-- 其他…

算法日记31:leetcode341整数拆分(DFS->记忆化->DP)

一、题目 二、题解 1、动态规划解题思路&#xff1a; 1、重述问题 2、找到最后一步 3、去掉最后一步&#xff0c;问题变成了什么&#xff1f; 原问题的答案去掉最后一步的问题&#xff1f; 4、考虑边界2、结合题目具体分析&#xff1a; 假设我们拆出了 5 5 5为第k个数 三、…