Atlantis
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

3.3 harbor

1. 前言

生成式 AI 说,Harbor 是一个企业级的 Docker 镜像仓库管理工具,它提供了以下主要功能:

  1. 镜像托管与分发
    1. 支持 Docker 和 OCI 标准的镜像格式存储和分发
    2. 提供安全的镜像存储和传输,包括 HTTPS 和 Token 认证等
  2. 镜像生命周期管理
    1. 支持镜像的自动扫描和漏洞修复
    2. 提供基于角色的访问控制(RBAC)和审计功能
    3. 支持镜像复制和镜像垃圾回收等高级管理功能
  3. 多租户和项目管理
    1. 支持创建多个项目,每个项目拥有独立的镜像仓库
    2. 支持基于项目的权限管理,实现细粒度的访问控制
  4. 高可用和可扩展性
    1. 支持集群部署,可通过负载均衡实现高可用
    2. 支持 HA 数据库、对象存储等各个组件的水平扩展
  5. 集成与扩展
    1. 提供 API 接口,可与 CI/CD 系统等外部系统集成
    2. 支持插件扩展,可集成云服务商的认证系统等

不过简单来讲,它是一套工具集,核心的功能是基于 registry 和 chartmuseum 封装出的支持多用户的私有镜像仓库和 Helm Chart 仓库,我们可以使用使用它代替 DockerHub,构建一个完全离线的镜像仓库~前提是有稳定的 S3 存储、PostgresSQL 数据库和 Redis 缓存。

我维护过的 Harbor 最多存储了 260 多万个容器镜像,占用接近 30TB 的 S3 存储, 缓存镜像 layer 数据的 Redis 内存占用超过 50G,且 PostgreSQL 数据库并没有做什么调优,代价是偶发 5xx 错误,加载镜像列表缓慢,就这样的前提下,经过一些调整还撑了一年多时间,只能说,Harbor 确实是一个优秀的开源软件。

每个容器从业者都应该有一个自己的镜像仓库,这里简单讲下如何在 K3s 中部署 Harbor。

2. 部署

Harbor 的组件数量较多,而且配置有些复杂,最简单的办法是使用 Helm 部署,然后再调优或者手动升级,我们希望使用已有的 S3 存储、Postgres 数据库,并使用 ingressroute 暴露服务,在部署前需要做一些准备工作:

  1. 在 Minio 中创建一个 harbor 专用的 bucket、accesskey、secretkey
  2. 在 Postgres 中创建一个 harbor 专用账号,以及三个数据库:coreDatabase、notaryServerDatabase、notarySignerDatabase

Redis 使用 Harbor 的 Helm Chart 自带配置部署,因为 Harbor 会固定占用 Redis 的 0~5 号数据库,这里就不和公共的 Redis 混杂在一起了。

接下来添加 Harbor 的 Helm Repo 并下载 Chart,这里使用的是 1.9.3 版本的 Chart(对应 2.5.3 版本的 Harbor):

helm repo add harbor https://helm.goharbor.io
helm repo update
helm fetch harbor/harbor --untar --version 1.9.3

进入 harbor 目录可以看到以下文件:

➜  harbor ls -lh
total 252K
drwxr-xr-x  2 root root 4.0K Aug 14 15:05 cert
-rw-r--r--  1 root root  566 Aug 14 15:05 Chart.yaml
drwxr-xr-x  2 root root 4.0K Aug 14 15:05 conf
-rw-r--r--  1 root root  12K Aug 14 15:05 LICENSE
-rw-r--r--  1 root root 189K Aug 14 15:05 README.md
drwxr-xr-x 16 root root 4.0K Aug 14 15:05 templates
-rw-r--r--  1 root root  32K Aug 14 15:05 values.yaml

编辑 values.yaml,执行以下修改:

  1. 配置 expose,选择 clusterIP 的方式暴露服务并设置 tls 的 enabled 为 false,这样就会创建一个 harbor 的 service,指向 nginx 的 80 端口,这个 nginx 会将请求自动分流到 harbor-core、harbor-portal、harbor-chartmuseum 等
  2. 配置 externalURL,设置需要暴露到外网的域名
  3. 设置 imageChartStorage 的类型为 s3,这样 Helm Chart 以及容器镜像都会存储到 Minio,注意 region 默认为 us-east-1
  4. 设置 database 的类型为 external,填写 harbor 专用的账号及数据库名
  5. 关闭不常用的服务:trivy、notary 和 trace,如果需要接入 Prometheus 监控 Harbor,可以启用 metrics 组件。

修改完成后,在 harbor 目录下执行命令安装,这里使用 harbor 命名空间:

helm  -n harbor install harbor  .

安装完成后,如果修改了 values.yaml,可以执行以下命令更新:

helm -n harbor upgrade harbor .

部署完成后,在 ingressroute 中添加一个 Rule 暴露 harbor 命名空间下的 harbor 服务即可。

alt text

3. 使用

Harbor 的功能十分丰富,这里讲一下常用的几种。

镜像托管

Harbor 使用项目管理容器镜像与 Helm Chart,授权也是以项目维度执行的,我们可以创建一个机器人账户专用于拉取和推送镜像。

alt text

镜像代理

创建项目时如果勾选镜像代理,可以就可以提供类似 docker registry 的 pull through cache 功能,比如创建了一个 proxy 项目代理 DockerHub,假设当前 Harbor 域名为 image.wbuntu.com,如需拉取容器镜像 wbuntu/gost:v2.11.5,执行以下命令即可:

docker pull image.wbuntu.com/proxy/wbuntu/gost:v2.11.5

alt text

镜像复制

Harbor 支持从其他镜像仓库 Pull 镜像以及将本地镜像 Push 到其他镜像仓库,可以使用镜像名、Tag、标签、资源类型匹配,下面是从 DockerHub 同步 alpine:3.18 镜像的配置:

alt text

4. 验证新版本

在按照 1.9.3 版本做完记录后,我尝试部署 1.15.0 版本,目前看区别如下:

  1. helm 版本要求大于 3.10.0
  2. 审查服务只保留 trivy,数据库只需创建一个 coreDatabase

这次保留了原始的 values.yaml,使用 diff 看一下修改部分,内容不多:

➜  harbor diff values.yaml values.yaml.backup
4c4
<   type: clusterIP
---
>   type: ingress
11c11
<     enabled: false
---
>     enabled: true
112c112
< externalURL: https://image.wbuntu.com
---
> externalURL: https://core.harbor.domain
194c194
<     type: s3
---
>     type: filesystem
218,222c218,222
<       region: us-east-1
<       bucket: harbor
<       accesskey: xxxxxx
<       secretkey: xxxxxx
<       regionendpoint: https://xxxxxx
---
>       region: us-west-1
>       bucket: bucketname
>       #accesskey: awsaccesskey
>       #secretkey: awssecretkey
>       #regionendpoint: http://myobjects.local
886c886
<   type: external
---
>   type: internal
936c936
<     host: "postgres.storage"
---
>     host: "192.168.0.1"
938,940c938,940
<     username: "xxxxxx"
<     password: "xxxxxx"
<     coreDatabase: "xxxxxx"
---
>     username: "user"
>     password: "password"
>     coreDatabase: "registry"