#!/bin/bash
desc='脚本说明:
1: 同步 arm、amd 镜像 (Docker Hub -> Harbor)
2: 导出镜像到本地 (从镜像地址 -> 本地 OCI 目录)
3: 导入镜像到 docker-daemon (本地 OCI 目录 -> Docker)
4: 导出镜像到本地 (指定私有仓库 -> 本地 OCI 目录)
5: 导入镜像到镜像仓库 (本地 OCI 目录 -> 目标仓库,保留原完整路径)
6: 同步amd64镜像到harbor (修复仅amd64的情况)
7: 导入镜像到 containerd (本地 OCI 目录 -> k8s/ctr)
8: 导入镜像到镜像仓库 (本地 OCI 目录 -> 目标仓库,**自动去除原域名**)
使用示例:
bash -x image-tools.sh 1
bash -x image-tools.sh 2 arm64
bash -x image-tools.sh 3 arm64
bash -x image-tools.sh 4 harbor.senses-ai.com arm64
bash -x image-tools.sh 5 sealos.hub:5000 arm64
bash -x image-tools.sh 6
bash -x image-tools.sh 7 k8s.io arm64
bash -x image-tools.sh 8 sealos.hub:5000 arm64
'
# 检查是否提供了位置参数
if [ $# -eq 0 ]; then
echo "$desc"
exit 1
fi
set -e
# 镜像列表文件
image_file="image.txt"
# 功能 1: 同步 arm、amd 镜像
sync_images() {
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
echo ">>> 处理镜像: $image"
if [ ! -z $1 ]; then
dest_project=base/${1}
else
dest_project=base
fi
src_project=''
src_image="docker.1ms.run/${image}"
# 目标镜像(多架构 manifest)
dest_image="harbor.senses-ai.com/${dest_project}/${image}"
echo "拉取 amd64"
docker pull --platform linux/amd64 "$src_image"
docker tag "$src_image" "${dest_image}-amd64"
docker push "${dest_image}-amd64"
echo "拉取 arm64"
docker pull --platform linux/arm64 "$src_image"
docker tag "$src_image" "${dest_image}-arm64"
docker push "${dest_image}-arm64"
# 删除中间镜像(可选)
docker rmi "$src_image" || true
# 创建 manifest
docker manifest create --amend "$dest_image" \
"${dest_image}-amd64" \
"${dest_image}-arm64"
# 注解(可选增强)
docker manifest annotate "$dest_image" "${dest_image}-amd64" --os linux --arch amd64
docker manifest annotate "$dest_image" "${dest_image}-arm64" --os linux --arch arm64
# 推送 manifest
docker manifest push "$dest_image"
echo ">>> ✅ 完成镜像: $image"
echo
done < "$image_file"
}
# 功能 2: 导出镜像到本地
export_images() {
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
src_image="${image}"
dest_image="${image}"
arch=${1:-amd64}
echo "导出镜像: $dest_image"
skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux "docker://${src_image}" "oci:data:${dest_image}"
echo ">>> ✅ 镜像 $dest_image 导出完成"
done < "$image_file"
}
# 功能 3: 导入镜像到 docker-daemon
import_images() {
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
src_image="${image}"
dest_image="${image}"
arch=${1:-amd64}
echo "导入镜像: $dest_image"
skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux "oci:data:${src_image}" "docker-daemon:${dest_image}"
echo ">>> ✅ 镜像 $dest_image 导入完成"
done < "$image_file"
}
# 功能 4: 导出镜像到本地 (指定源)
export_images_2() {
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
src_image="${image}"
dest_image="${image}"
src_repository=${1:-harbor.senses-ai.com}
arch=${2:-amd64}
echo "导出镜像: ${src_repository}/$dest_image"
skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux --dest-tls-verify=false --src-tls-verify=false "docker://${src_repository}/${dest_image}" "oci:data:${src_image}"
echo ">>> ✅ 镜像 $dest_image 导出完成"
done < "$image_file"
}
# 功能 5: 导入镜像到镜像仓库 (保留完��原路径)
import_images_2() {
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
src_image="${image}"
dest_image="${image}"
dest_repository=${1:-sealos.hub:5000}
arch=${2:-amd64}
echo "导入镜像: $dest_image"
skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux --dest-tls-verify=false --src-tls-verify=false "oci:data:${src_image}" "docker://${dest_repository}/${dest_image}"
echo ">>> ✅ 镜像 $dest_image 导入完成"
done < "$image_file"
}
# 功能 6: 同步amd64镜像到harbor
rsync_amd64() {
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
src_image="harbor.senses-ai.com/docker-hub/${image}"
dest_image="${image}"
dest_repository=${1:-harbor.senses-ai.com/base}
arch=${2:-amd64}
echo "导入镜像: $dest_image"
skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux --dest-tls-verify=false --src-tls-verify=false "docker://${src_image}" "docker://${dest_repository}/${dest_image}"
echo ">>> ✅ 镜像 $dest_image 导入完成"
done < "$image_file"
}
# 功能 7: 导入镜像到 containerd
import_to_containerd() {
if ! command -v ctr &> /dev/null; then
echo "错误: 未找到 ctr 命令。"
exit 1
fi
namespace=${1:-k8s.io}
arch=${2:-amd64}
echo ">>> 目标命名空间: $namespace"
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
src_path="oci:data:${image}"
tmp_tar="/tmp/import_ctr_${RANDOM}.tar"
echo "正在转换并导入镜像: $image"
if skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux \
"${src_path}" "docker-archive:${tmp_tar}:${image}"; then
ctr -n "$namespace" images import "$tmp_tar"
echo ">>> ✅ 镜像 $image 已导入到 containerd"
fi
rm -f "$tmp_tar"
done < "$image_file"
}
# 功能 8: 从本地 OCI 导入到镜像仓库 (自动去域名)
import_oci_clean_push() {
dest_repo=$1
arch=${2:-amd64}
[ -z "$dest_repo" ] && echo "❌ 错误: 请输入目标镜像仓库地址 (例如 sealos.hub:5000)" && exit 1
while read -r image; do
[[ -z "$image" || "$image" =~ ^# ]] && continue
# 1. 确定本地 OCI 目录名
# 因为功能 2 和 4 导出时,目录名就是 image.txt 里的完整字符串
src_image="${image}"
# 2. 构造目标镜像名 (截取域名)
# 如果 image 是 "gcr.io/google_containers/pause:3.2",image_suffix 变为 "google_containers/pause:3.2"
if [[ "$image" =~ ^[^/]+\.[^/]+/ ]]; then
image_suffix="${image#*/}"
else
image_suffix="$image"
fi
# 目标完整地址
dest_ref="docker://${dest_repo}/${image_suffix}"
echo "-----------------------------------------------"
echo "本地源: oci:data:${src_image}"
echo "目标 : ${dest_ref}"
# 3. 执行导入: 本地 OCI -> 目标 Registry
skopeo copy --insecure-policy --multi-arch system --override-arch ${arch} --override-os linux \
--src-tls-verify=false --dest-tls-verify=false \
"oci:data:${src_image}" "$dest_ref"
echo ">>> ✅ 导入成功: ${dest_repo}/${image_suffix}"
done < "$image_file"
}
# 根据位置参数调用相应的功能
case "$1" in
1)
echo ">>> 执行功能 1: 同步 arm、amd 镜像"
sync_images $2
;;
2)
echo ">>> 执行功能 2: 完整镜像地址导出到本地"
export_images $2
;;
3)
echo ">>> 执行功能 3: 完整镜像地址导入到 docker-daemon"
import_images $2
;;
4)
echo ">>> 执行功能 4: 导出镜像到本地 (指定源)"
[ -z "$2" ] && echo "请输入镜像仓库地址" && exit 1
export_images_2 $2 $3
;;
5)
echo ">>> 执行功能 5: 导入镜像到镜像仓库 (全名)"
[ -z "$2" ] && echo "请输入镜像仓库地址" && exit 1
import_images_2 $2 $3
;;
6)
echo ">>> 执行功能 6: 同步amd64镜像到 Harbor"
rsync_amd64
;;
7)
echo ">>> 执行功能 7: 导入本地镜像到 containerd"
import_to_containerd $2 $3
;;
8)
echo ">>> 执行功能 8: 导入本地镜像到仓库 (去域名)"
# 参数2: 目标仓库, 参数3: 架构
import_oci_clean_push $2 $3
;;
*)
echo "无效的参数! 请输入 1-8。"
echo "$desc"
exit 1
;;
esac