1. 选型之前,把“制品管理”这四个字先拆明白
最近一年我花了很多时间在制品治理这件事上,Harbor 和 Hadess 都被我团队放进真实环境里跑过。最初我也以为选制品管理工具就是选一个“能存镜像的私有仓库”,后来才发现这个想法会引导选型走向错误的方向。尤其当团队同时有 Java 的 jar、前端的 npm 包、容器镜像和 Helm Chart 时,需要被管理的东西远不止镜像本身。
所以这篇文章不想直接给你一个“Harbor 比 Hadess 好”或者相反的结论,而是把选制品管理工具时的判断逻辑、部署细节和踩坑记录都摊开讲。Harbor 在 CNCF 生态里几乎是容器镜像仓库的标准答案之一,而 Hadess 走的是一条统一制品库的路子,两者在表面上看着都能“存东西”,但解决的是不同场景下的不同问题。这个差异,恰恰是选型的关键。
1.1 我们说的制品,到底指什么
制品(Artifact)这个词在很多团队里被用得很泛,甚至有人把 Git 仓库里的代码也叫“制品”。这会导致第一个认知偏差:如果连管理对象都没定义清楚,工具选型自然无从谈起。
在我自己的定义里,制品是构建过程产生的、可以被交付和部署的产物。它可以是编译出来的 jar 包,可以是 npm pack 之后的 tgz,可以是 Docker build 出来的镜像,也可以是一份 Helm Chart、一个安装脚本、一个固件二进制。它和源代码的区别在于:源代码是有状态的、持续变化的,而制品应当是“一次构建、永久固定”的。制品管理工具的核心职责,就是让这个“永久固定”真正成立。
这也是为什么我不建议把制品随便丢在某个 FTP、NFS 共享目录或者对象存储桶里。丢进去容易,但版本怎么追溯?谁在什么时间传上去的?哪个版本对应哪次构建?生产环境用的包有没有被篡改过?这些问题一旦多起来,光靠文件夹命名和人工记录是扛不住的。
1.2 制品管理工具必须解决的五个问题
把需求拆开之后,制品管理工具本质上是围绕五个问题设计的:
第一是存储。制品体积可能很大,镜像尤甚,所以存储后端要能横向扩展、能对接对象存储,而不是只靠宿主机一块盘。第二是版本不可变。同一个标签不能被覆盖,否则就会出现“测试环境没问题,生产环境拉下来的却是另一个内容”的灾难。第三是分发效率。跨区域拉取镜像、下载依赖包,不能每次都回源,复制和缓存能力直接影响发布速度。第四是权限与审计。谁能推、谁能拉、谁能删,必须能追溯到人;对外部集成方来说,机器人账号而非真实员工密码是底线。第五是安全。入库之前至少要做一次漏洞扫描,镜像是 CVE 扫描,语言包也要查依赖树里的已知风险。
把这些问题列出来后再看 Harbor 和 Hadess,你会发现它们的设计取舍完全不同。Harbor 把“安全、稳健、以容器镜像为中心”做得极其扎实;Hadess 则把“统一、多格式、团队协作”作为切入角度。两者都能存制品,但它们对“制品管理”这四个字的理解,出发点并不一样。
2. Harbor 凭什么成为大多数团队的默认选择
Harbor 之所以在云原生场景里几乎成了私有镜像仓库的代名词,背后有很清晰的逻辑。它不是在裸 Registry 上套了一个壳,而是把企业使用镜像仓库时需要的整层能力都补齐了——权限、配额、复制、扫描、签名、审计。对大多数团队来说,只要核心交付物是容器镜像,Harbor 就是一个不太需要犹豫的答案。
2.1 Harbor 的技术骨架
从组件定义来看,Harbor 不是单进程应用,而是一组服务的组合。最外层是 Nginx,负责 HTTPS 终结和流量转发;核心服务负责 API、认证授权和项目管理;Registry 组件负责镜像层数据的存储;JobService 干复制、清理这类异步任务;PostgreSQL 存元数据;Redis 做缓存;可选的 Trivy 或 Clair 提供漏洞扫描能力。
这套架构的优点很清楚:每个组件都有成熟的替代方案,比如存储后端可以切换成 S3 或阿里云 OSS,数据库也可以用外部 PostgreSQL,不会把自己锁死在某个特定环境里。它和 Kubernetes、Helm、Docker 的集成方式也最贴近原生工具链。
缺点则是运维维度会稍微复杂。Harbor 一跑起来就是七八个容器,日常维护要关注数据库备份、对象存储容量、日志轮转、扫描器更新这些事。如果团队没有专人愿意维护这套东西,只是想要一个“能推能拉的仓库”,你会觉得 Harbor 很重。
2.2 CentOS 7 上跑通 Harbor 的完整路径
我把 CentOS 7 上搭建 Harbor 的过程重新走了一遍,很多细节其实比想象中容易踩坑。第一步先装 Docker 环境。CentOS 7 自带的老版本 Docker 太旧,直接装 docker-ce,建议版本在 20.10.x 左右,不要追最新的 26.x 系列。新版 containerd 在 CentOS 7 上有时候会和系统的 iptables 组件配合出问题,我遇到过几次容器网络异常,降回 20.10 以后稳定下来。
第二步是装 docker-compose。Harbor 离线安装包自身不带 compose 的可执行文件,CentOS 7 上第一次跑 install.sh 很容易报docker-compose: command not found。我建议直接把 docker-compose 1.29.2 放到 /usr/local/bin/docker-compose 并给执行权限,这个版本在 CentOS 7 上表现最稳。用官方的 docker compose v2 也没问题,但会被系统 Python 环境和 glibc 版本干扰。
第三步是下载 Harbor 离线安装包并解压,修改 harbor.yml。最重要的配置项是 hostname,千万别写 127.0.0.1。写 127.0.0.1 会让别的机器没法用这个仓库,而且后续改起来麻烦。我一般直接写服务器的内网 IP,如果公司有内部域名就写域名,同时保证域名能够被所有开发和构建机解析。
harbor.yml 里还有几个容易忽略的点。http 端口默认 80,如果被其他服务占用了就改成 8080;harbor_admin_password 要求至少 8 位;data_volume 不要放在根分区,否则镜像一多磁盘瞬间就爆了。如果先跑 HTTP 模式,别忘了在所有要登录仓库的机器上配置 Docker daemon 的 insecure-registries。我见过太多人镜像仓库搭好了,其他机器 login 却报证书错误,最后发现是 insecure-registries 没加。
第四步执行./install.sh。如果需要漏洞扫描功能,在后面加--with-trivy。这一步会生成 docker-compose 配置并拉取镜像,CentOS 7 上如果之前没有 docker compose 设置,可能还要稍等片刻。启动完成后打开 UI,用 admin 账号登录,先把系统管理里的仓库配额和垃圾回收策略配置好,再让团队往里推镜像。
验证方式很简单:在一台能访问这台机器的开发机上执行docker login,然后随便打一个镜像 tag 推上去。如果 push 报证书错,八成是 cert 或 insecure-registries 的问题;如果报权限错,就要回 Harbor 里创建项目并把当前用户加入成员。
2.3 Harbor 用深了才会遇到的三个“软肋”
第一个软肋是垃圾回收并不像想象中那么“及时”。Harbor 的 GC 清理的是没有被任何指向的镜像层,而不是你通过 UI 删除的 tag。比如一个镜像 tag 被删除后,只要层还被其他镜像引用,GC 就不会真正释放空间。解决思路是定期跑 GC,同时用保留策略把过期 tag 自动清掉,双管齐下之后磁盘回收才会正常。
第二个软肋是对非镜像制品的支持相对有限。Harbor 虽然支持 OCI Artifact,也能托管 Helm Chart,但日常体验下来,它的主战场就是容器镜像。你如果想让开发团队把 jar 包、npm 包也往里传,Harbor 的 UI、元数据模型和权限粒度都不太匹配。这不是缺陷,而是定位问题,可一旦团队有多语言的制品需求,Harbor 就只能解决其中一部分。
第三个软肋是升级路径。Harbor 大版本升级前必须重新读所跨越版本的升级说明,数据库迁移步骤一旦顺序错了,整个实例都可能起不来。我有一个环境从 2.2 往 2.9 升级,中途因为跳过了 2.4 的某个数据迁移脚本,导致核心服务一直报数据库字段不存在。后来只能从备份恢复,老老实实按版本逐级升。所以生产环境升级 Harbor,必须备份数据库和数据目录,最好先在临时环境跑一遍同样的升级流程。
3. Hadess 为什么值得放进对比清单
很多人看到 Hadess 的第一反应是“没听过”。这也正常,它的公开曝光度远不如 Harbor,但在我接触到的团队里,确实有人把它作为统一制品库的核心组件在使用。我最初对它也抱着怀疑态度,直到一个同时需要管理大量非镜像产物的项目上线,我才意识到 Harbor 覆盖不到的痛点,恰好在 Hadess 这类工具的能力范围内。
3.1 Hadess 解决的问题域
Hadess 给自己的定位并不是“又一个镜像仓库”,而是“制品中心”。它可以同时管理 Maven、npm、PyPI、NuGet、Helm Chart、容器镜像甚至普通二进制文件,让研发团队在一个入口里面对所有类型的产物。我实际测试的版本具备这么几个能力:对上游公共仓库做代理缓存、在 CI 构建过程中直接接收制品并记录构建元数据、以及按组织架构配置权限。
代理缓存这个能力值得多说两句。Java 团队每次构建都要去拉公共仓库的依赖,前端团队要拉 npm 包,如果不做缓存,每次构建都会把大量时间花在网络请求上,而且一旦上游仓库出现不稳定,整个构建链路都会受影响。Hadess 的做法是在本地保留一份缓存,首次拉取后后续请求直接命中,这对多团队共用同一套基础设施的场景非常友好。
构建元数据记录则是另一个亮点。推送到制品库的每个制品都可以关联构建号、代码提交号、分支信息、构建时间,发布时一眼就能追溯到具体来源。这个能力在事故排查时价值极高,不用再翻 Jenkins 或流水线日志,直接看制品详情页就知道是谁在什么代码版本下产出的。
3.2 和 Harbor 最大的区别在于治理粒度
Harbor 的权限模型以项目为基本单位,项目里再分角色,给机器人账号细分权限。这种模型对容器镜像团队非常够用。但当我面对多个业务线、每个业务线下又有多个团队、团队里混合着 Java 后端和前端工程时,Harbor 的扁平项目模型就不太够用了。
Hadess 更强调分层治理。权限可以按组织架构去建,部门和团队之间的关系可以在权限体系里体现出来。制品库不再是每个团队独立维护的项目堆叠,而是共享基础设施中带清晰归属的空间。这种粒度差异在几十人规模时感受不明显,到几百人、上千人的研发组织中就会变成刚需。
当然,这并不代表 Hadess 在镜像管理上一定比 Harbor 强。镜像签名、复制策略、OCI 生态的成熟度、Kubernetes 集成这些能力,Harbor 经过多年演进,依然是赢面更大的一方。Hadess 的强项在“广度”,Harbor 的强项在“深度”。
3.3 使用 Hadess 前必须保留的“验证心态”
我必须诚实地说明一点:Hadess 在不同版本之间的能力差异比较大,而且公开文档做得不如 Harbor 详尽,我测试的版本和你拿到的版本可能存在明显不同。所以如果有人让你引入 Hadess,别急着全量迁移,先申请一套独立的测试环境,把你们最典型的 CI/CD 流水线完整跑一遍,确认代理、权限、扫描这几个核心功能都符合预期再上线。
另一个需要验证的点是存储后端。Harbor 对对象存储的支持已经非常成熟,而 Hadess 在某些版本里对存储后端的适配范围更窄,如果你们本身已经有对象存储而且数据量很大,要提前确认兼容性。
4. 六个决策维度的正面硬刚
把 Harbor 和 Hadess 放在同一张表里比较,最怕的是只比功能清单,不比“你的团队到底在哪个维度上有痛点”。所以我设计了六个决策维度,每个维度都对应一类真实场景。
4.1 六维对比一份表说清
| 对比维度 | Harbor | Hadess |
|---|---|---|
| 定位 | 专业容器镜像仓库 | 统一制品库 |
| 格式支持 | 以 Docker 镜像、OCI 制品、Helm Chart 为主 | 覆盖 Maven、npm、PyPI、镜像、二进制等多种格式 |
| 安全能力 | 镜像漏洞扫描、签名、不可变标签 | 多类型制品扫描与审计,具体能力需实测确认 |
| 权限模型 | 项目维度 + 机器人账号 | 更接近组织架构的分层权限 |
| 生态集成 | Kubernetes、Helm、Tekton、ArgoCD 等云原生工具链成熟 | CI 流水线插件和 API 集成较灵活,但社区生态仍在成长 |
| 运维开销 | 组件多、升级复杂、需专人维护 | 部署形态更偏向整体平台,运维模型因版本而异 |
这张表虽然简单,但已经能看出两个工具不是同一物种。Harbor 更像是“镜像仓库的极致打磨”,Hadess 更像是“软件交付全域的大一统”。选哪个,完全取决于你的工作负载里容器镜像到底占多大比重。
4.2 如何用“镜像占比”快速判断方向
我给自己定了一个粗略的判断标准:如果团队交付物里超过 80% 是容器镜像,闭眼选 Harbor,它带来的稳定性和生态优势最大。而如果非镜像制品占比超过 30%,比如你们有大量 jar 包、npm 包需要管理,那单纯一个 Harbor 就不够了,要么引入统一制品库,要么补充一套语言包仓库工具,否则只能继续忍受手动把文件传到对象存储的原始状态。
这里有个容易犯的错误:以为可以先上 Harbor,等将来有需要再叠加 Hadess。理论上这是可行的,实际推进复杂度比想象中高很多。两套工具并存意味着开发者需要同时记住两个仓库地址,CI 流水线需要分别对接两套认证体系,制品追踪也要跨系统做关联。所以在选型早期就把未来两到三年内的交付形态想清楚,比纠结当前两个工具的功能差异更重要。
5. 更重要的还是落地姿势:我踩过的坑和补救办法
工具选得好只是第一步,真正决定成败的是落地过程。我在推进制品库治理的过程中踩过不少坑,有几个经验我认为比功能对比更有参考价值。
5.1 先把制品命名和不可变性定下来
没有规范的制品命名,再好的工具也会变成一个新的“垃圾场”。我在团队里定了三条硬规则:制品名称必须包含业务模块名和环境标识;镜像 tag 一律用构建号或 Git 短提交号,禁止使用 latest;每个制品的版本号一旦发布就不能覆盖,删除必须走审批流程。在 Harbor 里可以打开不可变标签功能,同时在 CI 流水线里加一道检查,发现有人往已有的 tag 上重复推送就直接失败。
一开始团队成员会觉得这些规则烦,但经历过一次“生产环境镜像 tag 被覆盖导致回滚失败”的事故以后,所有人都理解了不可变性的价值。制品库本质上服务于交付的可追溯性,如果制品本身可以随意变化,那追溯就没有意义了。
5.2 存量仓库迁移不要“一刀切”
我们当时有一个运行了很久的裸 Registry,里面堆了上千个镜像,有些是灰度中的,有些是已经废弃的。刚开始我计划一次性全部迁到 Harbor,后来发现不可行,因为裸 Registry 里的镜像元数据不完整,有些 tag 对应的镜像层早就不完整了。强行迁移会导致部分拉取失败。
后来改成按服务分批迁:先梳理在线服务依赖哪些镜像,把活跃镜像优先迁移;历史废弃镜像只保留清单,不做物理迁移。这样整个迁移过程持续了两周,期间没有出现一例影响发布的故障。这个经验对任何仓库迁移都适用,制品库迁移的难点从来不在“拷贝数据”,而在“搞清楚哪些数据还有价值”。
5.3 三个反复出现的基础设施问题
第一个是证书问题。Harbor 启用 HTTPS 后,自签证书如果缺少 SAN 扩展,Docker 客户端会在 TLS 握手阶段直接拒绝连接,报错信息里会提示找不到 IP SAN。用 openssl 生成证书时一定要加上-extfile指定扩展段,把服务器 IP 和域名写进 subjectAltName。
第二个是磁盘空间问题。Harbor 的数据目录、数据库、日志如果都放在同一个磁盘分区上,一个环节暴涨就会拖死其他环节。我把数据卷单独挂到一块大容量盘,数据库和日志目录也分开,再配上日志轮转,之后基本没有再出现过磁盘写满的情况。
第三个是权限泄漏问题。给开发环境的机器人账号赋权限时,我最初图省事直接给了项目管理员,后来发现某些开发同学拿这个账号登录后能改动保留策略,导致一批旧镜像被意外清理。正确做法是每个账号只给最小必要权限,机器人账号能只读拉取就不给推送权。
6. 如果让我重新选一次
做了这么多对比之后,我自己的结论其实很朴素:不要为了“统一”而被迫用一个处处都要将就的工具,也不要因为 Harbor 名气大就无视它不擅长管理多语言包的事实。
如果今天让我重新主导一个从零开始的团队制品基础设施,我会这样选。第一阶段绝大多数团队仍然可以优先布 Harbor,把容器镜像的交付链路先理顺,快速获得不可变标签、镜像扫描和复制能力。第二阶段再去评估是否需要一个统一制品库来承接非镜像产物,如果确实需要,就把两份工具的作用边界划清楚:镜像走 Harbor,构建产物走 Hadess 或同类工具,中间通过 CI 流水线把它们串联成一条完整的交付链。
工具本身不是目的,让交付过程可重复、可追溯、可审计才是目的。Harbor 和 Hadess 都有自己擅长的一面,只要贴合团队实际的痛点,选哪个都不会错。怕的是一边看着别人的最佳实践眼馋,一边又把仓库当成菜板随便乱丢东西,那样的团队换任何工具都救不回来。