从裸 Registry 到 Harbor:私有镜像仓库搭建与运维实战
发布时间:2026/10/21 3:23:12 锦皓数字建站

去年团队从三台测试机扩到十几个节点的时候镜像分发彻底乱套了。有人把镜像导出成 tar 包靠网盘转有人直接把镜像 tag 改成别的环境的名字再推直到有人误覆盖了一个生产镜像我才下定决心把私有镜像仓库这件事正经做完。当时对比了一圈方案最后选了 Harbor一直用到现在。这篇就把我从零搭建 Harbor 的完整过程、选型依据、配置细节和后来踩过的坑一次性写清楚。Harbor 是什么一句话能说清楚它是一个基于 Docker Registry 的企业级镜像仓库服务核心解决的不是存镜像而是镜像的权限管理、安全扫描、复制同步、审计日志这些团队协作里真正麻烦的事情。如果你只是自己在笔记本上跑两个容器那 Docker Hub 或者裸跑一个 Registry 都够用但只要是多人协作、多环境部署、有私有化交付需求直接上 Harbor 基本是唯一少走弯路的选择。1. 为什么我不建议裸跑 Registry几个真实痛点的对比很多人刚开始想省事直接docker run -d -p 5000:5000 registry就把仓库起了。我自己在正式搭 Harbor 之前也这么干过那段时间的痛苦体验让我现在还会劝别人如果团队超过三个人用同一个仓库裸 Registry 就是给自己埋雷。1.1 最要命的权限问题裸 Registry 没有用户概念谁能 push 全靠 Docker daemon 的访问控制要么全开要么全关。我当时的做法是映射端口后放在内网说服自己内网是安全的结果某次一台测试机被扫到 5000 端口被人塞了一堆奇怪的镜像还删掉了好几个正在用的 tag。从那次之后我就明白仓库这种基础设施访问控制必须做到项目级别。Harbor 在这块是天然的优势用户体系独立于操作系统有管理员、开发、访客多种角色每个项目可以单独设置公开或私有还能精确控制某个人对某个项目的 push / pull 权限。你不需要教团队什么复杂的 RBAC 概念在 Web 界面里点几下就能完成授权。1.2 镜像多了之后Registry 的无法搜索很难受裸 Registry 提供了 HTTP API但默认没有像样的人机交互界面。你要查某个服务的镜像有哪些 tag得curl调 API 或者干脆docker pull试错。Harbor 自带一个挺完整的 Web UI项目列表、镜像列表、tag 详情、镜像大小、push 历史一应俱全。排查问题的时候比如这个镜像到底是不是最新的登录 Web 界面一眼就能看到省太多事。1.3 还有个容易被忽略的垃圾回收镜像多了之后裸 Registry 那套registry:2会有一堆未标记的层占磁盘。裸 Registry 虽然支持/v2/_cancatalog那套 API但没有专门的 GC 机制。Harbor 在 Registry 之上做了一个中文界面的 GC 功能可以标记要清理的仓库、模拟运行查看要释放的空间再真正执行。这个我后面专门讲是生产环境很重要的一个按钮。可以看这么一张对比表方便你决定自己到底要不要上 Harbor能力项裸 RegistryHarbor镜像存储支持支持用户与权限不支持项目级 RBAC图形界面无完整 Web UI镜像复制需另配工具内置复制规则垃圾回收需手工 API可视化 GC审计日志无有操作记录安全扫描无支持漏洞扫描我见过太多的团队一开始图省事用裸 Registry最后因为权限和排查问题耗时过长又痛苦地迁到 Harbor。迁移本身不麻烦麻烦的是过程中容易丢 tag。所以如果你还在选型阶段听我一句劝直接上 Harbor省下一个月后的迁移成本。2. 部署前准备版本选型、资源规划与域名证书Harbor 部署方式有好几种最推荐的是离线安装包因为在线安装依赖网络情况而且离线包把需要的镜像全部打包好了安装过程中几乎不用外网。你只需要准备一台装了 Docker 的服务器再按下面的规划把目录和证书想清楚就行。2.1 版本怎么选Harbor 的版本节奏挺规律的推荐选偶数版本或者是稳定发布一段时间的版本。以 Harbor 2.x 为例2.6、2.8、2.9 这些长期稳定版本都没有硬伤新特性也不会在短时间内大改。不要追新版本尤其是刚发布的 .0 版本我见过有人在 2.0 刚出的时候直接上结果 Helm Chart 卷版本不兼容折腾了一整天。选版本的时候还要注意配套的 Docker 和 Docker Compose 版本。Harbor 的 install.sh 脚本默认调用 docker-compose 命令新版本已经逐步迁移到docker compose插件式命令但生产环境建议用 docker-compose 2.x 独立版兼容性最稳。2.2 服务器资源的最低下限Harbor 本身不算重但别把它想得太轻。部署后它要同时跑 Postgres、Redis、Registry、Core 服务、Portal 服务、JobService还有可选的 Trivy 漏洞扫描组件整套起来内存占用在 2GB 左右如果开了扫描还要更多。我的建议是最低配置2 核 CPU4GB 内存100GB 可用磁盘推荐配置4 核 CPU8GB 内存磁盘按镜像增长速度预留200GB 起磁盘那块要格外注意镜像仓库比代码仓库更吃空间因为一个镜像动不动就是几百 MB 到几个 GB而且每层都是持久化的。我当时顺手用df -h检查时发现数据目录所在的盘又快满了这才意识到要提前做空间规划。2.3 域名和 HTTPS 证书这一步千万别跳很多人第一次搭 Harbor 直接 IP 访问还用 HTTP图省事。但 Docker 客户端默认对非 localhost 的 HTTP 仓库极其不友好你需要给每个 Docker 节点配置 insecure-registries 才能绕过去。在测试环境可以接受生产环境我强烈不建议这么做因为镜像传输过程中是明文任何能抓包的人都能拿到你所有的镜像内容相当于把核心资产裸奔在内网。正确做法是准备一个域名比如harbor.internal.example.com然后给这个域名签证书。分两种情况内网环境自己用 OpenSSL 签自签证书然后把 CA 证书分发到所有需要访问的 Docker 节点有公网域名直接上 Lets Encrypt申请和续期都简单。自签证书这条我下面会给出具体命令。提前说一句ip直连方式虽然能在 harbor.yml 里配置不启用 HTTPS但团队大了之后谁也说不清哪个节点少了 insecure-registries 配置为了不给自己添麻烦一开始就把证书搞定。在这里顺便澄清一个误区Harbor 页面打开如果不安全很多人的第一反应是算了不管了但这会直接影响 Docker 客户端登录。你通过在节点上装 CA 证书能同时解决 Web 端和 Docker 客户端的信任问题一举两得。3. 一步一步搭起来docker-compose 部署 Harbor 全流程部署过程本身不复杂核心是把harbor.yml改对然后跑一遍install.sh。但有几个细节容易在改了配置之后翻车我把完整流程和踩坑点拆开讲。3.1 下载与解压先到 Harbor 官方的 GitHub Release 页面下载离线安装包注意文件名里有offline字样一般长这样$ wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-offline-installer-v2.9.0.tgz $ tar -zxvf harbor-offline-installer-v2.9.0.tgz $ cd harbor解压后目录里最重要的就是harbor.yml.tmpl模板文件和一个install.sh脚本。先把模板文件复制成harbor.yml$ cp harbor.yml.tmpl harbor.yml这里有个新手容易犯的错直接改模板文件等到后续升级或者重新安装时发现模板被污染了又得重新下载。养成复制一份改的习惯后面维护干净很多。3.2 harbor.yml 的关键配置项用编辑器打开harbor.yml重点关注这几块hostname: harbor.internal.example.com http: port: 80 https: port: 443 certificate: /data/certs/harbor.internal.example.com.crt private_key: /data/certs/harbor.internal.example.com.key harbor_admin_password: YourStrongPassword database: password: root123 data_volume: /data/harbor逐项解释一下hostname必须是你规划的域名不能写 IP除非你真的想只用 IP 访问但我不建议http.port默认 80如果服务器上已经占用 80 端口改成 8080 之类的同时要保证后续访问方式顺手https.certificate和private_key指向证书文件路径提前把证书放到指定位置harbor_admin_password这是初始管理员 admin 的密码如果留空或太简单安装完成之后登录 Web UI 时还要回头改麻烦database.passwordHarbor 内置 Postgres 的 root 密码最好也改成强密码data_volume所有镜像和数据库数据的存放目录一定要放到大分区。我见过有人把data_volume放在根目录/data/harbor结果根分区才 50GB镜像一多整个服务器直接报警。这个路径务必规划好最好用单独的挂载盘比如/mnt/harbor-data。3.3 生成自签证书如果走 HTTPS 且没有机构签发的证书用 OpenSSL 生成自签证书。注意必须包含subjectAltName否则现在新版 Docker 和浏览器都会报域名不匹配。$ mkdir -p /data/certs cd /data/certs $ openssl req -newkey rsa:4096 -nodes -sha256 -keyout harbor.internal.example.com.key \ -x509 -days 3650 -out harbor.internal.example.com.crt \ -subj /CNharbor.internal.example.com \ -addext subjectAltName DNS:harbor.internal.example.com,IP:192.168.1.100证书有效期我给了 3650 天内网自签证书这个时长合理省得频繁换。然后还需要一个 CA 证书文件ca.crt其实就是把刚生成的 crt 复制一份改名即可$ cp harbor.internal.example.com.crt ca.crt这个ca.crt后面要分发给所有 Docker 节点。3.4 执行安装配置没问题就可以执行安装了$ sudo ./install.shinstall.sh 会自动检测 docker 和 docker-compose 版本、加载离线镜像、生成 docker-compose.yml、启动所有容器。整个过程大概几分钟日志里看到Harbor has been installed and started successfully就完成了。验证是否正常用$ docker ps | grep harbor $ curl -I https://harbor.internal.example.com前者能看到十几个相关容器在跑后者返回 HTTP 200 就说明页面已经起来了。这里说一个我首次安装时遇到的情况服务器上本来装了别的服务占了 443 端口结果安装完成之后 Harbor 页面一直打不开排查了半天我才意识到是端口冲突。所以端口占用这一类基础检查真的要在安装前做掉别嫌麻烦。3.5 让 Docker 客户端信任仓库这一步目标很简单让这台机器和其他所有要拉取镜像的机器都能docker login成功。内网自签证书模式下推荐把ca.crt复制到/etc/docker/certs.d/harbor.internal.example.com/目录并改名为ca.crt。Docker 会依据这个目录里的证书自动信任对应域名的仓库。$ mkdir -p /etc/docker/certs.d/harbor.internal.example.com $ cp /data/certs/ca.crt /etc/docker/certs.d/harbor.internal.example.com/ca.crt $ systemctl restart docker之后用管理员账号测试登录$ docker login harbor.internal.example.com Username: admin Password: Login Succeeded登录成功后就可以打 tag 推送了$ docker tag nginx:latest harbor.internal.example.com/library/nginx:v1 $ docker push harbor.internal.example.com/library/nginx:v1看到 push 完成Harbor 的 Web 界面里刷新项目library镜像就会出现。完成了这一步整个基础链路算是通了。4. 安全加固与日常使用配置认证、项目权限、Robots 账户基础通了之后大部分人就停下来了但生产环境不是能访问就算完。这一节讲我在实际使用中觉得最值得做的几项加固尤其适合多团队共用一个仓库的场景。4.1 项目权限模型别什么镜像都往 library 塞Harbor 默认有一个叫library的公开项目一开始所有人都可以往里面推。如果你们是多个小组共用很快就乱成一锅粥服务 A 的镜像和小组的镜像混在一起tag 还可能被覆盖。强烈建议每个业务线建一个独立项目并且设置私有模式。比如项目名模式说明base-images私有公共基础镜像仅 Ops 可写service-a私有A 服务镜像service-b私有B 服务镜像public-cache公开只读公开镜像便于各节点拉取在 Web 界面创建项目之后在成员标签页里给对应的人分配角色。角色分为项目管理员、开发人员、访客等开发人员有 push 权限访客只能 pull。这样哪怕某个人误操作影响面也能限制在一个项目内部。4.2 Robots 账户给 CI/CD 机器人用的专用凭证Harbor 2.x 引入了一个特别贴心的功能叫 Robots 账户。它在用户体系之外单独创建专门给 CI/CD 流水线使用。这样你不需要在 Jenkins 或者 GitLab CI 里存管理员密码也不怕某个人的账号离职之后导致流水线不可用。创建路径在 Web UI 里系统管理 - Robot Accounts新建账号时填名字、过期时间并勾选权限。我通常给每个项目建一个只具备该项目 push 权限的最小化机器人账户GitLab CI 里用它登录再推送镜像安全性和可追溯性都很好。# GitLab CI 部分示例 push: stage: deploy script: - docker login harbor.internal.example.com -u robot$service-a -p xxx - docker push harbor.internal.example.com/service-a:latest设置成项目级别的最小权限后即使机器人账号泄露攻击者最多祸害一个项目比裸管理员的杀伤力小得多。4.3 强制 HTTPS 与禁用 HTTP 明文流量在harbor.yml里同时配置了 HTTP 80 和 HTTPS 443 时Harbor 允许两种协议并存。生产环境建议你在系统配置里把仅允许 HTTPS打开具体在 Web 界面系统设置里勾选。这样即使有人想用 http:// 访问也会被重定向或拒绝少一个明文传输的隐患。另外如果你用的网络环境里有多层代理要注意 Harbor 处理的是来自客户端直连的流量如果你在前面挂了 Nginx要记得把X-Forwarded-Proto头正确传给 Harbor否则强制 HTTPS 策略会让部分客户端请求莫名卡住。4.4 审计日志与操作追踪Harbor 默认开启了日志功能在系统管理 - 日志里可以查看用户登录记录和操作。我做过的几次重大误删事故复盘都是靠这个日志找到是哪个账号在什么时间删了什么 tag。定期把日志导出归档一次成本极低但关键时刻能救命。5. 镜像复制和垃圾回收生产环境真正离不开的两个功能镜像复制和 GC 是 Harbor 相对裸 Registry 最明显的生产力提升。很多人搭好 Harbor 之后只用了 push/pull等于买了个旗舰手机只用了打电话功能太可惜了。5.1 跨机房镜像复制规则怎么设计镜像复制解决的是多机房或容灾环境下的镜像分发问题。最典型的需求是总部一套 Harbor分机房一套 Harbor主环境推送的镜像要自动同步到分机房。具体做法是在分机房的 Harbor 里配置复制规则选择基于拉取的模式。源就是总部的 Harbor 地址目标选择本地仓库触发器设为事件驱动即总部出现新镜像时自动拉取过来。规则配置项参考 - 名称: sync-from-main-site - 复制模式: 拉取 (Pull) - 源仓库: https://harbor-master.internal.example.com - 过滤器: 项目 service-a, 名称匹配 /.*/ - 触发模式: 事件驱动注意几个易错点拉取模式与推送模式方向要搞清楚。分机房拉总部是拉取模式总部主动往分机房推是推送模式。跨机房网络带宽不够时复制会很慢建议按项目拆成多条规则而不是一条规则全量同步。复制规则执行失败后 Harbor 会自动重试但要注意看 JobService 日志如果远程仓库凭证过期会一直失败。我实际遇到过复制规则全配好了但总部远程仓库的密码过期导致新镜像同步不过去而分机房的镜像还是旧的部署到那边直接出问题。后来养成了习惯每次改了远程仓库密码第一件事就是去复制规则页面手动执行一次确认同步成功。5.2 垃圾回收的正确打开方式镜像每推一次Registry 会保留旧层的引用但当某个 tag 被删除或覆盖后对应的一些层就会变成孤儿层不占引用但占磁盘。所谓垃圾回收就是把这些孤儿层删掉。Harbor 的 GC 功能在系统管理 - 垃圾回收操作前有个非常关键的建议先在配置里勾选跳过当前正在被拉取的镜像避免 GC 过程中删到正在使用的层。真正执行的时候建议在业务低峰期进行因为 GC 过程中 Registry 的读写会受影响。我个人的执行节奏 1. 先勾选 在进行垃圾回收前停止仓库服务 2. 在 GC 页面点击 立即执行垃圾回收 3. 执行完成后检查磁盘释放情况 4. 全团队发通知接下来推送新镜像需要重试一两次至于 GC 周期一个月跑一次就够除非你们团队删镜像特别频繁。我见过有人天天跑 GC结果某天有容器还在拉镜像就触发 GC导致部分镜像层短暂不可用虽然影响不持久但也惊出冷汗。5.3 镜像保留策略防止磁盘被暴涨的 tag 填满生产环境经常有人给每次构建都打latest一段时间后同一个项目下 tag 数几百个磁盘暴涨。Harbor 支持保留规则通过正则筛选镜像和时间自动清理超期 tag。比如可以给service-a项目建一条规则保留最近 7 天以内、或者标签匹配release-*的镜像其余清理。这样既保持历史可回溯又不会无限膨胀。6. 运维排坑实录这些年我踩过的 Harbor 坑说实话Harbor 稳定性在同类开源项目里算很能打的但长期跑下来总会遇到一些零碎问题。我把印象最深的几个记录下来帮你提前避雷。6.1 磁盘占满后整个 Harbor 直接挂掉这是我第一次被 Harbor吓到的故障数据盘满了之后Registry 的写入直接失败但 Harbor 的 Core 容器还活着只有docker push一直报错。我以为是 Harbor 的配置坏了排查半天才发现是磁盘 100% 占用。排查链路先df -h确认数据盘是否写满如果写满找出大文件目录常用du -sh /data/harbor/* | sort -rh优先清理 /data/harbor 下的临时文件再考虑 GC清理出来空间后重启 harbor 容器组把磁盘监控加好尤其是数据盘比任何配置优化都重要。6.2 自签证书更新后客户端还是报 x509 错误换过证书之后明明所有客户端ca.crt都更新了还是会报x509: certificate signed by unknown authority。排查到最后发现有一台机器上的 Docker 没重启daemon 还在用旧证书缓存。正确做法是更新 ca.crt 后一定执行systemctl restart docker并且把 Docker 客户端缓存也清掉$ docker logout harbor.internal.example.com $ systemctl restart docker $ docker login harbor.internal.example.com这个顺序问题很多人会漏掉logout这一步导致新的登录请求被 daemon 缓存住了。6.3 Harbor 升级时不要直接覆盖数据目录Harbor 升级基本靠着重新下载安装包、修改harbor.yml、跑./install.sh听起来简单但有个致命细节新版本的数据库结构可能变化如果直接覆盖旧数据目录很可能导致 migration 失败。常规升级路径是备份整个/data/harbor目录和数据库下载新版本离线包用旧的harbor.yml作为基础对比新版本的配置项做调整执行./install.shHarbor 会自动跑 migration 脚本如果 migration 失败建议先看/var/log/harbor的日志大部分情况是权限问题或数据库存储空间不足。注意升级前一定要备份我第一次升级 2.0.0 的时候没备份migration 过程中磁盘不够直接卡住最后回滚差点丢数据吓出一身汗。6.4 慢的不是 Harbor是你的网络或 DNS有时候docker pull有时从 Harbor 拉镜像特别慢第一反应都是仓库出问题了。实际上很多情况是 Docker 客户端的 DNS 解析太慢尤其是用了内网域名但 /etc/resolv.conf 配置了公网 DNS域名解析绕了一大圈。解决方式是把仓库域名直接写进/etc/hosts192.168.1.100 harbor.internal.example.com如果用了 Nginx 反代还要注意client_max_body_size设置。镜像一个 layer 可能是几百 MBNginx 默认 1MB 限制会直接把 push 截断。我第一次给 Harbor 套 Nginx 反代时就碰到这个问题在配置里加上client_max_body_size 0;意思是限制大小不设上限。6.5 定时备份Harbor 的配置与数据库比想象中更重要Harbor 绝大多数配置都存在数据库里项目、用户权限、复制规则、保留规则全在 Postgres 中。如果服务器宕机或数据盘损坏恢复成本不低。我的建议是定期备份两个东西data_volume下的database目录以及harbor.yml。可以用简单的 cron 脚本定期打包/data/harbor/database或者更推荐用 Harbor 自带的 API 配置备份功能。不过我自己更习惯对 data_volume 做基于文件的 rsync 到另一台存储机器配合数据库逻辑备份恢复起来最快。# 简单的每日备份示例 tar -czf /backup/harbor-db-$(date %F).tar.gz /data/harbor/database根据我个人的经验Harbor 配置和数据备份策略值得在搭建完成后立刻写进运维手册别等真出了事故再补。最后再分享一个自己在日常运维中的小习惯每次改完harbor.yml或者换证书我都习惯先执行一次docker-compose down -v再重新install.sh。这里注意-v会删掉容器但不会删数据卷对应的宿主机目录只要data_volume里的数据还在Harbor 重启后所有项目和镜像都还在。当然这个操作依然要谨慎尤其是生产环境一定要先确认data_volume路径没有配错。Harbor 这套东西本质上不复杂但作为团队镜像流转的核心每一步配置都值得认真对待。这个项目后续还可以继续扩展比如接入 OIDC 统一登录、配置镜像签名、对接外部对象存储来扩大容量。先把基础打好后面的路自然顺。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。