求可删除私有Docker Registry中X天前镜像的脚本(Shell/Python)
私有Docker Registry清理:删除早于X天的镜像解决方案
以下提供Shell和Python两种脚本实现,均基于Docker Registry v2 API,精准筛选并删除指定天数前创建的镜像,而非盲目保留latest标签。
前置准备
确保你的私有Registry已开启删除功能:
- 修改Registry配置文件(通常是
/etc/docker/registry/config.yml),添加或修改:
storage: delete: enabled: true
- 重启Registry容器生效。
Shell脚本实现
依赖curl和jq工具,先通过包管理器安装(如apt install jq curl或yum install jq curl)。
#!/bin/bash # 核心配置 REGISTRY_URL="http://your-registry:5000" DAYS_TO_KEEP=30 # 需认证则取消注释并填写 # REGISTRY_USER="admin" # REGISTRY_PWD="your-password" # 计算截止时间戳(当前时间减去X天的秒数) CUT_OFF=$(date -d "-$DAYS_TO_KEEP days" +%s) # 获取所有仓库列表 REPOS=$(curl -s ${REGISTRY_USER:+ -u $REGISTRY_USER:$REGISTRY_PWD} "$REGISTRY_URL/v2/_catalog" | jq -r '.repositories[]') for REPO in $REPOS; do echo "=== 处理仓库: $REPO ===" # 获取仓库下所有标签 TAGS=$(curl -s ${REGISTRY_USER:+ -u $REGISTRY_USER:$REGISTRY_PWD} "$REGISTRY_URL/v2/$REPO/tags/list" | jq -r '.tags[]') for TAG in $TAGS; do # 获取镜像manifest的Digest和创建时间 MANIFEST_RESP=$(curl -s -I ${REGISTRY_USER:+ -u $REGISTRY_USER:$REGISTRY_PWD} "$REGISTRY_URL/v2/$REPO/manifests/$TAG") DIGEST=$(echo "$MANIFEST_RESP" | grep -i Docker-Content-Digest | awk '{print $2}' | tr -d '\r') # 优先从响应头取创建时间,取不到则从manifest内容读取 CREATED_TIME=$(echo "$MANIFEST_RESP" | grep -i 'Created' | awk '{print $2}' | tr -d '\r') if [ -z "$CREATED_TIME" ]; then MANIFEST_CONTENT=$(curl -s ${REGISTRY_USER:+ -u $REGISTRY_USER:$REGISTRY_PWD} "$REGISTRY_URL/v2/$REPO/manifests/$TAG") CREATED_TIME=$(echo "$MANIFEST_CONTENT" | jq -r '.created') fi # 时间转换并判断是否删除 if [ ! -z "$CREATED_TIME" ]; then IMAGE_TS=$(date -d "$CREATED_TIME" +%s) if [ $IMAGE_TS -lt $CUT_OFF ]; then echo "删除镜像: $REPO:$TAG (创建时间: $CREATED_TIME)" curl -X DELETE ${REGISTRY_USER:+ -u $REGISTRY_USER:$REGISTRY_PWD} "$REGISTRY_URL/v2/$REPO/manifests/$DIGEST" fi else echo "跳过 $REPO:$TAG: 无法获取创建时间" fi done done # 执行垃圾回收,释放磁盘空间 echo "=== 执行Registry垃圾回收 ===" docker exec -it your-registry-container-name bin/registry garbage-collect /etc/docker/registry/config.yml
使用说明
- 替换
REGISTRY_URL为你的Registry地址 - 设置
DAYS_TO_KEEP为需要保留的镜像天数 - 替换最后一行的
your-registry-container-name为实际Registry容器名 - 脚本可添加执行权限后直接运行:
chmod +x clean_registry.sh && ./clean_registry.sh
Python脚本实现
依赖requests库,先安装:pip install requests
import requests from datetime import datetime, timedelta import subprocess # 核心配置 REGISTRY_URL = "http://your-registry:5000" DAYS_TO_KEEP = 30 AUTH = ("admin", "your-password") # 无需认证则设为None REGISTRY_CONTAINER = "your-registry-container-name" def get_all_repos(): resp = requests.get(f"{REGISTRY_URL}/v2/_catalog", auth=AUTH) resp.raise_for_status() return resp.json()["repositories"] def get_repo_tags(repo_name): resp = requests.get(f"{REGISTRY_URL}/v2/{repo_name}/tags/list", auth=AUTH) resp.raise_for_status() return resp.json().get("tags", []) def get_image_details(repo_name, tag): headers = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"} resp = requests.get(f"{REGISTRY_URL}/v2/{repo_name}/manifests/{tag}", headers=headers, auth=AUTH) resp.raise_for_status() digest = resp.headers.get("Docker-Content-Digest") created_time = resp.json().get("created") return digest, created_time def delete_image(repo_name, digest): resp = requests.delete(f"{REGISTRY_URL}/v2/{repo_name}/manifests/{digest}", auth=AUTH) if resp.status_code == 202: print(f"✅ 已删除 {repo_name} (Digest: {digest})") else: print(f"❌ 删除失败 {repo_name}: {resp.text}") def run_garbage_collection(): cmd = ["docker", "exec", REGISTRY_CONTAINER, "bin/registry", "garbage-collect", "/etc/docker/registry/config.yml"] subprocess.run(cmd, check=True) if __name__ == "__main__": cut_off_time = datetime.utcnow() - timedelta(days=DAYS_TO_KEEP) repos = get_all_repos() for repo in repos: print(f"\n=== 处理仓库: {repo} ===") tags = get_repo_tags(repo) for tag in tags: digest, created_time = get_image_details(repo, tag) if not created_time: print(f"⚠️ 跳过 {repo}:{tag} - 无法获取创建时间") continue # 解析时间(兼容两种格式) try: created_dt = datetime.strptime(created_time, "%Y-%m-%dT%H:%M:%S.%fZ") except ValueError: created_dt = datetime.strptime(created_time, "%Y-%m-%dT%H:%M:%SZ") if created_dt < cut_off_time: print(f"准备删除: {repo}:{tag} (创建时间: {created_time})") delete_image(repo, digest) print("\n=== 执行垃圾回收释放磁盘 ===") run_garbage_collection()
使用说明
- 修改配置项中的地址、天数、认证信息和容器名
- 直接运行脚本:
python3 clean_registry.py
重要注意事项
- 脚本执行删除后,必须运行垃圾回收才能真正释放磁盘空间
- 建议先在测试环境验证脚本逻辑,避免误删重要镜像
- 若Registry使用HTTPS,需将
REGISTRY_URL改为https开头;自签名证书可在Python脚本中添加verify=False(生产环境建议配置可信证书)
内容的提问来源于stack exchange,提问作者tiamat
相关产品推荐
相关产品推荐

