You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求可删除私有Docker Registry中X天前镜像的脚本(Shell/Python)

私有Docker Registry清理:删除早于X天的镜像解决方案

以下提供Shell和Python两种脚本实现,均基于Docker Registry v2 API,精准筛选并删除指定天数前创建的镜像,而非盲目保留latest标签。

前置准备

确保你的私有Registry已开启删除功能:

  1. 修改Registry配置文件(通常是/etc/docker/registry/config.yml),添加或修改:
storage:
  delete:
    enabled: true
  1. 重启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

重要注意事项

  1. 脚本执行删除后,必须运行垃圾回收才能真正释放磁盘空间
  2. 建议先在测试环境验证脚本逻辑,避免误删重要镜像
  3. 若Registry使用HTTPS,需将REGISTRY_URL改为https开头;自签名证书可在Python脚本中添加verify=False(生产环境建议配置可信证书)

内容的提问来源于stack exchange,提问作者tiamat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 11:08:10