背景
在持续集成和持续部署的流程中,频繁的构建和部署会生成大量的镜像版本。这些历史镜像如果不及时清理,会占用大量的存储空间,导致 Harbor 仓库膨胀,影响系统性能。
目前 公司的Harbor存储已经占用1T,好多的repo的镜像tag达到上百多,没有清理十分占用空间。
目前研究了下,可采取两种方案进行清理。(各自有各的优势)
1、采用Harbor自带的清理策略
2、写脚本,可以自定义控制清理,比较方便。
目的
-
释放存储空间:清理不再使用的镜像,释放被占用的磁盘空间。
-
提高系统性能:减少无用数据,提高 Harbor 的响应速度和稳定性。
-
简化管理:通过自动化策略,减少手动清理的工作量,提高管理效率。
方案一 Harbor 镜像自动清理策略
Harbor 提供了基于项目的镜像保留策略(Retention Policy),允许用户根据特定的规则自动保留或删除镜像。该策略支持以下配置:(需要每个仓库分别配置)
- 匹配规则:通过通配符匹配特定的仓库或镜像。
- 保留策略:设置保留最近推送或拉取的镜像数量或时间范围。
- 标签过滤:根据镜像的标签(Tag)进行筛选,如保留特定前缀的标签。
- 删除未打标签的镜像:选择是否删除未打标签的镜像(Untagged Artifacts)。
1、使用管理员账号登录 Harbor 的 Web 控制台。
2、在左侧导航栏选择“项目”,点击需要配置清理策略的项目名称。
3、配置保留策略
在项目页面,选择“策略”选项卡,点击“添加规则”按钮,进行以下配置:
- 规则名称:为策略命名,便于识别。
- 匹配仓库:使用通配符(如
**
)匹配需要应用策略的仓库。
- 保留策略:选择保留最近推送或拉取的镜像数量或时间范围。
- 标签过滤:设置标签匹配规则,如保留以
release-
开头的标签。
- 删除未打标签的镜像:根据需要选择是否删除未打标签的镜像。
4、设置定时任务
在策略页面,点击“编辑”按钮,配置策略的执行时间。Harbor 使用 UTC 时间,需注意与本地时间的差异。例如,设置每周六凌晨 0 点执行:
这表示每周六 UTC 时间 0 点执行,若在中国时区,实际执行时间为周六上午 8 点。
5、手动执行策略(可选)
在策略页面,点击“立即执行”按钮,可以手动触发策略,立即清理符合条件的镜像。

方案二 使用Shell脚本处理
harbor_clean.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
#!/bin/bash
#/**********************************************************
# * Author : 南宫乘风
# * Email : 1794748404@qq.com
# * Last modified : 2024-01-17 10:00
# * Filename : harbor_clean.sh
# * Description : 清理指定Harbor项目的镜像,只保留最近5次
# * *******************************************************/
set -e
# 日志文件配置
LOG_FILE="./harbor_clean.log"
user=$(whoami)
# Harbor配置(请配置账号和密码)
HARBOR_URL="bdata-hub.xxxxx.cn"
HARBOR_USERNAME="admin"
HARBOR_PASSWORD="xxxxxxxxx"
KEEP_NUM=15 # 保留最近的5个镜像
# 指定要清理的项目列表
PROJECTS=("service" "pre")
# 创建临时目录
TMP_DIR="$PWD/harbor_clean_tmp"
# 日志函数
function log_info() {
content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $0 $user msg : $@"
echo $content >>$LOG_FILE
echo -e "\033[32m${content}\033[0m"
}
function log_warn() {
content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $0 $user msg : $@"
echo $content >>$LOG_FILE
echo -e "\033[33m${content}\033[0m"
}
function log_err() {
content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $0 $user msg : $@"
echo $content >>$LOG_FILE
echo -e "\033[31m${content}\033[0m"
}
# 获取指定项目的仓库列表
function get_repos_list() {
local project=$1
log_info "获取项目 ${project} 的仓库列表"
mkdir -p "$TMP_DIR/repos"
local repos_list=$(curl -s -k -u "${HARBOR_USERNAME}:${HARBOR_PASSWORD}" \
"https://${HARBOR_URL}/api/v2.0/projects/${project}/repositories?page=1&page_size=100")
if [ $? -ne 0 ]; then
log_err "获取项目 ${project} 的仓库列表失败"
return 1
fi
echo "${repos_list}" | jq '.[]' | jq -r '.name' | awk -F "/" '{print $2}' >"$TMP_DIR/repos/${project}.txt"
log_info "成功获取项目 ${project} 的仓库列表"
}
# 获取镜像标签列表
function get_tag_list() {
local project=$1
local repo=$2
log_info "获取仓库 ${project}/${repo} 的标签列表"
mkdir -p "$TMP_DIR/tags/$project/$repo"
local artifacts=$(curl -s -k -u "${HARBOR_USERNAME}:${HARBOR_PASSWORD}" \
"https://${HARBOR_URL}/api/v2.0/projects/${project}/repositories/${repo}/artifacts?page=1&page_size=100&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false")
if [ $? -ne 0 ]; then
log_err "获取仓库 ${project}/${repo} 的标签列表失败"
return 1
fi
echo "${artifacts}" | jq '.[]' | jq -r '.digest' >"$TMP_DIR/tags/$project/$repo/digests.txt"
log_info "成功获取仓库 ${project}/${repo} 的标签列表"
}
# 删除旧镜像
function delete_images() {
local project=$1
local repo=$2
local digest_file="$TMP_DIR/tags/$project/$repo/digests.txt"
if [ ! -f "$digest_file" ]; then
log_warn "仓库 ${project}/${repo} 的标签文件不存在,跳过"
return
fi
local total_num=$(wc -l <"$digest_file")
if [ $total_num -gt $KEEP_NUM ]; then
local delete_num=$((total_num - KEEP_NUM))
log_info "仓库 ${project}/${repo} 有 ${delete_num} 个镜像需要删除"
tail -n $delete_num "$digest_file" | while read digest; do
log_info "准备删除镜像: ${project}/${repo}@${digest}"
curl -X DELETE -s -k -u "${HARBOR_USERNAME}:${HARBOR_PASSWORD}" \
"https://${HARBOR_URL}/api/v2.0/projects/${project}/repositories/${repo}/artifacts/${digest}"
if [ $? -eq 0 ]; then
log_info "成功删除镜像: ${project}/${repo}@${digest}"
else
log_err "删除镜像失败: ${project}/${repo}@${digest}"
fi
done
log_info "仓库 ${project}/${repo} 的镜像清理完成"
else
log_info "仓库 ${project}/${repo} 的镜像数量未超过保留限制,跳过清理"
fi
}
# 清理临时文件
function cleanup() {
log_info "清理临时文件"
rm -rf "$TMP_DIR"
}
# 主函数
function main() {
log_info "开始执行Harbor镜像清理脚本"
mkdir -p "$TMP_DIR"
trap cleanup EXIT
# 遍历指定的项目列表
for project in "${PROJECTS[@]}"; do
log_info "开始处理项目: ${project}"
get_repos_list "$project"
if [ -f "$TMP_DIR/repos/${project}.txt" ]; then
while read repo; do
get_tag_list "$project" "$repo"
delete_images "$project" "$repo"
done <"$TMP_DIR/repos/${project}.txt"
else
log_warn "项目 ${project} 的仓库列表文件不存在"
fi
done
log_info "Harbor镜像清理脚本执行完成"
}
# 执行主函数
main
|

1
2
3
|
#定时任务
crontab -e
/bin/bash /root/shell/harbor_clean.sh
|
运行日志:

垃圾回收(Garbage Collection)
-配置并执行镜像清理策略后,镜像的元数据会被删除,但实际的存储空间不会立即释放。为彻底释放空间,需要执行垃圾回收操作。
执行步骤
- 在左侧导航栏选择“系统管理” > “垃圾清理”。
- 点击“立即清理”按钮,执行垃圾回收操作。
- 在“历史记录”中查看垃圾回收的执行情况和释放的空间大小。
垃圾回收操作可以配置为定时执行,确保系统定期释放无用的存储空间。


注意事项
策略优先级:多个策略可能存在冲突,Harbor 按照策略的创建顺序依次执行,建议合理规划策略的优先级。
标签管理:合理使用标签(Tag)命名规范,有助于策略的精确匹配和管理。
测试策略:在生产环境应用策略前,建议在测试环境验证策略的效果,避免误删重要镜像。
备份数据:执行清理操作前,建议备份重要数据,以防止数据丢失。