Harbor私有镜像仓库离线安装与配置:从原生Registry到团队化治理 很多人第一次搞私有镜像仓库都觉得这事简单docker run -p 5000:5000 registry完事。可真到了团队里大伙儿一起用或者要往生产环境推问题就接踵而至——没有登录鉴权、没有用户管理、镜像说删就删、说不清谁在什么时候推了什么、连个可视化的界面都没有。这也是我当年从原生Registry迁移到Harbor的直接原因。Harbor是一个开源的云原生镜像仓库基于Docker环境运行自带Web控制台、基于角色的访问控制RBAC、镜像复制、漏洞扫描等能力部署方式对Docker环境非常友好。这篇文章不是产品手册而是把我从零开始下载离线包、改配置、跑安装脚本、接上Docker客户端、日常运维避坑的全过程记录下来。适合的对象包括要给团队内部搭建镜像仓库的运维工程师以及希望在自己服务器上搭一个私有仓库的独立开发者。1. 先搞清楚一件事Harbor到底比原生registry强在哪里1.1 原生registry的痛Docker官方那套registry镜像是所有私有仓库的基础但如果你只在局域网里跑一台很快就会发现几个挺难受的限制。第一没有真正的用户体系Harbor里每一个用户有单独的账号和密码而原生registry要么整体开放要么靠自己在nginx层拼一个非常简陋的基础认证谈不上角色和权限。第二没有Web界面想看仓库里有哪些镜像、哪些tag、大小是多少只能手动调用registry API或者装一堆第三方浏览器工具。第三没有什么审计能力谁在什么时间推了什么、拉了什么各凭本事出了问题想追溯基本靠猜。这些痛点在小规模、单机单人使用时勉强能忍一旦变成开发、测试、生产多条流水线共用一个仓库就会频繁出现“镜像被覆盖”“标签被乱删”“不知道自己该用哪个版本”这类问题管理成本会立刻上来。更麻烦的是新同事入职或者外部协作者要访问仓库时原生registry根本没有一套好用的账号开通和权限分配流程。这也是大部分团队最终切换到Harbor的原因——它就是在registry之上做了一层完整的业务层把仓库从一个存储工具变成了一个可治理的平台。1.2 Harbor给你的不只是“一个仓库”Harbor由很多组件构成但部署后被整体封装成一组Docker容器nginx负责统一的访问入口和TLS终结core处理API和UI请求registry就是镜像存储后端jobservice跑复制和清理任务portal是前端控制台database保存元数据redis做缓存。虽然本质上是“把一堆容器拉起来”但对外看完全像一个单一应用用户只需要记住一个访问地址。相比原生registry它有几个很实用的特性。支持多项目Project和精细的角色划分可以做到只读者、开发者、管理员的权限区别内置镜像复制Replication可以从另一个Harbor或标准Registry拉取同步也可以推送到远端机房支持漏洞扫描配合Trivy和不可变标签immutable tag大团队容易踩的“基础镜像被覆盖”这类坑基本都在产品层面做了防护。还有操作日志、垃圾回收、配额管理这些全是生产环境的刚需。我不是说所有场景都得用Harbor如果你只是个人电脑上自己倒腾镜像原生registry加一个简单的UI工具确实够用。但当镜像要服务到一个团队、一个部门甚至一条完整的CI/CD链路时Harbor的复杂度与它换来的管理能力相比完全划算。下面进入正题说安装。2. 安装前必须定的几件事版本、机器规格和证书策略2.1 版本怎么选2.x还是3.x离线包还是在线包先给结论如今新装Harbor不要再用1.x直接从2.x的较新版本开始。Harbor 2.x 调整了组件架构从依赖Docker Compose v1平滑过渡到支持v2同时镜像格式升级为支持OCI标准项目级策略也更丰富。我这次安装用的是2.11.x的离线包和2.6、2.8这些中早期版本相比配置方式和核心逻辑差别很小上手成本很低。安装包选择上官方提供online和offline两种区别在于离线包把Harbor自身需要的镜像和二进制全部打包好了安装过程不依赖从外网拉取镜像适合内网部署也适合网络不稳的环境。我自己的习惯是无论有没有外网都下离线包一是快二是版本锁定不会今天装和明天装的产物不一致。下载就到官方开源仓库的Release页面找harbor-offline-installer-v2.x.x.tgz即可注意下载后先校验一下SHA256避免文件损坏。这个校验虽然只多一步但能省下后面排查“容器起不来”的大量时间。2.2 机器与依赖检查清单Harbor整体是一个多容器应用虽然单机部署不夸张但也不能拿太小的机器硬顶。我建议生产环境至少2核4G镜像存储需求比较大的再往上加内存因为数据库和redis是内存占用的大头。磁盘不只是看总容量更要看data_volume所在分区的剩余空间镜像仓库的容量增速往往比你预想得快。系统我用的是主流Linux发行版内核版本不要太旧Docker版本建议20.10及以上同时准备好docker compose插件。Harbor的install.sh脚本会检测docker和docker compose缺了就直接报错。依赖环节最容易忽略的是基础工具openssl用于生成证书、tar用于解包、curl用于接口测试很多精简服务器镜像没有预装安装前先补上。另外确认80端口没被nginx或其它Web服务占用如果机器上已经跑了Web服务后面配置时就要主动避开否则大概率会撞端口。2.3 证书策略HTTPS还是HTTP生产怎么选这一步很多人会直接跳过本地测试无所谓但一旦面向团队甚至生产我强烈建议把HTTPS搞定。Harbor官方安装脚本默认启动http如果要配https需要提前准备证书和私钥并在harbor.yml里指定路径。如果团队内部有CA体系或者能拿到受信任的正式证书直接用最省事。如果没有就自己生成自签证书。自签证书的坑在于Docker客户端默认不信任私有CA需要在每台要访问Harbor的机器上把CA证书放到系统信任目录并在docker daemon的证书目录里单独配置。这块我放到后面第4章具体讲这里先说结论即使麻烦一点也别为了“方便”长期裸跑HTTP。镜像内容里经常包含大量代码和配置信息明文传一遍相当于把内部结构暴露给沿途的节点。测试环境想省事就先用HTTP生产一定要上HTTPS或者让统一网关来做TLS终止总之不要让镜像流量裸奔。3. 离线安装一条龙从tar包到控制台3.1 下载并解压离线安装包下载完成后把安装包上传到目标机器的目标目录比如/opt/harbor-install然后解压。解压后目录里的核心文件是harbor.yml.tmpl和install.sh名字带tmpl说明只是个模板要先复制一份成harbor.yml再修改。注意解压时用tar -zxf确认文件归属和权限没问题后再进入目录。我第一次装的时候图省事直接在原目录里改harbor.yml.tmpl结果后面执行脚本时发现模板文件被改了后续升级还会被覆盖踩过一次坑。所以规范动作一定是cp harbor.yml.tmpl harbor.yml所有自定义配置都写到harbor.yml里这也是官方推荐的做法。3.2 harbor.yml 配置逐项拆解harbor.yml是安装配置的核心我建议一行一行过一遍不要只改hostname就完事。下面按关键项讲hostname这个是你访问Harbor的地址可以填域名也可以填IP不要带http://前缀。之后Docker客户端要访问它所以填的必须是客户端能解析到且能到达的地址别填localhost除非你只在同一台机器上用。如果后面要启用外部访问hostname最好跟证书里的域名保持一致否则TLS校验会报hostname mismatch。http.port默认80如果80已经被占用改成8080或其它未占用端口。改完之后记得所有访问地址都要带上新端口包括docker login、页面URL、复制规则里的远端地址漏一个就会让你误以为Harbor“挂了”。https部分默认注释掉如果你有证书取消注释并填写certificate和private_key的绝对路径。注意Harbor对证书文件的权限有要求私钥不能太开放否则nginx容器会反复重启报权限错误。harbor_admin_password默认管理员密码是Harbor12345第一次部署时就要改掉。这个密码字段只在首次安装时生效后续改管理员密码要登录UI操作或走API不能只改这个文件再重启很多新手在这上面吃了亏。database.password这是Harbor内部数据库的root用户密码默认值是root123生产环境必须改而且改了要妥善保管因为后面备份恢复、升级都会用到它。data_volume所有持久化数据存放位置包括镜像层、数据库文件、redis持久化数据。务必指向一个有独立空间的分区比如/data/harbor。安排磁盘时就要想到这个目录以后会膨胀不要放在根分区里挤占系统空间。log.level默认info排查问题想看得细就改成debug但生产一般用info就好debug会产生大量日志日志文件轮转不及时可能反过来占满磁盘。3.3 执行install.sh与配套组件开关配置保存后直接执行./install.sh只要依赖都齐脚本会自动做几件事检查环境、准备目录、启动依赖组件、拉起所有Harbor容器。整个过程可能会有几分钟取决于磁盘写入速度不要看到命令行长时间没输出就以为卡死了可以另开一个终端看docker ps。install.sh还支持一些可选参数比如--with-trivy启用漏洞扫描--with-chartmuseum提供Helm Chart仓库--with-notary提供镜像签名。我的建议是如果你用Helm部署应用chartmuseum值得开Trivy扫描在团队协作时很有用但会多消耗不少内存notary除非你确实有镜像签名合规要求否则别开维护成本大于收益。组件越多容器越多占的内存和磁盘也就越大不要为“都有”而开所有开关以后每次升级多一组迁移步骤的滋味可不好受。3.4 验证部署状态与首次登录安装脚本执行完第一件事是确认所有容器都处于healthy状态。用docker compose -f /opt/harbor-install/docker-compose.yml ps查看或者直接docker ps。正常情况会有nginx、core、portal、registry、jobservice、db、redis这几个核心容器开了trivy的话还能看到trivy相关任务。容器处于starting或restarting状态都说明配置有问题不要急着登录页面。容器全部healthy后浏览器访问你配置好的地址看到登录页就用admin和前面设置的密码登录。登录后第一建议先去“系统管理-项目”里创建自己的项目或者调整自带library项目的访问级别不要一上来就急着推镜像。UI显示正常说明安装阶段基本通过了接下来是让Docker客户端能顺畅访问它。4. 把Docker客户端接进来daemon.json、登录和推送4.1 daemon.json改什么insecure-registries和registry-mirrors不能搞混部署好Harbor之后你拿到一台开发机要推送镜像如果是HTTP访问比如http://192.168.1.100:80Docker默认会拒绝连接报错类似http: server gave HTTP response to HTTPS client。解决方法是让Docker把这个地址标记为不安全仓库在/etc/docker/daemon.json里加一段{ insecure-registries: [192.168.1.100:80] }注意这里有两个地方容易混insecure-registries里写的是Harbor地址registry-mirrors里写的是镜像加速器地址两者完全不是一回事。我曾经看到同事把Harbor地址填到mirrors里重启Docker后所有公开镜像拉取都走Harbor效果自然不对拉个nginx都可能因为仓库里没有而卡上半天。配置文件改完需要重启Docker进程systemctl restart docker老版本init系统就是service docker restart。重启前要评估影响因为很多服务器Docker里还跑着业务容器最好选维护窗口操作。如果你配了HTTPS和自签证书更推荐的方式是把自签CA放到/etc/docker/certs.d/hostname/ca.crt这样Docker会把你Harbor当作可信节点。这个做法的好处是不用无条件信任整个网段安全控制更精确客户端机器上也只认这一台仓库。4.2 docker login与tag、push的完整流程配置完成后先在命令行登录docker login 192.168.1.100:80输入你在Harbor里创建的用户名密码。注意登录成功后会生成一个登录文件存放在~/.docker/config.json之后push/pull就不需要再输入密码。这里有的同学会疑惑明明登录成功了push时还是提示unauthorized多半是因为镜像tag不符合格式规则或者没有推送到你有权限的项目。Harbor的完整镜像名称结构是Harbor地址/项目名/镜像名:标签。比如你有一个nginx镜像要传到library项目下docker tag nginx:latest 192.168.1.100:80/library/nginx:v1 docker push 192.168.1.100:80/library/nginx:v1项目名的位置很关键不是想当然地docker push 192.168.1.100:80/nginx:v1如果那个项目不存在或者你没权限就会遇到权限问题。拉取时也是一样docker pull 192.168.1.100:80/library/nginx:v1。在Harbor UI里能看到这个镜像成功出现说明整套链路已经通了。4.3 界面操作创建项目、设置策略、权限分配客户端接入之后Harbor真正的管理价值在UI里。登录进入控制台左侧菜单能看到“项目”入口。新建项目时名称规则要求和镜像名里的项目名一致比如team-dev访问级别建议默认私有只有被授权的账号才可见可拉镜像代理缓存、复制规则这些按需配置。建完项目后进入“成员”页面把开发、测试人员添加进来并分配角色。Harbor的角色默认有项目管理员、开发者、访客三种对应不同权限集合。开发者可以push和pull访客只能pull项目管理员还能管理成员和配置。实际操作里我一般会把开发者权限给需要的同事访客权限给下游部署服务器最小化权限原则能减少很多误删误覆盖的事故。另外如果镜像会被多个项目共用可以考虑library作为公共只读项目大家统一从里面拉基础镜像自己的项目再建私有项目单独存。这样既降低了重复推送基础镜像的浪费也便于控制生产环境的镜像来源。5. 长期运行避坑端口冲突、磁盘占用与常见报错5.1 端口冲突和502排查Harbor安装阶段最常遇见的错误就是端口冲突。有一次我在一台已经跑着Nginx的服务器上装Harbor默认80端口被占用install.sh执行时组件能起来但portal始终无法访问。当时第一反应是看容器状态发现所有容器都在running但页面就是打不开。排查思路先用ss -lntp | grep 80确认端口被谁占用再做修正改harbor.yml里的http.port为8080重新执行install.sh。但注意旧的容器和卷不会自动清理干净会留下上次启动的残留。最干净的做法是先docker compose down再重新部署确保配置变更生效。把端口改成8080后页面立刻能访问。如果你是已启动Harbor后改配置必须完整down再up不能只restart一个容器因为nginx入口在转发逻辑里会按旧的配置缓存。502在Harbor里经常是core服务响应超时或数据库连接没起来。排查时看core日志docker compose logs core常见的如redis连不上、数据库密码不对基本都在日志里写得很明确。这时候别急着重启所有容器先看日志把根因定住盲目重启只会让问题反复出现。5.2 数据卷增长与GC清理Harbor跑起来的第三四个月最直观的问题就是磁盘看着看着就不够了。镜像层数据很占空间尤其团队并行开发、频繁构建的场景仓库里容易堆出一堆没人用的旧tag。Harbor自带垃圾回收GC功能在UI“系统管理”入口能找到作用是把已经被删除镜像标记、但还在磁盘占用的数据真正清理掉。但GC不是灵丹妙药它只回收已经被删除的镜像不会自动清理那些“还留在仓库里但已经没人用”的旧tag。所以日常维护里要定期做两件事一是要求团队成员删除无用tag二是对长期不用的项目设置配额阻止仓库无限膨胀。也可以在“系统管理-配额管理”里给每个项目设置存储上限超过后push会被拒绝避免几轮无节制测试把磁盘打满。5.3 自签证书告警、时钟偏差等细节自签证书场景下Docker客户端偶尔会报x509 certificate signed by unknown authority原因就是没把CA放入客户端信任目录。另一个比较隐蔽的坑是服务器时间偏差Harbor在生成和校验token时强依赖时间戳如果机器时钟差了几分钟你会看到登录页能打开、但API反复401。这个问题的修复不是在Harbor里而是用NTP/chrony同步系统时间然后再重启Harbor容器。顺带一提如果你是在虚拟机上做实验宿主机休眠再唤醒后最容易出现这类时间漂移我在这上面浪费过一个小时。除了这些还有一些小点值得注意定期检查容器状态不要只靠眼睛我习惯写一个简单的巡检脚本定时把docker compose ps的输出发到工作通知群能第一时间发现容器退化到unhealthy。日志目录默认在/var/log/harbor/下面core、nginx、jobservice各自的日志分开存放千万别用docker logs去替代那样看到的内容不全也不会做滚动轮转。6. 我最后想说的几个实践体会6.1 配置决策比安装本身更重要装了几次Harbor之后我最大的体会是这个项目真正的复杂度不在安装脚本而在配置决策上。版本选对、磁盘规划好、证书策略想清楚、权限按最小化分配后面基本是顺水推舟。反过来如果一开始只图省事把密码全用默认、HTTP裸跑、数据目录放根分区三个月后你大概率要花比安装多十倍的时间去补课。我见过一个团队因为省略了数据库密码修改后来数据库被外部扫描器直接连上整个仓库元数据被清空教训相当惨痛。虽然不能完全怪Harbor但安装时顺手改掉默认密码的成本实在太低了不值得冒这个险。6.2 别把组件全家桶当成最优解另一个体会是别把所有可选的组件都打开。每次看到install.sh后面跟着一堆--with参数都觉得功能越多越好但每个组件都要占用内存、产生日志、增加升级时的迁移步骤。Harbor的核心价值是镜像管理和权限控制其他能力按实际需要选择而不是图“全家桶”。我自己的项目里长期只跑核心组件加一个Trivy扫描镜像签名和Helm Chart仓库都没开升级时省心很多。等以后确实需要了再加一把开关重新install一次也不麻烦。6.3 升级迁移前备份是你的保命底牌最后分享一个小技巧在做升级或迁移之前永远先备份。Harbor的备份不需要太复杂harbor.yml、数据库导出、data_volume完整拷贝这三样是关键。我自己的习惯是升级前先搞一份完整备份到另一台机器或移动硬盘升级失败还能退回旧版本升级成功后再把旧备份归档而不是删除留一个月。真出问题的时候这份备份就是你敢继续操作底气的来源。备份完做一次恢复演练确认数据真的能带回来而不是备份完就以为万事大吉。很多人直到丢失数据的那天才发现自己的备份是坏的那种心情我不想你再体验一次。