找回密码
 立即注册
首页 业界区 业界 Harbor磁盘空间清理指南:如何安全清理半年前的镜像 ...

Harbor磁盘空间清理指南:如何安全清理半年前的镜像

挚魉 4 天前
1 背景:为何需要定期清理Harbor镜像

在多项目开发环境中,随着持续集成/持续部署(CI/CD)流程的不断运行,Jenkins等工具会频繁地向Harbor镜像仓库推送新构建的镜像。久而久之,仓库中会积累大量历史镜像版本,导致虚拟机磁盘空间迅速耗尽。这些"僵尸镜像"不仅占用宝贵的存储资源,还可能增加安全风险和管理复杂度。
根据实践经验,一个中等规模的开发团队每周可能产生数十甚至上百个新镜像。如果没有有效的清理策略,Harbor存储占用呈指数级增长只是时间问题。更糟糕的是,单纯删除镜像并不立即释放物理空间——这是许多管理员常遇到的误区。
本文将详细介绍两种有效清理半年前镜像的方法:Harbor原生保留策略API脚本清理方案,并解释最终释放磁盘空间的关键步骤。
2 清理原理:Harbor的两级删除机制

Harbor采用两级删除机制,理解这一点对有效管理存储空间至关重要:

  • 软删除(标记删除):当我们通过界面或API删除镜像标签时,Harbor只是移除了镜像的元数据引用,并未真正删除底层的物理文件(blobs)。这就是为什么删除镜像后磁盘空间似乎没有变化。
  • 硬删除(物理删除):需要通过垃圾回收(Garbage Collection, GC) 过程来实现。GC会清理那些不再被任何镜像引用的底层数据块,从而真正释放磁盘空间。
flowchart TD    A[Harbor 磁盘空间不足] --> B{选择清理方式}        B -- 官方推荐
UI配置 --> C[配置保留策略]    B -- 高度定制化
API操作 --> D[编写清理脚本]        subgraph C [方案一:通过 Harbor UI 配置保留策略]        C1[创建保留规则]        C2[设置保留最近180天镜像]        C3[设置定时执行或手动运行]    end        subgraph D [方案二:通过 Harbor API 编写脚本]        D1[认证获取 Token]        D2[筛选创建时间早于半年的标签]        D3[调用 API 删除旧标签]    end        C --> E    D --> E[执行垃圾回收 GC]        subgraph E [关键步骤:垃圾回收 GC]        E1[安排维护窗口
GC期间仓库只读]        E2[执行垃圾回收命令]        E3[真正释放物理磁盘空间]    end        E --> F[磁盘空间得到释放]3 方法一:使用Harbor原生保留策略(推荐UI操作)

Harbor自v2.4版本起提供了强大的保留策略(Retention Policy)功能,这是清理旧镜像的最简便方法。
3.1 配置步骤


  • 登录Harbor控制台,进入需要清理的项目
  • 点击"策略"选项卡 -> "添加规则"
  • 配置保留规则:

    • 规则名称:例如"清理半年前镜像"
    • 匹配仓库:可使用**匹配所有仓库,或指定特定仓库
    • 保留策略:选择"保留最近多少天被推送过的",设置天数为180天(约半年)
    • 标签过滤:可根据需要设置标签匹配模式(如release-*)
    • 删除未打标签的镜像:建议启用,以清理无标签的中间层镜像

  • 设置执行频率(如每周一次)
  • 点击"模拟运行"预览将被清理的镜像
  • 确认无误后"立即执行"
3.2 优势与注意事项


  • 优势:官方支持、配置简单、可定时自动运行、提供模拟运行功能降低风险
  • 注意事项

    • 保留策略基于"保留最近推送的镜像"逻辑,而非直接按时间点删除
    • 需要Harbor v2.4+版本支持
    • 执行后仍需运行垃圾回收才能释放物理空间

4 方法二:使用API脚本精确删除

对于需要更复杂清理逻辑或使用旧版Harbor的情况,可通过API脚本实现精确控制。
4.1 Python脚本示例

以下Python脚本示例演示了如何删除指定项目中所有早于半年的镜像标签:
  1. import requests
  2. from datetime import datetime, timedelta
  3. # Harbor配置
  4. HARBOR_URL = 'https://your-harbor.com'
  5. USERNAME = 'admin'
  6. PASSWORD = 'your-password'
  7. PROJECT_NAME = 'your-project'
  8. # 计算半年前时间点
  9. six_months_ago = datetime.now() - timedelta(days=180)
  10. # 获取认证token
  11. def get_token():
  12.     login_url = f'{HARBOR_URL}/c/login'
  13.     resp = requests.post(login_url, json={
  14.         'principal': USERNAME,
  15.         'password': PASSWORD
  16.     }, verify=False)
  17.     return resp.headers.get('Authorization')
  18. # 获取项目中的所有仓库
  19. def get_repositories(project):
  20.     headers = {'Authorization': get_token()}
  21.     repos_url = f'{HARBOR_URL}/api/v2.0/projects/{project}/repositories'
  22.     resp = requests.get(repos_url, headers=headers, verify=False)
  23.     return [repo['name'] for repo in resp.json()]
  24. # 获取仓库的所有标签及其创建时间
  25. def get_tags(repository):
  26.     headers = {'Authorization': get_token()}
  27.     tags_url = f'{HARBOR_URL}/api/v2.0/{repository}/tags'
  28.     resp = requests.get(tags_url, headers=headers, verify=False)
  29.     return [(tag['name'], datetime.strptime(tag['push_time'], '%Y-%m-%dT%H:%M:%S.%fZ'))
  30.             for tag in resp.json()]
  31. # 删除早于指定时间的标签
  32. def delete_old_tags():
  33.     for repo in get_repositories(PROJECT_NAME):
  34.         tags = get_tags(repo)
  35.         for tag_name, push_time in tags:
  36.             if push_time < six_months_ago:
  37.                 delete_url = f'{HARBOR_URL}/api/v2.0/{repo}/tags/{tag_name}'
  38.                 requests.delete(delete_url, headers={'Authorization': get_token()}, verify=False)
  39.                 print(f'Deleted: {repo}:{tag_name}')
  40. if __name__ == '__main__':
  41.     delete_old_tags()
复制代码
4.2 Shell脚本方案

Alternatively,也可以使用Shell脚本实现类似功能:
[code]#!/bin/bashHARBOR_URL="https://your-harbor.com"USERNAME="admin"ASSWORD="password"ROJECT="your-project"# 获取tokenTOKEN=$(curl -s -k -X POST -H "Content-Type: application/json" \  -d "{\"principal\": \"$USERNAME\", \"password\": \"$PASSWORD\"}" \  "$HARBOR_URL/c/login" | grep -o '"token":"[^"]*' | cut -d'"' -f4)# 获取项目中的仓库列表REPOS=$(curl -s -k -X GET -H "Authorization: Bearer $TOKEN" \  "$HARBOR_URL/api/v2.0/projects/$PROJECT/repositories" | jq -r '.[].name')for REPO in $REPOS; do  # 获取仓库的标签列表  TAGS=$(curl -s -k -X GET -H "Authorization: Bearer $TOKEN" \    "$HARBOR_URL/api/v2.0/$REPO/tags" | jq -r '.[] | [.name, .push_time] | @tsv')    while IFS=$'\t' read -r TAG PUSH_TIME; do    # 转换时间格式并比较    PTIME=$(date -d "$PUSH_TIME" +%s)    SIX_MONTHS_AGO=$(date -d "6 months ago" +%s)        if [ $PTIME -lt $SIX_MONTHS_AGO ]; then      # 删除旧标签      curl -s -k -X DELETE -H "Authorization: Bearer $TOKEN" \        "$HARBOR_URL/api/v2.0/$REPO/tags/$TAG"      echo "Deleted: $REPOTAG"    fi  done

相关推荐

您需要登录后才可以回帖 登录 | 立即注册