ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Harbor私有镜像仓库搭建实战:避坑指南与运维技巧

Harbor私有镜像仓库搭建实战:避坑指南与运维技巧

做运维或者开发的同学,多多少少都会碰到镜像管理的窘境:本地机器上堆了一堆docker images,来回拷 tar 包传到内网,环境一多就彻底乱了;又或者生产环境需要部署一套服务,但容器镜像存放在公共仓库总让人不太放心,万一哪天拉不下来或者被限速,整个发布流程就卡住了。我自己前前后后搭过好几次镜像仓库,从裸的 Registry 到带 Web UI 的 Harbor 都用过,最终稳定在团队内部长期跑的还是 Harbor。这篇文章就结合实际部署过程,把“搭建 Harbor 私有镜像仓库”这件事从头到尾讲透,包括环境准备、安装步骤、证书配置、日常使用技巧和踩坑记录,适合正在选型或准备落地私有镜像仓库的运维、开发和项目负责人参考。

1. 项目概述与核心价值

1.1 为什么要自建私有镜像仓库

Docker 镜像本质上是分层的文件集合,平时用公共镜像仓库拉取非常方便,但真正进到生产或者企业内网环境,问题就暴露出来了。一层是网络隔离,很多机房内部根本没有连通外网,就算能连,几百兆甚至几个 G 的镜像在公网上传输也极不稳定;另一层是安全和合规,公司内部的业务镜像可能包含代码、模型、配置文件等敏感信息,放在公共仓库无论如何都会有心理障碍。自建私有镜像仓库就是为了解决这些问题:把镜像保存在自己的基础设施里,传输走内网或者专线,速度可控、权限可控、审计也可控。

镜像仓库的核心角色相当于“镜像的版本管理 + 分发中心”。不光要能存,还要能对镜像做 tag 管理、访问控制、生命周期清理。裸的registry:2容器只能满足最基本的 push/pull,连个可视化的界面都没有,权限控制更是靠反向代理硬搓。Harbor 正是在这个基础上做了一层完整的产品化封装,目前它已经把镜像存储、Web 管理界面、用户体系和项目隔离这些能力集成得很好,这也是我最终选择它的理由。

1.2 Harbor 与其他镜像仓库方案的对比

先聊一下候选方案,这样大家在选型时心里有数。Docker 官方提供的registry镜像是最轻量的选择,部署简单,但功能极少,适合临时用或者只用命令行操作。Portus是很多年前 SUSE 推出的一个可视化镜像仓库,界面比较古老,社区活跃度也不够理想。近几年国内常用的还有Nexus,它是一个通用制品仓库,既能存 Maven、npm,也能存 Docker 镜像,功能很强大,但配置和资源占用都偏重,单独的镜像仓库场景反而显得杀鸡用牛刀。

Harbor 的优势在于专注、开源、功能全。它由项目最初由某公司开源后捐赠给云原生计算基金会(CNCF)孵化,社区活跃度高,更新迭代稳定。它原生支持多租户项目隔离、基于角色的访问控制、镜像复制、漏洞扫描、垃圾回收、审计日志等功能,部署方式包含在线安装和离线安装。对国内团队来说,离线安装包非常友好,因为可以在有网环境预先下载好所有资源,然后带到内网安装,不用从公网拉取海量镜像。

1.3 本次搭建的目标与适用场景

我这里要做的是一套可以支撑几十人研发团队日常使用的 Harbor 私有镜像仓库,部署目标是:内网访问,使用 HTTPS 单向认证,支持多个项目分组,每个项目有独立账号权限,镜像能正常推送拉取,并且配置了基础的磁盘清理策略。场景覆盖日常开发测试环境的镜像发布、测试服务器拉取镜像部署,以及后续需要对接持续集成流水线(CI/CD)。

这套方案的核心技术栈是Docker + Docker Compose + Harbor。Harbor 官方安装包内部封装了多个组件,包括Harbor Core(核心 API)、Registry(镜像存储)、Nginx(反向代理)、PostgreSQL(数据库)、Redis(缓存)等。其实不需要手动一个个部署,使用官方提供的 installer 脚本就能一键完成,但前提是 Docker Compose 环境要准备好。

2. 环境准备与部署方案设计

2.1 基础环境要求

Harbor 对服务器配置要求并不高,最主要的瓶颈是磁盘 IO 和容量。镜像仓库本质上是存储服务,读多写多,建议至少 4 核 CPU、8GB 内存,如果是几十人团队的日常使用,这个配置绰绰有余。磁盘方面,操作系统盘和数据盘建议分开,数据盘走独立挂载,容量根据镜像增速预留。这里有一点很重要,Harbor 的镜像实际存储目录默认是在/data下,如果系统盘不够大,必须提前挂载大容量数据盘,否则运行几个月就等着磁盘告警吧。

操作系统我建议用 Ubuntu 22.04 LTS 或 CentOS 7.9,如果你的环境用的还是 EulerOS、Kylin 这些国产发行版,只要能正常安装 Docker 和 Compose 就可以,Harbor 本身跑在容器里,对宿主机系统不是特别挑剔。需要注意内核版本不能太低,否则 Docker 的存储驱动和网络模式会出各种奇怪问题。

2.2 安装方式选型

Harbor 的部署方式主要分两类:在线安装和离线安装。在线安装需要服务器能访问外网,执行 installer 时会从 Docker Hub 拉取相关镜像包,包括goharbor/harbor-core、goharbor/registry、goharbor/nginx-photon等等。这种方法省去下载安装包的步骤,但依赖网络,且下载速度不稳定。

离线安装则更稳妥。去官方 Release 页面下载名为harbor-offline-installer-v2.x.x.tgz的压缩包,里面既包含安装脚本,也包含所有 Docker 镜像的 tar 包。安装时脚本会把这些 tar 包导入到本地 Docker 环境,整个过程完全不需要外网。我强烈推荐离线安装,不只是因为内网环境用得上,就算在有网环境,离线包也能避免重复拉取带来的时间浪费,而且版本锁定,可复现性更好。

2.3 域名与证书规划

Harbor 默认支持通过 IP 地址访问,但在生产环境使用 IP 访问会有很多不便,比如 Docker 客户端登录时,如果 registry 地址是 IP,镜像 tag 名称就会变成192.168.x.x:443/project/image。如果使用域名,比如harbor.example.local,看起来更清晰,且后续如果迁移服务器,只用改 DNS 解析,镜像 tag 无需变动。

因此建议提前规划一个内网域名。证书方面,我建议使用自签 CA 证书,因为内网环境不太可能申请到公网证书,自签证书需要注意把所有客户端机器的 CA 证书都信任一遍。还有一种方式是在安装 Harbor 时直接配置 HTTP,但是 Docker 对 HTTP 仓库默认是拒绝的,需要在每个客户端配置 insecure-registries,非常繁琐且不安全。所以无论多麻烦,我还是推荐走 HTTPS。

3. 实操:从零搭建 Harbor

3.1 安装 Docker 与 Docker Compose

这一步是基础。先更新系统,然后添加 Docker 官方软件源,安装docker-ce、docker-ce-cli、containerd.io和docker-compose-plugin。以 Ubuntu 为例,安装完成之后不要忘了启用 Docker 服务:

systemctl enable --now docker docker version docker compose version

为什么要用docker compose而不是老旧的docker-compose?新版 Compose 作为 Docker 的插件集成,版本更新更及时,命令格式也更统一。Harbor 的安装脚本本身会调用docker-compose命令,所以需要确认该命令是否存在,版本不要太低。我个人通常做一个软链接兼容:

ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

这个细节很关键,如果不做兼容处理,Harbor 安装脚本可能会报“command not found”。另外,宿主机的时间同步也要检查,镜像仓库涉及日志审计和复制调度,时间漂移会导致很多难以排查的问题。

3.2 下载并配置 Harbor

到 Harbor 的官方 GitHub Release 页面下载离线安装包,这一步建议在有网的开发机上完成,然后再传到目标服务器。比如我下载的是harbor-offline-installer-v2.10.0.tgz,解压后目录结构如下:

tar -zxvf harbor-offline-installer-v2.10.0.tgz cd harbor

目录里最重要的文件是harbor.yml.tmpl,这是配置模板。我们需要把它复制一份成harbor.yml,然后修改关键参数。在一次真实部署中,我把核心配置简化成下面这个样:

hostname: harbor.example.local http: port: 80 https: port: 443 certificate: /data/cert/harbor.example.local.crt private_key: /data/cert/harbor.example.local.key harbor_admin_password: YourStrongAdminPassword123 database: password: YourDBPassword456 data_volume: /data/harbor log: level: info local: rotate_count: 10 rotate_size: 100M

需要注意的坑有哪些?hostname一旦确定,尽量不要再改,因为后续 Docker 客户端的镜像 tag 会绑定这个字段。harbor_admin_password是初始化时管理员的密码,长度和复杂度一定要满足要求,否则登录会出问题。database.password是 Harbor 内部数据库的密码,这个也是只在初始化时生效。data_volume建议专门挂载大容量磁盘,和系统盘分开。

3.3 生成 HTTPS 证书并启用

这里直接生成自签 CA,然后签发 Harbor 服务器证书。大概分三步:创建 CA 私钥和根证书,创建 Harbor 服务器私钥并生成签名请求,最后用 CA 签名并生成最终证书。为方便演示,在这里用明文命令说明关键步骤。

第一步:生成 CA 私钥和根证书。

mkdir -p /data/cert && cd /data/cert openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj "/CN=Harbor-CA" -out ca.crt

第二步:生成服务器私钥和证书签名请求。

openssl genrsa -out harbor.key 2048 openssl req -new -key harbor.key -out harbor.csr -subj "/CN=harbor.example.local"

第三步:新建一个扩展文件,写上 SAN(Subject Alternative Name),IP 地址和域名都要加上,否则 Docker 校验证书时会发现证书不匹配。

cat > ext.cnf <<EOF subjectAltName=DNS:harbor.example.local,IP:192.168.1.100 EOF openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out harbor.crt -days 3650 -sha256 -extfile ext.cnf

在执行官方安装脚本之前,需要把harbor.yml里的https.certificate和https.private_key路径指向刚才生成的harbor.crt和harbor.key。这一步如果不做,安装时如果路径无效,脚本会直接报错退出。

3.4 部署 Harbor 并验证

接下来执行安装脚本:

sudo ./install.sh

这个脚本会导入镜像包、生成 docker-compose 配置并启动所有服务。正常情况下,等待几分钟后,使用docker compose ps可以看到容器状态全部是 healthy。我通常再确认一下监听端口:

ss -tlnp | grep -E '80|443'

看到 80 和 443 都在监听,说明 Nginx 反代已经起来了。浏览器访问https://harbor.example.local,如果之前没有信任 CA 证书,浏览器会提示不安全,这个属于正常现象,选择高级继续访问即可,但要注意后续每台客户端都需要把证书放到系统信任链里,Docker 才会信任。

首次登录使用admin+ 初始化密码,进入系统后第一件事是修改管理员密码,然后开始配置项目。这里建议管理员账号不要给所有开发人员使用,而是创建独立账号,按需分配项目权限,这样审计日志才有意义。

4. 核心功能配置与使用技巧

4.1 Harbor Web 界面与项目管理

登录 Harbor 后,左侧菜单能看到“项目、镜像仓库、日志、垃圾回收、配置管理”等核心模块。项目就是一个命名空间,Docker 镜像的 tag 前缀就是项目名,例如harbor.example.local/demo/my-app:v1.0,其中demo就是项目名。创建项目时可以勾选访问级别为“公开”或“私有”,公开项目允许所有用户匿名拉取(如果仓库整体是私有网络的话),私有项目需要授权。

我强烈建议默认创建私有项目,然后针对项目添加成员并分配角色。角色分为仓库管理员、开发者、访客等。开发者可以推送和拉取镜像,访客只能拉取镜像。这样开发人员只拥有自己所在项目的写权限,不会干扰其他项目。给团队成员授权的时候还有个细节:Harbor 支持有项目管理员创建账号并绑定角色,不同项目可以互相隔离。实际使用中,我们通常一个业务线建一个项目,成员单独拉进各自的组,这样权限清晰,镜像也容易找。

4.2 配置 Docker 客户端登录与推送

客户端要登录 Harbor,必须先把 Harbor 的 CA 证书加到系统信任链。以 Ubuntu 客户端为例:

sudo cp /data/cert/ca.crt /usr/local/share/ca-certificates/harbor-ca.crt sudo update-ca-certificates

然后 Docker 登录:

docker login harbor.example.local

输入账号密码,提示Login Succeeded就代表连接成功。接下来给本地镜像打标签并推送:

docker tag nginx:latest harbor.example.local/demo/nginx:v1.0 docker push harbor.example.local/demo/nginx:v1.0

这里有两个常见问题。第一个是如果不信任 CA,登录时会报certificate signed by unknown authority,解决方法就是刚才那两步,或者把证书放到/etc/docker/certs.d/harbor.example.local/下,Docker 会优先使用该目录下的证书。第二个是如果是 HTTP 方式访问,Docker 会直接拒绝,必须修改/etc/docker/daemon.json里的insecure-registries,但这种方式不建议,自签 HTTPS 才更安全。

另外,推送时如果没有给镜像打上 Harbor 的地址前缀和项目名称,会报错denied: requested access to the resource is denied。需要先打标签再推送,这个新手最容易踩。

4.3 镜像复制与垃圾回收

镜像复制功能我觉得是 Harbor 的一大杀手锏。它的使用场景是:开发环境在 A 地区,生产环境在 B 地区,两个环境之间网络隔离,但需要把验证通过的镜像同步到生产镜像仓库。Harbor 内置了复制管理,只需要配置一个复制规则,源仓库和目标仓库都关联好,一旦源镜像 tag 更新,就会自动或手动同步过去。我们实际用它实现了“开发仓库 → UAT 仓库 → 生产仓库”的多级同步链路,非常省力。

配置复制规则时需要注意:目标仓库的地址、账号要有写权限,复制模式可以选择 Push-based(由源仓库主动推送到目标)或 Pull-based(目标仓库主动拉取源镜像)。网络不通的情况下,可以选择定期拉取模式,甚至让目标仓库在空闲时段去拉取,避免高峰带宽占用。复制完成后一定要回去看任务状态,有一个“呈现最近作业”的列表,每次成功失败清清楚楚。

垃圾回收是另一个必须养成的习惯。镜像仓库在删除 tag 或者镜像后,底层的层数据并不会立即删除,实际上磁盘空间还是一直被占用。Harbor 的垃圾回收功能可以清理这些无用的层数据,但需要注意:垃圾回收期间建议停止推送操作,否则可能造成部分镜像的层数据引用不一致。实操时我们通常安排在凌晨触发,并在 Web 界面上勾选“不进行清单”,减少风险。

4.4 用户权限与安全策略

安全策略的落地,我从三个层面说。第一是账户管理,Harbor 默认使用本地数据库用户体系,但同时也支持接入 LDAP 和 OIDC。我们有部分团队接入了 LDAP,好处是人员入职离职自动同步权限,不用手工创建账号。第二是认证策略,Harbor 的 Web 界面支持强制让用户定期修改密码,登录失败次数多了还会锁定账户,这些在“配置管理”里可以调整。第三是操作审计,每个推送、删除、复制操作都会记录在“日志”模块中,出现问题可以直接按时间检索,定位到具体操作人。

还有一个平时很容易忽略的安全点:Harbor 自带的漏洞扫描功能支持对镜像层进行 CVE 扫描,扫描器默认从公共 CVE 库拉取数据,在内网环境可能需要提前配置漏洞数据库离线包。虽然不能完全替代专业的镜像安全扫描工具,但有总比没有强,至少能排查出基础系统镜像的已知漏洞,我们把它用在 CI 流水线的前置检查,有一定效果。

5. 常见问题与排查实录

5.1 登录报错与 HTTP/HTTPS 配置问题

最常见的错误就是 Docker 登录时报Error response from daemon: Get "https://harbor.example.local/v2/": x509: certificate signed by unknown authority。这个问题的根源是客户端没有信任 Harbor 的 CA。解决办法按照前面说的,把ca.crt复制到系统信任链,或者放到/etc/docker/certs.d/harbor.example.local/目录下,重启 Docker 再登录即可。

如果你偏要用 HTTP,那就在/etc/docker/daemon.json中配置insecure-registries,但我不推荐。另外一个隐蔽问题:如果 Harbor 的hostname配置的是域名,但客户端无法解析该域名,登录也会超时或者报错。需要在每台客户端的/etc/hosts加入一条记录,或配合内网 DNS 打通,否则就算证书没问题也连不上。

5.2 磁盘空间不足与 GC 策略

镜像仓库跑久了,磁盘占用增长非常快。很多人发现docker images删了一大堆,但 Harbor 服务器上的磁盘依然爆满,原因就是没有执行垃圾回收。GC 的执行分两个步骤:先清除软删除的镜像标记,再清理存储目录。

在使用 GC 时必须掌握一个原则:不要在 GC 进行时推送镜像,否则可能被标记为“已软删除”的层被复用,出现镜像损坏。我的做法是配置一个定时任务脚本,在凌晨 2 点调用 Harbor API 触发 GC,并搭配 log rotate 控制日志大小。另外,对于数据盘要设置监控告警,这里我建议使用磁盘容量达到 70% 时告警,达到 85% 时必须启动紧急 GC 和镜像滚动清理,否则撑不了几个工作日。

脚本里面调用 API 时可以用管理员账号生成一个机器人账号,专门用于 GC 触发和状态查询,而不是把管理员密码放在脚本里,这个习惯可以降低账号泄露风险。

5.3 高并发与性能调优

团队规模扩大后,镜像仓库的并发拉取请求会明显增加。Harbor 的前置 Nginx 默认配置吞吐能力足够,瓶颈往往在于存储层和 Registry 的并发能力。早期我们用机械盘存储,多个任务同时推送镜像时,经常出现超时和 io 延迟飙升,后来换了 SSD 后明显改善。如果数据量过大,可以考虑把/data/harbor放到独立的快存储上,先跑一段时间观察 IO 指标再决定是否迁移。这里要提醒一点,如果以后镜像量特别大,建议搭配对象存储(比如兼容 S3 的存储)作为后端,但配置复杂度会上升。

性能调优的另一个层面是镜像分发加速。Harbor 本身支持在多个节点部署同一套实例,通过负载均衡对外提供服务,但数据库和缓存需要共享。如果不想搞那么复杂,可以通过 Harbor 的镜像复制功能,把常用镜像复制到每个机房的本地仓库,拉取请求直接命中本地,跨机房带宽占用问题也就少了。

5.4 升级与备份恢复

Harbor 版本升级其实不难,但必须按官方流程走。首先要备份数据库和存储目录,然后下载新版本离线包,运行./install.sh --upgrade脚本。在这里我吃过一次亏:直接从次新版本跳到更的版本跨度很大,数据库迁移脚本会执行很多步骤,一旦中间报错,整个服务就起不来了。所以一定要先在测试环境完整跑一遍升级,再操作生产环境,同时升级前快照或者完整备份。

备份恢复的实操经验是:数据卷/data/harbor和数据库要分开理解。Harbor 的元数据(用户、项目、复制规则等)存在 PostgreSQL 中,而镜像的二进制层数据存在数据卷里。如果只是备份了数据卷而没有备份数据库,恢复后镜像数据可能和元数据对不上;反过来如果只备份数据库而没有备份数据卷,恢复后镜像会全部丢失。完整的备份策略是:数据库用pg_dump导出,数据卷用 rsync 或者 tar 打包,再配合对象存储定期上传。

恢复的时候有一个小技巧:先安装一个全新的 Harbor 实例(版本尽量保持一致),然后用备份的数据库覆盖新实例的数据库,再同步数据卷,最后启动服务。整个过程不能跨大版本,否则数据库 schema 不兼容。某些场景下如果只是迁移服务器,建议直接在新服务器上用同样安装包重新安装,再把旧数据卷和数据库整体搬过去,这样的成功率反而更高。

6. 扩展思考:与 CI/CD 流程的集成

搭建好 Harbor 之后,第一个真正发挥威力的场景就是持续集成持续发布。我们的团队并没有把镜像仓库独立使用,而是把它作为流水线中的一环。具体流程是:代码提交触发构建任务,把生成的镜像打好 tag 推送到 Harbor 的开发项目;测试环境直接从 Harbor 拉取对应 tag 的镜像部署;验证通过后,通过复制规则同步到生产仓库,同时更新 Jenkins 或 GitLab CI 中的部署配置。

在使用 API 时,可以给流水线建立一个机器人账号,Harbor 中“机器人账户”是专门为自动化场景设计的,可以指定权限范围,比如只允许推送某个项目。它的好处是没有普通用户的密码生命周期限制,即使不可用也可以在 UI 中一键吊销,比把管理员密码硬编码到流水线安全得多。

写到这里发现其实还有很多细节可以继续展开,比如如何配置镜像自动清理策略来避免仓库无限膨胀、如何用 Webhook 在镜像推送完成后自动通知部署系统、如何基于 Harbor 的 OIDC 对接公司内部统一的身份认证。不过这些都是在完成基础搭建之后因地制宜的东西,先把基础环境跑稳再说。

最后说一点个人经验:Harbor 这个项目有一个特性,就是你没有踩过坑之前,会觉得它太简单了;真正用起来之后,才发现它的复制、GC、安全和升级机制都是在一个一个真实场景中磨出来的。搭建本身半天就能完成,但要想稳定服务团队一年甚至更久,一定要做好磁盘监控、备份策略和权限规划。这几点在平时不会刷存在感,可一旦出问题,就会让你觉得当初多花的时间非常值得。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进