Harbor v1.10.6镜像仓库部署与HTTPS配置实战指南 团队在上个月把内部的镜像仓库从裸registry换成了 Harbor v1.10.6整个过程比预想中要繁琐不少。这里把从零搭建、TLS 配置到企业级功能落地的完整过程整理出来尤其是那些官方文档一笔带过、但实际操作时一定会踩的坑希望给正在选型或已经准备上 Harbor 的团队一些参考。先解释一下为什么是 v1.10.6 而不是更新的 2.x。我们这边有不少存量脚本和 CI 任务都基于旧版 API 和推送方式写的2.x 改了部分接口和组件编排方式短期没有足够人力去做兼容验证。v1.10.6 又是 1.x 生命周期里比较稳定的一个补丁版安全修复比较全面社区里的问题反馈和踩坑经验也最多出了问题基本都能搜到答案。对很多中小团队来说稳定性优先于追新这个版本反而是最合理的选择。1. 环境准备先盘清楚资源、系统和网络约束Harbor 本质上是一组容器的集合由 nginx、core、portal、registry、jobservice、数据库、Redis 等组件拼在一起通过 docker-compose 统一编排。所以底层的 Docker 环境和系统资源规划直接决定了后面能跑得多稳这一块值得花半小时认真对待。1.1 硬件资源别被镜像仓库很轻量骗了不少文档会写 Harbor 最低配置 2 核 4G 就能跑这话没错但也只说对了一半。我自己部署时发现空转状态下 Harbor 的内存占用就接近 1.5G 左右一旦开始处理镜像上传、触发复制任务或垃圾回收内存和 CPU 都会明显冲高。如果是给团队用的内部仓库建议至少 4 核 8G磁盘单独挂一块数据盘不要让系统盘和镜像数据挤在一起。磁盘容量方面按团队活跃项目数量和镜像更新频率来估算我个人习惯按未来一年增量 x 2来规划不要只按当前存量算。仓库这种东西一旦上线镜像只会越来越多后期扩容虽然可以做但要迁移数据卷中间要停服务代价远比一开始多给点空间要大得多。1.2 Docker 环境版本和存储驱动都要看搭建机器上的 Docker 版本建议用 19.03 之后的因为对overlay2存储驱动的支持比较成熟。我遇到过用老版本 Docker 的情况存储驱动还是aufsHarbor 的 registry 容器在并发推送时偶发层文件丢失后来升级 Docker 并切换到overlay2才彻底稳定。可以在部署前先确认一下当前环境docker version docker info | grep -i storage如果输出显示Storage Driver: overlay2就没问题。如果不是建议先升级 Docker 再继续否则后面排查问题的成本会很高。1.3 网络与域名提前定好对外访问地址Harbor 的配置里有一个hostname字段这个值非常关键。它既会写进 Web 访问地址也会用于生成镜像推送路径。例如你配置了hostname: harbor.internal.example.com那么团队成员推送镜像时就要执行docker pull harbor.internal.example.com/library/nginx:1.25这要求在团队内部网络环境里这个域名能被解析到 Harbor 服务器。如果大家是通过 IP 访问也可以直接把 IP 写在 hostname 里。但要注意后面一旦要启用 HTTPS证书的 Common Name 或 SAN 里必须包含这个域名或 IP所以建议从一开始就选定一个固定的访问地址不要中途频繁改否则每个成员都要重新配置 Docker 客户端的信任证书非常麻烦。2. 离线安装包准备与 docker-compose 部署全流程我这次用的是离线安装包方式。相比在线安装离线包把所有需要的容器镜像都打成压缩文件放进包里部署时不用从 Docker Hub 拉镜像整个过程更可控。尤其是在网络环境受限、或者 Docker Hub 访问不顺畅的内网机房这个方法非常有必要。2.1 下载离线包与校验拿到了harbor-offline-installer-v1.10.6.tgz之后建议先解压到固定目录我习惯放在/opt/harbormkdir -p /opt/harbor tar -xzvf harbor-offline-installer-v1.10.6.tgz -C /opt/harbor cd /opt/harbor目录下会有一个harbor.yml这是整个 Harbor 的核心配置文件。另外还有install.sh和prepare脚本。需要留意的是install.sh每次执行时会重新读取harbor.yml并生成对应的docker-compose.yml所以修改配置后要重新跑 install 或 prepare 才能生效不能只改配置文件不重新生成编排文件。2.2 配置文件修改必改项和推荐项打开harbor.yml后有几个字段必须认真对待hostname: harbor.internal.example.com http: port: 80 harbor_admin_password: Harbor12345 data_volume: /data/harborhostname上面已经强调过。harbor_admin_password是 Web 管理员admin的初始密码默认值是Harbor12345如果不上生产环境这个值必须要改而且建议用密码生成器随机生成一串不要图省事用默认值。data_volume是镜像元数据和存储的根目录。这个目录必须挂在大容量磁盘上并且建议做成独立分区。我在生产环境选择把/data/harbor单独 mount 一块磁盘避免日志或系统进程把根分区写满后波及镜像仓库。如果是通过 HTTP 方式访问还要把下面这段打开# 注意 1.10 版本的写法 enable_http: true这里有个容易混淆的点enable_http表示 Harbor 是否启动 HTTP 监听端口而不是是否允许 HTTP 访问。如果同时配置了https和http两个端口块并且enable_http: true那么两个端口都能访问。如果只想用 HTTPS就把http端口注释掉。2.3 执行安装脚本与验证组件状态配置修改完之后直接运行安装脚本sudo ./install.sh脚本会先加载镜像再生成docker-compose.yml最后拉起容器。整个过程大概一到三分钟。安装完成后先用docker ps看看所有容器是否都处于Up状态。正常应该有 9 个左右的容器包括nginx、core、portal、registry、registryctl、jobservice、postgresql、redis、log。如果某些容器反复重启多半是配置有问题。常见的排查方式是看具体容器的日志docker logs -f container_name比如core容器起不来经常和数据库连接参数或密码错误有关。把配置文件中的database字段和实际环境对一遍基本就能发现原因。2.4 首次登录和基本状态检查安装完成后浏览器访问配置的地址用admin加你设置的密码登录。登录后建议先去系统管理确认各项组件的健康状态再看一下日志端点是否能正常接收日志。我遇到过安装顺利但log容器内部权限不对导致日志丢失的情况这种问题不检查日志平台很难发现等需要排查问题时才后悔当初没看一眼。3. 启用 HTTPS生产环境必须跨过的第一道坎在团队内部的测试阶段直接 HTTP 访问确实省事但一旦要面向多个团队、并且有部分成员会通过公网或跨地域访问仓库HTTPS 就变成了硬需求。镜像推送过程中如果走明文 HTTP镜像内容在传输过程中可能被篡改Docker 客户端也会因为非 TLS 连接产生一堆校验问题。3.1 自建 CA 还是用内部 CA 签发企业内部使用强烈建议不要用自签证书而是让公司网管或运维组签一套内部 CA 证书统一分发给所有接入终端。这样只要在每台 Docker 客户端上安装一次 CA 根证书后续所有使用该 CA 签发的 Harbor 证书都会被信任不需要逐台配置 insecure-registries。如果只有一两台服务器要用临时用自签证书顶一下也可以但需要在每台客户端执行类似下面的操作# 拷贝证书到 Docker 的证书目录文件名必须和 hostname 对应 mkdir -p /etc/docker/certs.d/harbor.internal.example.com cp harbor.crt /etc/docker/certs.d/harbor.internal.example.com/ca.crt systemctl restart docker如果客户端不做这一步直接执行docker login大概率会报x509: certificate signed by unknown authority。这个错误非常典型几乎每天都有人在社区提问。3.2 证书生成时的 SAN 配置最容易忽略的细节用内部 CA 申请证书时必须把 Harbor 的访问域名写进 SANSubject Alternative Name字段。很多人还停留在只写 Common Name 的习惯但新版 Docker 和浏览器做证书校验时首先看 SAN不再信任只有 CN 的证书。生成证书请求时openssl的配置文件里要有类似内容[ req ] distinguished_name req_distinguished_name req_extensions v3_req [ v3_req ] subjectAltName alt_names [ alt_names ] DNS.1 harbor.internal.example.com IP.2 192.168.10.20注意IP.2这个写法在不同的openssl版本里略有差异如果同时要支持域名和 IP 访问一定要确认生成的证书里真的包含了对应条目。可以用下面这条命令校验openssl x509 -in harbor.crt -noout -text | grep -A1 Subject Alternative Name3.3 修改配置并重启 Harbor拿到证书之后把harbor.yml的 HTTPS 段配置好https: port: 443 certificate: /data/certs/harbor.crt private_key: /data/certs/harbor.key证书文件路径建议放在data_volume之外的独立目录这样后续做数据清理时不会意外删掉证书。然后重新执行sudo ./install.sh这里要特别注意install.sh会重读配置并重新生成编排文件但不会清理已有的数据卷所以重复执行是安全的。不过如果改了数据库密码重复执行并不代表会自动同步到已初始化的数据库里这种场景需要单独处理下面会提到。4. 配置生效后的事镜像推送、拉取和数据校验部署完成、HTTPS 也配好之后最重要的就是跑通一次真实的镜像推送链路。这个环节最能暴露问题很多人在这里卡住。4.1 Docker 登录和推送先登录docker login harbor.internal.example.com输入用户名和密码如果没有任何输出说明登录成功。然后给本地镜像打上仓库地址的 tagdocker tag nginx:1.25 harbor.internal.example.com/library/nginx:1.25 docker push harbor.internal.example.com/library/nginx:1.25推送完成后在 Web 界面的library项目里就能看到这个镜像。4.2 公网和内网混合场景下的配置差异如果团队里有人在外网办公访问 Harbor 时需要走公网域名或反向代理此时 Docker 客户端的insecure-registries配置要谨慎对待。千万不要因为嫌证书分发麻烦就直接把域名加入 insecure-registries这会绕过 TLS 校验等于把 HTTPS 的安全收益全部放弃。正确做法仍然是把内部 CA 根证书安装到每台需要登录的终端上。另外一个比较隐蔽的问题Docker Desktop 在 Mac 和 Windows 上做证书信任时和纯 Linux 的 Docker Engine 不太一样需要单独在 Docker Desktop 的设置界面里配置证书路径而不是直接放到某个系统目录就行。我第一次给同事配置时就漏了这个他们登录时报错排查半天才意识到问题出在 Docker Desktop 的证书配置入口和普通 Linux 完全不同。4.3 日常巡检和健康检查Harbor 没有现成的命令行客户端日常巡检我主要看两部分。一是容器状态docker ps --filter nameharbor二是 Harbor 的 API 是否正常响应curl -u admin:password https://harbor.internal.example.com/api/v2.0/ping如果返回正常说明核心服务在线。这个接口用于检查 Harbor 是否能正常处理请求返回内容比较简单但能确认网络链路和基础认证都没问题。5. 企业级功能落地认证对接、镜像复制和配额搭建完成只是第一步。真正让它变成一个能对外提供服务的企业级仓库还需要把认证对接、复制规则、配额控制这些能力用起来。5.1 LDAP 对接让团队成员用企业账号登录v1.10.6 支持在harbor.yml里配置 LDAP/AD。配置之前先确认企业 LDAP 服务器的地址、端口、Base DN 和管理员 DN。把下面这段按实际情况填入ldap: url: ldaps://ldap.internal.example.com base_dn: oupeople,dcexample,dccom uid: uid filter: (objectClassperson) search_dn: cnadmin,dcexample,dccom search_password: 你的LDAP管理员密码配置完成并重新安装后在 Web 界面系统管理-认证模式中选择LDAP再填写对应的LDAP Base DN和LDAP UID。这一步容易出问题的是uid字段每个企业的LDAP目录属性不同有的用sAMAccountName有的用cn这取决于你们使用的LDAP目录服务和属性定义。第一次配置时建议先用目录查询工具确认一下不要照抄网上任意一份配置就执行。5.2 镜像复制几百个项目都用得上跨机房或跨环境同步镜像时Harbor 的复制功能非常实用。创建一条规则的方式也比较简单进入系统管理-复制管理新建一条复制规则源仓库选当前 Harbor目标仓库填目标注册中心信息例如另一套 Harbor 的地址和认证信息然后设置要复制的镜像范围和同步方向。规则触发方式可以选手动、定时或事件驱动。我一般推荐选推送镜像时触发这样只要源仓库有新镜像上传目标仓库能自动同步适合两地机房的多活场景。5.3 存储配额防止有人把仓库当网盘Harbor 的镜像大小和存储配额在 v1.10 系列中已经比较成熟。在项目详情页可以设置存储限额例如某个测试项目限制为 5 GB超过后再推送镜像会被拒绝。设置配额的最大好处是防止仓储被大量无用的测试镜像占满尤其当团队有新人频繁打 tag 不清旧镜像时配额能迫使团队养成定期清理的习惯。需要注意配额限制生效后推送大镜像时如果当前项目剩余空间不足Docker 客户端会收到一个 403 错误信息可能是insufficient storage space之类。遇到这个提示去项目配置里清理掉不需要的镜像或增大配额即可。5.4 垃圾回收清理被遗忘的镜像层Harbor 里删除镜像时删除动作只改了元数据和引用真正占磁盘空间的 blob 层并不会立即被清除。只有执行垃圾回收以后那些没有被引用的 blob 才会被实际删除。在 v1.10 里垃圾回收入口在系统管理-垃圾回收。点击立即回收后系统会创建一个任务。回收过程中不要往仓库里推镜像否则可能出现因为并发操作导致的层数据不一致问题。我在实际回收时习惯选业务低峰期执行并且提前通过邮件或群里通知团队暂停推送任务避免仓库在清理期间出现数据异常。垃圾回收完成之后可以对比回收前后的磁盘占用df -h /data/harbor通常能看到明显的数据量下降。6. 那些年我踩过的坑完整排查链路与避坑建议最后这部分单独讲两个我印象最深的故障排查过程也许能帮大家省下不少时间。就一条条说没有太多理论知识都是实操现场。6.1 容器起不来数据库密码修改带来的连环坑第一次部署时误把harbor.yml里的database.password从默认值改了然后执行install.sh结果postgresql容器反复重启。一开始我以为是镜像有问题反复重新 load 镜像也没有效果。后来看了日志才知道问题出在 Harbor 的数据库是第一次初始化的如果修改了数据库密码但实际上 PostgreSQL 在首次初始化时使用的密码来自install.sh的执行过程。日志里一直报password authentication failed for user harbor。当时的情况是配置文件里写了新密码但数据库已初始化密码还是旧的。解决方法是先停掉 Harborsudo docker-compose -f /opt/harbor/docker-compose.yml down然后把数据卷中数据库相关的初始化目录备份后清掉例如/data/harbor/database再重新执行install.sh。要注意这会清空已有的项目和镜像元数据所以只能在部署早期或能接受数据丢失的情况下这么干。如果仓库已生产使用就必须走官方数据库迁移流程或保留原密码不能随意改这个字段。6.2 镜像推送偶发失败网络层和数据层都要怀疑还有一次团队反馈推送大镜像时偶尔失败报错信息类似blob upload unknown或connection reset by peer。第一反应是网关或防火墙拦截了大包但调大 MTU 和超时时间后依然随机出现。最后定位到是磁盘空间不足。Harbor 的 Dockerfile 在接收分片上传时会先把临时数据写到数据卷磁盘剩余空间在一次并发推送中被打满导致分片写入失败。清理了旧镜像并扩展磁盘之后问题消失。后来我养成了对/data/harbor磁盘剩余空间做阈值告警的习惯不仅看总量也监控docker system df显示的层数据量提前预防这类问题。6.3 明确定位各服务日志的入口Harbor 的所有容器日志都可以通过 Docker 查看但实际排查时最有用的是core、registry、jobservice三个服务。例如镜像推送失败优先看registry容器日志登录认证失败优先看core容器日志复制任务失败优先看jobservice容器日志。可以在.env或 docker-compose 输出里找到相关服务的容器名也可以直接用docker logs --tail 500 -f harbor-core docker logs --tail 500 -f harbor-registry docker logs --tail 500 -f harbor-jobservice定位问题的速度会快很多。6.4 数据备份的最佳方式最后一定要提的就是备份。Harbor 的数据分为两部分一部分是 PostgreSQL 中的元数据包括项目、用户、标签等另一部分是/data/harbor/registry下的镜像数据。备份时最好两部分都覆盖只备份目录而不备份数据库的做法非常危险。数据库备份可以用容器内执行docker exec harbor-database pg_dump -U harbor -d registry harbor_backup.sql这个备份文件挺小的每天定时备份放到对象存储即可。镜像数据则考虑定期用 rsync 同步到另一台机器。恢复时先恢复数据库再把镜像目录放回原位。7. 从这套实例里沉淀的运维习惯整套 Harbor v1.10.6 跑到现在已经稳定运行了好几个月中间经历了几次升级和日常维护最后分享几个个人的运维习惯。第一配置文件改动后先执行prepare而不是直接install.sh。prepare会根据harbor.yml重新生成配置文件和 docker-compose 编排文件但不会重新加载镜像。如果需要重新应用配置可以用install.sh但要注意它会执行 complete 重新加载并重建容器。两者区别搞清楚能少踩很多坑。第二定期在 Web 界面导出系统日志和查看项目配额使用趋势不要等到磁盘报警才去处理。镜像仓库像硬盘一样越接近满载性能越差回收也越困难。第三如果有多个机房或多个环境优先把复制规则配置好而不是每天手动同步镜像。Harbor 的复制功能一旦配置好基本不用管比人肉同步可靠得多。构建一套企业级的镜像仓库并没有想象中那么复杂但也没有那么简单。只要把环境规划、TLS 证书、认证对接、配额的坑都走一遍整个系统会变得非常稳定。希望这份实操记录能给正在搭建或维护 Harbor 的各位一个参考。