1. 先别急着比工具:制品管理工具到底在管什么
"制品管理工具"这几个字听起来很后端,实际上天天跟前端、后端、运维、测试都打交道。我之前在一家公司同时跑着 Java、Node、Python 三条业务线,第一周就发现:Jenkins 构建完之后,jar 包传到某个 Windows 共享目录,npm 包塞进私有仓库,Python wheel 散落在各成员的个人电脑上,Docker 镜像直接推到一台没有账号密码校验的 registry。等要发版本的时候,没人能在十分钟内说清楚"上一个版本的制品到底在哪一份服务器上"。
制品仓库要解决的就是这件事——给所有构建产物一个统一的"出生地"和"存档地"。从 CI/CD 流水线的角度去看,制品管理工具正好卡在中间环节:左侧是代码仓库,右侧是部署环境。代码只是"原材料",构建出来的包和镜像才是真正上线的东西,而这个"真正上线的东西"如果连存储都管理不好,后面谈环境一致性、版本回滚、安全审计全是空中楼阁。
具体拆开看,制品管理工具需要填四个坑:
- 依赖获取。构建环境需要一个稳定可达的包源。外网依赖如果经常抖动,就得有代理缓存兜底,否则每次构建都可能因为一个转移下载失败而挂掉。
- 产物发布。每次构建结束后,jar、npm 包、镜像、安装包必须有一个规范的发布路径,不能人肉扔到某台服务器上。
- 可追溯性。版本号、哈希值、流水线编号、提交号,这些信息要能串成一条链,出问题时能顺着链追到"哪个代码提交产出了这个包"。
- 团队协作。并不是所有人都该对制品目录拥有删改权限。研发能推,测试能拉,运维能清理,这需要清晰的权限边界。
Nexus 和 Hadess 的差异,本质上就是在这四个坑里选了两个不同的侧重:Nexus 更像"包管理器世界的聚合器",把 Maven、npm、PyPI、NuGet 这些生态统一收口;Hadess 这类容器优先的仓库则更像"OCI 镜像世界的保险箱",围绕 Docker 镜像的推送、拉取、复制和不可变追踪做设计。两者不是同一物种,强行放在一个擂台上一决高下,很容易得出错误结论。
这一点,我建议在往下看之前先建立起来:Nexus 和 Hadess 是"不同赛道上的选手",选型的第一件事不是打分,而是先判断你团队的核心制品长什么样。
1.1 制品仓库和文件服务器的本质差别
很多人会反问:我把构建产物随便丢到 MinIO 或者 NFS 共享目录里,不行吗?
短期跑一个小项目确实"能用",长期下来一定会撞上这些破事:
- 没有代理缓存的概念。外网依赖每次构建都要重新下载,网络一抖,构建就挂。
- 文件版本被覆盖了没人知道。昨天发的包被今天的包覆盖掉,回滚时才发现"找不到上一版"。
- 没有权限和审计。谁删了哪个文件完全无迹可寻。
- 没有元数据检索。目录里的文件堆到 10 万件时,光列个目录都能卡半天。
文件服务器只提供"存储语义",制品仓库提供的是"制品生命周期管理语义"。仓库知道哪个包被谁推过、哪个组件被哪个构建引用过、哪些代理缓存在过去 30 天没有被访问过。这些语义在文件服务器上不存在,需要重新造轮子。
1.2 团队规模不同,需求画风完全不一样
5 个人的小团队,Nexus OSS 单点部署就够了,不需要高可用,也不需要 CVE 扫描。
50 人以上、多产品线并行,就开始需要回收站、保留策略、镜像不可变性、多集群复制、审计日志这些东西。
到了 K8s 平台团队,重点又变了。他们要的是 OCI registry 能力,是镜像签名、漏洞扫描、不可变 tag、跨机房同步,而这些恰恰是通用制品仓库做得不够深的地方。
所以你看,同样是"选型制品管理工具",站在不同团队规模下,关注点根本不在一个维度上。下面的对比,我会把这些维度逐个摆出来。
2. 一张功能对照表,先框住选型维度
动手对比 Nexus 和 Hadess 之前,建议先做一张功能需求清单,把评估维度列清楚。我自己在做选型时经常用下面这张表:
| 评估维度 | 这条为什么重要 | 选型时重点看什么 |
|---|---|---|
| 包格式支持 | 团队的生态决定了格式,Maven、npm、PyPI、NuGet、OCI 是几个大头 | 是否原生格式支持,还是只能 raw 上传凑合 |
| 代理与缓存 | 内网构建稳定依赖,外网依赖抽风时靠缓存兜底 | proxy 仓库的配置能力、TTL、上游节点切换 |
| 权限模型 | 研发、测试、运维的入口不同,不能都拿管理员 | 角色粒度、LDAP/SSO、机器人 token 支持 |
| 安全扫描 | 上线前要能发现依赖漏洞,合规需要留痕 | CVE 库更新机制、扫描触发方式、报表导出 |
| 复制与容灾 | 多机房部署,镜像和包要在两地可读 | 单向/双向复制,异地同步延迟 |
| 清理与保留策略 | 存储成本要控制,但误删生产版本更可怕 | 保留版本数、宽限期、回收站机制 |
| 审计与不可变性 | 发布追溯和合规要求 | 操作日志、镜像不可变 tag、对象锁定 |
| API 自动化 | 和 CI/CD 集成,减少人肉操作 | REST API 丰富度、CLI、Webhook 支持 |
| 成本模型 | 开源免费和商业版本差异很大 | 许可模式、额外功能收费点、镜像存储费用 |
这张表贴到自己的协作文档里,每项按团队真实需求打分,比靠印象和社区热度去选靠谱得多。
2.1 哪些维度看着重要,其实可以往后放
完整的功能表容易让大家陷入"清单焦虑"。实际操作中,有几个维度是被高估的:
- 安全扫描:如果产品还没上线,客户也没有合规审计要求,扫描可以先不做,后续再补。
- 复制与容灾:单机房部署、数据量小,双向复制纯属添乱。
- 成本模型:OSS 版本能跑就不要急着买商业版,很多团队购买商业版后,一年到头用到的也就是"高可用"那几个按钮。
真正决定选型方向的,通常只有三个:包格式、权限粒度、运行环境。
2.2 用"三问法"收敛需求
我给很多团队梳理过选型需求,最后都会落到三个问题上:
- 团队主要在构建什么格式的制品?是 Java 的 jar、前端包、Python wheel,还是以 Docker 镜像为主。
- 这些制品是给一台机器用,还是要分发到几十上百个节点?部署范围决定了对复制、签名、不可变性的要求。
- 未来半年到一年,会不会有安全合规或审计需求?如果有,仓库的扫描和审计能力就不能缺。
把这三个问题的答案写出来,再往回看功能对照表,大半工具已经被排除掉了。
3. 再看 Nexus:为什么它在通用制品领域地位这么稳
Nexus 我从 Nexus 2 时代开始用,一直到 Nexus 3,横跨了差不多十年。它在通用制品管理领域地位稳,不是没有理由的。
3.1 三类仓库模型是它的杀手锏
Nexus 的核心设计是三类仓库:proxy、hosted、group。
- proxy(代理仓库):把外部的中央仓库内容做缓存。比如你配一个 Maven Central 的 proxy,团队所有环境的依赖都从它这里拉,只有缓存未命中时才回源到公网。这对网络抖动的容忍度提升是实打实的。
- hosted(托管仓库):存放公司内部自己构建的制品,这些制品只属于你们团队,不依赖任何上游。
- group(聚合仓库):把多个 proxy 和 hosted 仓库合并成一个对外地址,构建工具只需要配一个 URL 就能同时访问内部制品和外部缓存。
这套模型最妙的地方在 group 仓库。以 Maven 为例,你不用让每个开发者在 settings.xml 里写大学同学的私有仓库地址,也不用让 Jenkins 单独配外部中央库。一个 group 地址,从上到下聚合,构建配置永远只需要改一处。npm、PyPI、NuGet 仓库同样适用。
3.2 多格式支持与 Blob Store
Nexus 3 不再像 Nexus 2 那样按格式分隔实例,而是同一个服务里直接支持 Maven、npm、PyPI、NuGet、Docker、Yum、Apt、Raw 等格式。这一点在语言栈混杂的团队里非常省事——一套服务、一套账号体系、一套权限,不需要每个语言单独搭私服。
存储层的概念是 Blob Store。每个 Repository 背后对应一个 Blob Store,Blob Store 决定实际文件落在哪个磁盘路径。我有一个习惯:把重要的 hosted 仓库单独放到一块独立的 Blob Store 里,这样备份时可以只备份关键制品,而不是整盘一锅端。磁盘规划更灵活,恢复粒度也更清晰。
3.3 REST API 与自动化的实际体验
Nexus 3 的 REST API 做得比较完整,日常管理基本可以脱离 UI。常用操作我整理过几个:
# 查询仓库列表 curl -u admin:admin123 \ "http://nexus.example.com/service/rest/v1/repositories" # 搜索指定仓库里的组件 curl -u admin:admin123 \ "http://nexus.example.com/service/rest/v1/search?repository=internal-repo&name=common-lib" # 获取组件详情,拿版本号、格式和大小 curl -u admin:admin123 \ "http://nexus.example.com/service/rest/v1/search?repository=internal-repo&name=common-lib&version=1.2.3"我通常会在 CI/CD 最后一步,让流水线去调用一次搜索接口,把产物坐标和构建号写入部署清单。这样后期排查"这个包是谁在什么时候构建出来的",直接看部署清单就能定位,不需要再去 UI 里翻。
3.4 Nexus 的局限也不能回避
Nexus 有两点我想吐槽。一是UI 设计确实老旧,信息密度很大但交互逻辑停留在十年前,第一次用的人需要时间适应。二是OSS 和 Pro 的功能边界很明显,安全扫描、高可用、热备份这些能力在 OSS 版本里缺失,如果团队明确需要这些功能,要提前把预算算进去,别等部署完才发现要继续买授权。
4. Hadess 的真实定位:容器优先的制品仓库
看到标题里 "Hadess" 这个拼写,我先说明一下:目前社区里更常见的名称是Harbor(Harbor),也有一些团队会把自己内部的轻量制品服务直接叫成 Hade 之类的代号。如果你在选型清单上看到的是 "Hadess",大概率是以下两种情况之一:要么是 Harbor 的笔误,要么是团队内部对某个自研制品仓库的代号。下面的分析我按"容器优先、Harbor 类制品仓库"的能力模型来讲,这也是这类工具最典型的定位。
4.1 容器镜像管理的核心逻辑
Hadess 这类容器优先的仓库,思想不是"包坐标",而是OCI Distribution 规范。它围绕 Docker 镜像的 push、pull、tag、digest 来组织。和 Nexus 这种通用制品仓库相比,有几个非常明显的差异:
- 镜像仓库粒度:每个项目一个 repository,镜像的 tag 和 digest 是核心标识。回滚操作直接依赖 digest,比"重新打 tag"更可信。
- 镜像代理和拉取缓存:可以代理 Docker Hub 或上游私有 registry。集群节点从本地拉镜像,速度和稳定性都会好很多。
- 不可变 tag:镜像推上去之后禁止覆盖同名 tag。这对生产环境非常重要,能防止"排查问题时发现线上镜像被偷偷改掉"的尴尬。
- 复制与多集群同步:多个 K8s 集群、多个机房之间做镜像复制,异地容灾时是刚需。
- GC(垃圾回收):长期运行后会有大量孤儿层,GC 机制能把无用的镜像层清理掉,否则磁盘会悄悄被吃满。
如果团队的核心交付物是 Docker 镜像,Hadess 这类工具天生就比 Nexus 更适合。原因是它从设计之初就理解"镜像层"这个数据模型,存储去重、拉取加速、复制同步都针对这个模型做了优化;而通用制品仓库对 OCI 镜像的支持,本质上是"能用,但没有做到极致"。
4.2 不可变 Tag 和审计能力,是容器仓库相对通用仓库的重要加分项
我见过太多团队在私有 Docker registry 上翻车:某个"latest" tag 被反复覆盖,出问题后谁也不知道当前 running 的镜像到底是哪次构建出来的。Hadess 类工具默认会支持不可变 tag 或内容签名,推送相同 tag 会直接拒绝,CI/CD 只能通过新增 tag 或明确 digest 来发布。这在发布追溯和回滚时价值非常大。
另外,容器镜像的安全扫描不是可选项。镜像一旦进入生产集群,镜像层的漏洞会直接影响运行时安全。Hadess 类仓库通常会集成 Trivy、Clair 这类扫描引擎,push 之后自动出报告,比在 Nexus 里把镜像包当作通用组件去扫描要自然得多。
4.3 与 Nexus 的典型差异对比
| 对比点 | Nexus | Hadess(容器优先) |
|---|---|---|
| 数据模型 | 包坐标 + 版本号 + 格式 | 镜像仓库 + tag + digest |
| 核心优势 | 多格式统一、代理/聚合强大 | OCI 镜像原生管理、不可变 tag、复制 |
| 权限模型 | 角色 + 仓库/组件权限 | 项目级授权 + 机器人账户 |
| 扫描 | OSS 版缺扫描,Pro 才有 CVE 能力 | 镜像推送后自动触发扫描 |
| 适用场景 | 语言构建产物为主 | K8s、Docker 镜像为主 |
如果你问"Hadess 能不能替代 Nexus",我会回答:在容器镜像场景,Hadess 比 Nexus 更适合;在语言构建产物场景,Hadess 替代不了 Nexus。两者不是同一个技能树上的工具,强行替换会让某一侧付出额外成本。
5. 一条流水线里让 Nexus 和 Hadess 配合起来
大多数团队的真实情况是:语言包和容器镜像同时存在。Java 项目用 Maven 构建 jar,再把 jar 打进镜像;前端项目用 npm 管理依赖发布,最终产物也打包进镜像。这种情况下,Nexus 和 Hadess 不是二选一,而是可以同时存在、各管一段。
5.1 最常见的配合形态
我在一个中型后端团队里搭过这样的流水线:
- 代码提交触发 CI,拉取依赖时统一走 Nexus 的 group 仓库。
- 构建结束产生 jar 包,推送给 Nexus 的 hosted 仓库,作为语言产物存档。
- 再基于这个 jar 包构建完整 Docker 镜像,推送到 Hadess(Harbor 类)仓库。
- 后续所有集群部署直接写 Hadess 的镜像地址,核心镜像不可变,同时启用扫描。
- 发布单里同时写 Nexus 里的 jar 坐标和 Hadess 里的镜像 digest。
这套结构下,Nexus 管"依赖和构建产物",Hadess 管"运行时交付物",两者各司其职。回滚时优先看镜像 digest,追溯构建产物再去 Nexus 查 jar 坐标,链条非常清晰。
5.2 仓库命名和代理链路的规划
配合使用时最需要提前想清楚的是命名规范。我的建议是:
- 在 Nexus 里按团队名建 hosted 仓库,内部包名建议带上公司域名反转,避免和公共包冲突。
- 在 Hadess 里按项目建镜像仓库,镜像名统一用项目代号,tag 只允许用版本号或 commit 短哈希,禁止用 latest 打到生产环境。
- 代理链路不要层层叠。比如 npm 只配一个 proxy 指向 npmjs,不要一个 proxy 指另一个 proxy,否则回源排队和异常排查都会变成噩梦。
5.3 统一认证和权限是另一个隐藏的大头
两套系统同时跑,如果各自维护一套账号密码,研发很快就会被搞烦。我的做法是走统一入口:
- Nexus 和 Hadess 都接入公司的 LDAP/SSO,让研发用同一个员工账号登录。
- CI/CD 流程里使用机器人账户或 token,而不是拿某个人的人头账号去推包。
- 权限最小化:研发能推自己项目的制品,测试能拉取和浏览,运维能配置清理策略和复制规则,能删除产物的角色尽量只给自动化系统。
这里特别提醒:机器人 token 不要写死在流水线脚本里。我见过好几次 token 泄露导致仓库被清空的例子,token 至少要走 CI 平台的 Secret 管存储,定时轮换。
6. 选型结论、迁移成本与最容易翻车的点
最后把结论收敛一下。不要追求"一个工具解决所有问题",先看清楚团队真实的制品流。
6.1 什么场景选谁
| 场景 | 推荐工具 | 原因 |
|---|---|---|
| 团队只有 Java / Node / Python 语言构建产物,不碰容器 | Nexus | 多格式支持、proxy/group 模型统一入口 |
| 团队以 Docker/K8s 为核心交付方式,镜像数量多 | Hadess(Harbor 类) | OCI 原生能力、不可变 tag、复制、扫描 |
| 语言包和镜像同时大量存在 | Nexus + Hadess 并行 | 各管一段,互不干扰 |
| 企业级多团队、多种技术栈、强制合规审计 | 建议评估 Artifactory 等商业化防线 | 权限矩阵、风险治理、制品防火墙更成熟 |
6.2 迁移时最容易翻车的三个点
第一,清理策略不能拍脑袋。我之前在 Nexus 上配过一次清理任务,规则写得过激进,直接把 90 天前的所有包扫掉了,导致几个旧版本无法回滚。正确做法是:保留至少最近 3 个版本或最近 90 天,并在正式清理前先跑一遍 dry-run,看它会删什么再放行。
第二,备份恢复不能只复制文件。Nexus 的备份不只是把存储目录拷贝走,Blob Store 和数据库元数据需要对齐,否则恢复时会发现组件列表数据不完整。Hadess 类仓库的备份也同样要关注数据库和存储的一致性。用容器方式部署时,数据卷和配置卷一定要分清。
第三,迁移期间不要搞"切换大法"。最稳的办法是两个仓库并行跑一个月,在 CI 里同时推送到新老仓库,等新仓库稳定运行后再把旧仓库切为只读,然后归档。直接切换的最大风险是:新仓库某个配置没对齐,整个团队卡在仓库权限上。
6.3 最后说句我的个人习惯
这些年经历过不少仓库选型,我自己总结出一个固定动作:在选型之前,先花半天把团队当前的依赖流完整画出来。比如 Java 的依赖从哪来、构建产物去哪、镜像在哪构建、部署从哪拉。画完这张图,大多数工具选择问题其实已经自己有了答案——因为你会非常清楚地看到,团队最缺的到底是"代理缓存",还是"镜像不可变",还是"多集群复制"。
如果让我给一句话建议:不要被"选哪个工具"这种问题困住,先搞清楚你的制品流长得像什么样。很多团队最终是 Nexus 和 Hadess 同时存在,两者配合得反而很顺。工具是为了让流水线更稳定,而不是反过来给团队多一套需要伺候的系统。