如何优雅将harbor存储迁移到s3
我们有一个 docker compose 部署的 harbor,随着时间的推移,存储的镜像越来越多,磁盘空间已经捉襟见肘。急需迁移到更大的存储空间去。harbor 支持众多的后端存储,所支持的后端存储类型和配置方法点击 Configuring a registry | CNCF Distribution 和 Harbor docs | Configure the Harbor YML File 查看。
我这里使用的是minio(兼容s3)作为后端存储。
假设我的 harbor 的访问地址是:https://hub.kops.cc
配置方法
修改 harbor.yml
文件:
storage_service:
s3:
accesskey: minioadmin
secretkey: minioadmin
regionendpoint: http://127.0.0.1:9000
bucket: harbor
multipartcopythresholdsize: "5368709120"
执行 ./prepare
脚本使配置生效
./prepare
docker-compose down
docker-compose up -d
测试一下拉镜像,如果配置生效,这时候镜像是拉不下来的,因为我们存储空间改变了,新的存储空间没有这个镜像的数据。
harbor 原来是有 library/redis:5.0
这个镜像的,此时已经不能拉取。
docker pull harbor.kops.cc/library/redis:5.0
Error response from daemon: manifest for harbor.kops.cc/library/redis:5.0 not found: manifest unknown: manifest unknown
迁移镜像数据
harbor后端的镜像仓库使用的是 CNCF Distribution,原来应该叫 Docker Registry。因此我们迁移有几种方案,你选一种合适的方案即可。
如果你执行了上面的步骤,已经修改了 harbor 的存储后端为s3,那么原来的镜像此时已经无法拉取。那么有没有办法能让镜像能拉取呢?自然是有的。我们临时部署一个 registry,并挂载 harbor 的 registry 存储目录过去,那么就可以拉取到原来的镜像了。
假设你的harbor数据存储在 /data/harbor
,那么 harbor registry 的数据目录就是 /data/harbor/registry
,将这个目录挂载到临时 registry 的 /var/lib/registry
,用 docker 的话,命令如下:
docker run -d --name temp-registry -p 5000:5000 -v /data/harbor/registry:/var/lib/registry registry:2
测试一下,用临时registry拉取镜像看看:
docker pull localhost:5000/library/redis:5.0
docker pull localhost:5000/library/redis:5.0
5.0: Pulling from library/redis
Digest: sha256:6411e32d8386718b01ca27f6754847fd880c653c215467d0cd3d7876f213eb94
Status: Image is up to date for localhost:5000/library/redis:5.0
好,可以拉取。
这时候,你应该要清楚:
localhost:5000
能拉取到之前的镜像hub.kops.cc
已经不能拉取镜像了,其他的数据都是还在的,harbor web也都能正常登录和查看
重新打标法(retag)
这个方案最原始,要求能访问原来的镜像(用上面提到的临时registry)。
迁移步骤如下:
- 拉取镜像(localhost:5000)
- 重新打标(docker tag localhost:5000/xxx hub.kops.cc/xxx)
- 推送镜像(hub.kops.cc)
此步骤可以用一个 shell 脚本自动完成,需要装有 jq
#!/bin/bash
# 临时 Registry 地址
TEMP_REGISTRY_URL="http://localhost:5000"
# Harbor 地址
HARBOR_URL="http://hub.kops.cc"
# 获取所有镜像列表
images=$(curl -s "${TEMP_REGISTRY_URL}/v2/_catalog" | jq -r '.repositories[]')
# 遍历每个镜像
for image in $images; do
echo "镜像: $image"
# 获取每个镜像的 tag 列表
tags=$(curl -s "${TEMP_REGISTRY_URL}/v2/${image}/tags/list" | jq -r '.tags[]?' )
if [ -z "$tags" ]; then
echo " (无 tag)"
else
for tag in $tags; do
old_tag=${TEMP_REGISTRY_URL##http*://}/${image}:${tag}
new_tag=${HARBOR_URL##http*://}/${image}:${tag}
docker pull ${old_tag}
docker tag ${old_tag} ${new_tag}
# 需要提前docker login
docker push ${new_tag}
docker rmi ${ols_tag} ${new_tag}
done
fi
echo ""
done
skopeo copy 法
这个方法是重新打标法的升级版,重新打标需要pull/retag/push三个步骤,pull要接压缩,push要重新压缩,效率较低。
而 skopeo 在传输过程中,不会对镜像的层解包再封包,效率上提高了很多。
skopeo copy
skopeo copy docker://localhost:5000/xxx docker://hub.kops.cc/xxx
- 如果不是安全连接(https),有两个参数:--src-tls-verify=false --dest-tls-verify=false,分别标记源仓和目标仓是否是安全连接
- 账号密码:--src-username --src-password --dest-username --dest-password,分别给源仓和目标仓配置用户名和密码
文件系统迁移法
我在想,能不能直接将 Harbor Registry 数据目录原封不动同步到 s3 去。我试了一下,确实存储的目录结构和本地文件系统是一模一样的。有了这个理论基础,那么就可以直接将整个目录的数据同步到 s3。
- 首先,要先配置
~/.s3cfg
配置文件,配置方法不会的可以找找其他资料,这里不过多赘述 - 假设 Harbor Registry 的数据目录在
/data/harbor/registry
- 假设桶名是 harbor
s3cmd sync /data/harbor/registry/docker s3://harbor/docker/
确保能看到这样的目录结构就说明是对的:
s3cmd ls s3://harbor/docker/registry/v2/
DIR s3://harbor/docker/registry/v2/blobs/ DIR s3://harbor/docker/registry/v2/repositories/
此法最简单高效,也不需要临时 Registry。在这种换存储系统的场景使用是最为合适的。只需要提前sync到s3,然后择机再做一次增量sync,然后再改配置重启harbor即可,整个停机窗口也可以控制在相当短的时间。
- 增量 sync 加上 --delete 参数