Harbor存储回收

Harbor简介

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源的Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。Harbor支持安装在多个Registry节点的镜像资源复制,镜像全部保存在私有Registry中, 确保数据和知识产权在公司内部网络中管控。另外,Harbor也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等。现在Harbour已成为由Cloud Native Computing Foundation(CNCF)托管的项目。

Harbor存储回收

在使用Harbor很长一段时间后镜像所占存储空间越来越大,我们就需要对不再会使用到的镜像进行删除回收它所占用到的空间以免浪费资源。删除镜像的操作显然是一个非常有重复性的操作,那么我们就可以定制一些规则调用Harbor的API进行删除。这些操作我们将会使用到Harbor的以下API:

Method URL Remarks
GET /projects List projects
GET /repositories Get repositories accompany with relevant project and repo name.
GET /repositories/{repo_name}/tags Get tags of a relevant repository.
DELETE /repositories/{repo_name}/tags/{tag} Delete a tag in a repository.

首先获取所有项目列表,依次遍历项目下所有的仓库,将仓库下的镜像tag逐一列出进行规则比对,若包含定义的关键字或匹配的正则表达式进行删除,不具备条件的则略过。此操作只是进行软删除,不回收镜像实际所占物理存储。比对tag是否满足删除规则的代码如下:

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
func needDeleteTag(tag harbor.TagResp, count *int) bool {
baseTime, _ := time.ParseDuration("1h")
if time.Now().Sub(tag.Created) < deletePolicy.IntervalHour*baseTime || *count < deletePolicy.MixCount {
*count += 1
return false
}
match, err := regexp.MatchString(deletePolicy.Tags.Exclude.Regex, tag.Name)
checkErr(err)
if match {
return false
}
match, err = regexp.MatchString(deletePolicy.Tags.Exclude.KeysRegex, tag.Name)
checkErr(err)
if match {
return false
}
match, err = regexp.MatchString(deletePolicy.Tags.Include.Regex, tag.Name)
checkErr(err)
if match {
glog.V(2).Infof("%s match Tags.Regex: %s", tag.Name, deletePolicy.Tags.Include.Regex)
return true
}
match, err = regexp.MatchString(deletePolicy.Tags.Include.KeysRegex, tag.Name)
checkErr(err)
if match {
glog.V(2).Infof("%s match Tags.KeysRegex: %s", tag.Name, deletePolicy.Tags.Include.KeysRegex)
return true
}
return false
}

项目代码已上传至Github,可使用go get进行安装或直接下载编译好的可执行文件

1
go get -u github.com/TimeBye/harbor-cleaner

使用harbor-cleaner进行软删除

  • 编写配置文件delete_policy.yml

    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
    # 仓库相关信息
    registry_url: https://registry.example.com/
    username: admin
    password: password

    # 仅模拟运行,不真实删除,默认启用
    dry_run: true
    # 删除以现在时间为基础以前的镜像,单位为小时,默认72
    interval_hour: 72
    # 至少保留镜像个数,默认10
    mix_count: 10
    # 忽略这个项目下所有镜像
    ignore_projects:
    # 项目删除策略
    projects:
    # 是否删除空项目
    delete_empty: false
    # 需删除的关键字
    include:
    # 按关键字进行删除
    keys:
    # 按正则表达式删除
    regex:
    # 排除策略,删除策略与排除策略都匹配,以排除策略为准
    exclude:
    # 按关键字进行排除
    keys:
    # 按正则表达式排除
    regex:

    # 镜像tag删除策略
    tags:
    # 删除策略
    include:
    # 按关键字进行删除
    keys: dev,test
    # 按正则表达式删除
    regex:
    # 排除策略,删除策略与排除策略都匹配,以排除策略为准
    exclude:
    # 按关键字进行排除
    keys:
    # 按正则表达式排除
    regex: latest|master|^[Vv]?(\d+(\.\d+){1,2})$
  • 运行并指定配置文件位置

1
harbor-cleaner -f delete_policy.yml

存储回收

Harbor v1.7.0及以上版本

Harbor从v1.7.0版本开始支持不停机进行在线存储回收。在调用本程序进行软删除后,系统管理员可以通过单击“管理”下“配置”部分的“垃圾回收”选项卡来配置或触发存储回收。

👋 注意 👋在执行存储回收时,Harbor将进入只读模式,并且禁止对 docker registry 进行任何修改。换而言之就是此时只能拉镜像不能推镜像。

Harbor 1.7.0以前版本

Harbor从v1.7.0以前版本进行存储回收时需要手动切断外部访问以达到禁止对 docker registry 进行任何修改的目的。回收镜像所占存储参考文档

  • 切断外部访问入口

  • 进入到registry容器中执行存储回收命令

    1
    2
    3
    4
    # 测试回收,不会真回收,可在日志中看到要回收的镜像
    $ registry garbage-collect --dry-run /etc/registry/config.yml
    # 执行回收,没有后悔药
    $ registry garbage-collect /etc/registry/config.yml

不理想的地方

不论是哪个版本的Harbor进行存储回收都是使用docker registry官方的命令进行回收,但回收空间太少,很多manifests仍没删除。那就只有扫描镜像仓库存储文件,通过docker registry api删除无用的manifests。这里可参考使用mortensrasmussendocker-registry-manifest-cleanup项目。

  • 使用docker-registry-manifest-cleanup当前最新版本进行存储回收
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 执行以下脚本尝试通过api模拟删除manifests
    $ docker run -it \
    -v /home/someuser/registry:/registry \
    -e REGISTRY_URL=https://registry.example.com \
    -e DRY_RUN="true" \
    -e SELF_SIGNED_CERT="true" \
    -e REGISTRY_AUTH="myuser:sickpassword" \
    mortensrasmussen/docker-registry-manifest-cleanup:1.1.1
    # 如上一步没有报错,执行以下脚本,真正删除
    $ docker run -it \
    -v /home/someuser/registry:/registry \
    -e REGISTRY_URL=https://registry.example.com \
    -e SELF_SIGNED_CERT="true" \
    -e REGISTRY_AUTH="myuser:sickpassword" \
    mortensrasmussen/docker-registry-manifest-cleanup:1.1.1

若使用上面命令执行报错找不到目录的错误可切换docker-registry-manifest-cleanup的版本至1.0.5进行尝试

  • 使用docker-registry-manifest-cleanup 1.0.5进行存储回收。
    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
    # 由于以前的版本不支持提权,故将 /etc/registry/config.yml 中的鉴权配置部分先暂时注释掉,重启registry容器
    # auth:
    # token:
    # issuer: harbor-token-issuer
    # realm: https://registry.example.com/service/token
    # rootcertbundle: /etc/registry/root.crt
    # service: harbor-registry

    # 执行以下脚本尝试通过api模拟删除manifests
    $ docker run -it --rm \
    -v /home/someuser/registry:/registry \
    -e REGISTRY_URL=https://registry.example.com \
    -e CURL_INSECURE=true \
    -e DRY_RUN=true \
    mortensrasmussen/docker-registry-manifest-cleanup:1.0.5

    # 如上一步没有报错,执行以下脚本,真正删除
    $ docker run -it --rm \
    -v /home/someuser/registry:/registry \
    -e REGISTRY_URL=https://registry.example.com \
    -e CURL_INSECURE=true \
    mortensrasmussen/docker-registry-manifest-cleanup:1.0.5

    # 执行完成后将授权配置改回来,取消注释
    auth:
    token:
    issuer: harbor-token-issuer
    realm: https://registry.example.com/service/token
    rootcertbundle: /etc/registry/root.crt
    service: harbor-registry

参考文档:

setzero wechat