如何保留私有Docker仓库中指定项目的最新3个Docker镜像?
我来帮你搞定这个需求!要在私有Docker仓库里保留指定项目的最新3个镜像,其余的自动清理,咱们可以通过仓库的API来实现,甚至可以写成脚本定期执行,下面是详细的操作方案:
前提准备
- 确保你的私有Docker仓库已开启删除功能:默认情况下私有仓库是禁用删除的,需要修改配置重启。如果是用容器运行的仓库,启动时加上环境变量:
docker run -d -p 5000:5000 -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry registry:2;如果是配置文件管理,在config.yml里添加storage: { delete: { enabled: true } }后重启仓库服务。 - 安装
jq工具用来解析JSON:CentOS上执行yum install jq -y。 - 确认能正常访问私有仓库的API:比如执行
curl http://your-registry:5000/v2/_catalog(如果有认证,加上-u username:password),能返回仓库列表说明API可用。
步骤1:获取项目的所有镜像标签
假设你的项目镜像在私有仓库中的路径是your-registry:5000/my-project(my-project是仓库名),先获取该项目的所有版本标签:
# 替换成你的仓库地址和项目名 REGISTRY="your-registry:5000" REPO="my-project" # 如果有认证,取消下面注释并填写 # AUTH="username:password" # 获取所有标签并输出 curl -s ${AUTH:+-u $AUTH} http://$REGISTRY/v2/$REPO/tags/list | jq '.tags'
步骤2:筛选出要保留和删除的镜像
接下来需要对标签排序,筛选出最新的3个保留,其余标记为待删除。这里要注意版本标识的排序逻辑:
- 如果你的版本是语义化版本(比如
v1.0.0、v2.1.3),用sort -Vr按版本号倒序排序; - 如果是时间戳或纯数字版本,用
sort -r倒序即可。
示例命令:
# 获取所有标签并按版本倒序排序 ALL_TAGS=$(curl -s ${AUTH:+-u $AUTH} http://$REGISTRY/v2/$REPO/tags/list | jq -r '.tags[]' | sort -Vr) # 保留最新的3个标签 KEEP_TAGS=$(echo "$ALL_TAGS" | head -n 3) # 得到需要删除的标签(排除保留的标签) DELETE_TAGS=$(echo "$ALL_TAGS" | grep -vE "^($(echo "$KEEP_TAGS" | tr '\n' '|'))$")
执行完可以分别输出KEEP_TAGS和DELETE_TAGS确认筛选结果是否正确。
步骤3:删除指定镜像
私有仓库删除镜像需要先获取镜像的digest(摘要),再调用DELETE API删除对应的manifest:
for TAG in $DELETE_TAGS; do echo "正在处理标签: $TAG" # 获取镜像的digest DIGEST=$(curl -s ${AUTH:+-u $AUTH} -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ http://$REGISTRY/v2/$REPO/manifests/$TAG | jq -r '.config.digest') if [ -z "$DIGEST" ]; then echo "无法获取$TAG的digest,跳过" continue fi # 执行删除 RESPONSE=$(curl -s -w "%{http_code}" -X DELETE ${AUTH:+-u $AUTH} \ http://$REGISTRY/v2/$REPO/manifests/$DIGEST) HTTP_CODE=$(echo "$RESPONSE" | tail -n1) if [ "$HTTP_CODE" -eq 202 ]; then echo "$TAG 删除成功" else echo "$TAG 删除失败,响应码: $HTTP_CODE" fi done
步骤4:清理仓库存储空间
删除镜像后,仓库的实际存储文件并不会立即删除,需要执行垃圾回收来释放磁盘空间:
- 如果是容器运行的仓库,执行:
docker exec -it registry bin/registry garbage-collect /etc/docker/registry/config.yml
(把registry换成你的仓库容器名)
- 如果是直接安装的仓库,运行对应的垃圾回收命令即可。
脚本化自动执行
把上面的步骤整合成一个可复用的shell脚本,方便定期执行:
#!/bin/bash # 配置参数,请根据实际情况修改 REGISTRY="your-registry:5000" REPO="my-project" KEEP_COUNT=3 # AUTH="username:password" # 有认证时取消注释并填写 # 检查jq是否安装 if ! command -v jq &> /dev/null; then echo "错误: 未安装jq工具,请执行yum install jq -y安装" exit 1 fi # 获取所有标签并排序 ALL_TAGS=$(curl -s ${AUTH:+-u $AUTH} http://$REGISTRY/v2/$REPO/tags/list | jq -r '.tags[]' | sort -Vr) # 检查镜像数量是否需要清理 TAG_COUNT=$(echo "$ALL_TAGS" | wc -l) if [ $TAG_COUNT -le $KEEP_COUNT ]; then echo "当前只有$TAG_COUNT个镜像,无需清理" exit 0 fi # 筛选保留和删除的标签 KEEP_TAGS=$(echo "$ALL_TAGS" | head -n $KEEP_COUNT) DELETE_TAGS=$(echo "$ALL_TAGS" | grep -vE "^($(echo "$KEEP_TAGS" | tr '\n' '|'))$") echo "=== 清理计划 ===" echo "将保留的标签: $KEEP_TAGS" echo "将删除的标签: $DELETE_TAGS" # 执行删除 for TAG in $DELETE_TAGS; do echo -e "\n正在删除标签: $TAG" DIGEST=$(curl -s ${AUTH:+-u $AUTH} -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ http://$REGISTRY/v2/$REPO/manifests/$TAG | jq -r '.config.digest') if [ -z "$DIGEST" ]; then echo "❌ 无法获取$TAG的digest,跳过" continue fi RESPONSE=$(curl -s -w "%{http_code}" -X DELETE ${AUTH:+-u $AUTH} \ http://$REGISTRY/v2/$REPO/manifests/$DIGEST) HTTP_CODE=$(echo "$RESPONSE" | tail -n1) if [ "$HTTP_CODE" -eq 202 ]; then echo "✅ $TAG 删除成功" else echo "❌ $TAG 删除失败,响应码: $HTTP_CODE" fi done # 执行垃圾回收 echo -e "\n=== 执行垃圾回收 ===" docker exec -it registry bin/registry garbage-collect /etc/docker/registry/config.yml echo "✅ 清理完成"
使用方法:
- 保存脚本为
registry-cleanup.sh,修改配置参数; - 给脚本加执行权限:
chmod +x registry-cleanup.sh; - 测试运行:
./registry-cleanup.sh; - 添加到crontab定期执行(比如每周日凌晨2点):
crontab -e # 添加下面一行,替换脚本路径 0 2 * * 0 /path/to/registry-cleanup.sh >> /var/log/registry-cleanup.log 2>&1
注意事项
- 一定要先测试排序逻辑,确保
KEEP_TAGS是你真正想要保留的最新镜像; - 如果仓库有HTTPS认证,curl命令需要加上
-k(忽略证书)或者指定证书路径; - 垃圾回收建议定期执行,避免磁盘空间被占用。
内容的提问来源于stack exchange,提问作者Devendra
相关产品推荐
相关产品推荐

