资讯详情

Harbor 2.5离线部署全攻略:内网镜像仓库搭建与排坑指南

📅 2026/10/14 7:22:51 | 华诺云谱 👁 阅读
Harbor 2.5离线部署全攻略:内网镜像仓库搭建与排坑指南
简介Harbor v2.5.0-rc1离线安装包面向需要在无外网或受限网络环境中部署容器镜像仓库的运维与开发人员解决从在线源拉取Harbor镜像困难、依赖关系复杂的问题适合内网机房、私有云及等保合规等场景。资源共6个文件以shell脚本、配置模板、镜像压缩包和许可证为主install.sh与common.sh负责安装流程与公共函数封装prepare与harbor.yml.tmpl用于配置生成与参数适配harbor.v2.5.0.tar.gz则承载全部离线镜像数据总大小约623.92MB。已有257人学习/下载可帮助读者避开手动拼接各镜像组件的时间成本。借助该资源能够直接执行离线安装快速搭建可供团队使用的私有镜像仓库同时配置文件模板与脚本保留了灵活调整空间便于按业务需求修改端口、存储和后端认证等关键参数也为后续版本升级与故障排查提供了清晰的脚本化入口。1. 离线镜像仓库 Harbor真正吃紧的不是 docker是网在内网环境搭私有镜像仓库头一个难住你的往往不是 docker 用法而是你连不上公网 registry。harbor-offline-installer-v2.5.0-rc1.tgz 这个包把 Harbor 2.5.0-rc1 用到的镜像、安装脚本、配置模板整体打成一个离线包不依赖外网就能把完整的 Harbor 服务跑起来。它解决的是离线交付、隔离网部署和等保环境下镜像仓库缺位的场景。如果你手里是一台没外网的机器又要给团队提供一个能稳定 push / pull 的内部仓库这个包是最快能落地的方案。rc1 虽然带预览性质但版本基底是 2.5 系列功能边界和正式版基本一致值得评估后使用。2. Harbor 2.5.0-rc1 组件拆解离线包里的七张镜像和版本束缚为什么先讲组件而不是让你直接装因为离线包安装失败的时候报错多半发生在镜像加载和容器启动阶段这时候你只盯着 install.sh 这个入口看是定位不到问题的。搞清楚这个 tar 里面封的是什么遇到奇奇怪怪的报错才不会慌。下面我把包内结构和关键组件按实际作用拆开讲。2.1 离线包里封的不是源码是镜像 tar、prepare 脚本和配置模板解压以后你看到的不是一堆源码而是这样一个目录结构harbor/ ├── common.sh # 公共函数库检查 docker、compose、端口 ├── harbor.v2.5.0.tar.gz # 离线镜像包install.sh 会把它 load 进 docker ├── harbor.yml.tmp # 配置模板需要复制成 harbor.yml 再改 ├── install.sh # 安装入口 ├── prepare # python 脚本生成 docker-compose.yml 和相关配置 └── LICENSE这里重点说一下 common.sh、install.sh 和 prepare 三个文件的分工。install.sh 是外层操作者它先调用 common.sh 里的检测函数确认 docker 和 docker-compose 存在再检查端口是否被占用然后把 harbor.v2.5.0.tar.gz 通过 docker load 加载成本地镜像最后执行 prepare 并调用 docker-compose up -d 启动整套服务。prepare 是一个 python 脚本它的职责是读取 harbor.yml 里的配置把端口、证书路径、数据库密码、data_volume 这些参数映射到生成的 docker-compose.yml 环境中。所以如果你改了 harbor.yml 之后没有重新执行 prepare配置不会生效。离线包真正有价值的地方在 harbor.v2.5.0.tar.gz里面封的是这些镜像镜像角色harbor-core核心业务逻辑管理项目、用户、权限、机器人账号harbor-registry镜像存储与分发兼容 docker registry v2 协议harbor-registryctlregistry 的管理控制负责配置和健康检查harbor-portal前端 web UIharbor-dbPostgreSQL存放元数据harbor-redis缓存与任务队列harbor-jobservice异步任务GC、复制、漏洞扫描触发harbor-nginx统一入口按路径分发请求harbor-trivy漏洞扫描器2.5 默认用 Trivy这些镜像之间的调用关系是nginx 接收外部请求把 /api 和 /cgi 路径分给 core把 /v2 路径分给 registrycore 操作 db 和 redisjobservice 消费 redis 里的任务队列registry 和 trivy 都通过 registryctl 做状态感知。理解这条链路后面排错时你知道先看哪个容器日志。2.2 为什么离线安装包选 docker-compose 而不是 k8s很多人会问Harbor 明明支持 Helm 和 Operator为什么官方离线包一直保留 docker-compose 方案。原因是离线安装包的适用场景很明确单机或者双机的小规模部署。在一台没外网的虚拟机上用 docker-compose 管理生命周期最直接资源占用小启动链路短出了问题也容易手工介入。我一般会在两种情况下选择离线包加 docker-compose一种是要交付到客户内网的隔离环境机器配置普遍是 4C8G 到 8C16G跑 k8s 太重另一种是临时搭建一个镜像中转站比如从公网环境把一批镜像导出再搬到内网导入。这套方式的特点是快解压、改配置、执行安装十分钟内能看到 web UI。需要说明的是docker-compose 不等于不能用集群方案。包内的镜像同样可以被 pull 出来放到 k8s 节点上用只是离线包本身不负责编排集群。所以如果你想上 k8s最好把离线包当镜像源用而不是直接跑 install.sh。2.3 版本束缚先看清docker、compose、python 三者最低门槛离线安装包对环境有硬性要求而且这些要求在 install.sh 里是直接检查的。我在部署前习惯先跑一组命令把环境底数一次性摸清# 检查 docker 版本 docker --version # 检查 docker-compose 是否有独立二进制 docker-compose --version # 检查 python3prepare 脚本依赖它解析 yaml python3 --versionHarbor 2.5.0-rc1 对 docker 的要求是 17.06.0 以上docker-compose 1.18.0 以上python 版本至少 2.7能跑 3.6 以上最好。这三个条件看着不高但离线环境里最容易翻车的恰恰是它们。常见的情况是机器上只有 docker 没有 docker-compose因为装 docker 的时候很多人不会顺带把 compose 装进去。另一个容易被忽略的点是 python有些精简系统镜像连 python3 都没有prepare 直接跑不起来。如果检查发现有缺口不要直接执行 install.sh。我的做法是先解决依赖再安装因为 install.sh 的检查逻辑是发现缺失就直接退出并不会帮你装。docker-compose 可以用离线方式放到 /usr/local/bin 下单独给执行权限python 缺失的话要么用系统自带的包管理器补要么找一个低版本 python 的静态编译包放进 /usr/local/bin。完成这三项检查后再进入部署流程后面基本不会有环境问题拦路。3. 离线部署 Harbor 2.5解压、改配置、跑通 push/pull 的完整过程部署这个包的过程不算复杂但每一步都有值得注意的细节。这一章我直接把完整流程拆开写从环境准备到镜像 push 验证全部覆盖。照做的时候建议每一步都确认输出不要连着执行完一长串命令再回头看结果。3.1 先把环境拍清楚网络、端口、域名、证书动手之前我通常会在目标机器上先做一轮预检。第一步确认这台机器能不能被其他机器访问到因为镜像仓库的核心价值是分发如果客户端到服务器的端口不通后面全白搭。用下面这组命令看监听状态# 查看 80 端口是否被占用 ss -lntp | grep -E :80\s # 查看 443 端口是否被占用 ss -lntp | grep -E :443\s # 查看 /data 目录所在分区的剩余空间 df -h /data端口规划要提前定。Harbor 默认用 80 端口提供 http 服务这是 install.sh 不做特殊配置时的默认行为。如果这台机器已经有 nginx 或其他 web 服务占了 80你需要在 harbor.yml 里显式改成其他端口。数据目录默认是 /data镜像文件和数据库文件都会落在这里所以这个分区要有充足空间我给生产环境的最低建议是 100GB 可用空间镜像多的话按数据增长预期再加。域名方面如果是内网使用不一定要有正式域名但建议在 hosts 里给服务器配一个固定主机名。原因很简单docker login 时如果写 IP后面改地址会让所有客户端重新登录用域名的话只要解析指向不变客户端配置可以用域名统一管理。证书这块生产环境如果有内部 CA建议提前给域名签发证书没有的话可以先沿用 http等证书到位再切 https。3.2 解压、改配置、生成证书、预检查、install.sh 五连环境检查通过后进入正式安装。按顺序执行下面这组命令# 第一步解压离线包 tar -zxf harbor-offline-installer-v2.5.0-rc1.tgz # 第二步进入解压目录复制配置模板 cd harbor cp harbor.yml.tmp harbor.yml # 第三步编辑配置 vi harbor.ymlharbor.yml 里需要重点确认这几个字段我一般会逐个核对# 对外提供服务的地址写域名或 IP 都行但最好固定 hostname: registry.internal.example.com # http 服务端口默认 80被占用就改成 8080 之类 http: port: 80 # https 配置没有证书就先注掉整个 https 段 https: port: 443 certificate: /data/cert/server.crt private_key: /data/cert/server.key # 管理员初始密码默认是 Harbor12345首次登录后必须改 harbor_admin_password: Your-Strong-Password # 数据库密码不要与管理密码相同 database: password: DB-Password-X9 # 数据卷位置默认 /data data_volume: /data这段配置里最容易漏的是 https 证书路径。prepare 脚本会在执行时去读取 certificate 和 private_key 这两个路径如果文件不存在或者权限不对会直接报错。所以我的顺序是先确认证书文件已经摆在对应位置再执行 install.sh。用 http 就把 https 整段注掉不要留一个空的 https 配置否则 prepare 会按 https 模式生成配置结果端口和证书都不对启动必挂。配置改完执行安装# 第五步执行安装脚本 sudo ./install.shinstall.sh 会自动完成四件事加载离线镜像、执行 prepare 生成配置、检查端口占用、用 docker-compose 启动所有容器。如果输出末尾能看到各容器状态变成 Up说明基础安装完成。这里有个细节install.sh 默认会启动除 Nydus 外的所有附加组件如果不想启用 Trivy 漏洞扫描可以在执行时加--with-trivy或对应开关实际要看脚本参数。我没加开关的默认行为会启动 Trivy扫描器占一定内存低配机器可以主动关掉。3.3 打完收工登录、创建项目、验证 push/pull安装完成后访问 http://服务器地址用 admin 和刚才设置的密码登录。第一次登录后我会顺手做三件事改管理员密码、创建正式项目、配置一个机器人账号。管理员密码在 harbor.yml 里设过一次但 web UI 里的 admin 密码可能还是初始状态建议在 UI 里改一次避免配置文件里的密码泄露导致安全问题。验证镜像分发链路可以用下面这组命令在另一台机器上操作# 客户端登录仓库 docker login registry.internal.example.com -u admin # 给本地镜像打上仓库地址的 tag docker tag nginx:1.25 registry.internal.example.com/library/nginx:1.25 # 推送镜像 docker push registry.internal.example.com/library/nginx:1.25 # 拉取镜像验证 docker pull registry.internal.example.com/library/nginx:1.25library 是 Harbor 预置的公开项目默认存在适合做连通性验证。推送成功后登录 web UI在项目里的镜像列表中能看到 nginx:1.25 这个 artifact。这里我要提醒一个点docker login 的用户名和密码如果你配置了机器人账号就应该用机器人账号而不是 admin因为 admin 账号权限过大客户端机器上保存凭证会有泄露风险。机器人账号在项目的“机器人账号”菜单里创建可以按项目级别限制权限建议每个客户端用独立的机器人账号。验证完成后一个可用的离线私有镜像仓库就落地了。4. 出问题时怎么查日志目录、排查流程和常见错误离线部署最害怕的不是安装慢而是装完以后某个容器悄悄退掉镜像 push 到一半报错。这一章我按实际操作习惯整理排查路径从日志入口到具体错误类型按“先看容器状态再看日志最后定位配置或资源”的顺序讲。4.1 日志入口定位docker logs 与容器状态配合使用Harbor 的日志分两层一层是容器 stdout一层是写到宿主机的日志文件。排查第一步永远是确认哪些容器还活着# 查看全部容器状态包括退出的 docker ps -a | grep harbor # 查看某个容器的 stdout 日志core 是主入口 docker logs harbor-core --tail 200Harbor 2.5 的容器名基本是 harbor-core、harbor-db、harbor-registry、harbor-jobservice、harbor-portal、harbor-nginx 这类前缀。常见的情况是 harbor-db 退出但 core 还活着这时 web UI 能打开但登录报错。原因是数据库容器异常core 连不上 PostgreSQL。通过 docker logs harbor-db 可以看到数据库启动失败的具体原因比如数据目录权限不对或者磁盘空间不足。如果容器全部活着但镜像 push 失败下一步就要看宿主机日志目录。Harbor 会把组件日志写到 /var/log/harbor 下比如 core.log、registry.log、jobservice.log。这些日志在容器启动时通过 volume 映射出来排查时直接看宿主机文件比进容器看更方便# 查看 registry 日志 tail -200 /var/log/harbor/registry.log # 查看 core 日志 tail -200 /var/log/harbor/core.log日志的时间戳和内容能直接告诉你问题出在认证、存储还是网络。比如 registry.log 里出现layer does not exist说明镜像层在存储里找不到大概率是磁盘清理或者宿主机目录被手工动过。4.2 prepare 阶段报错配置文件和证书路径是第一道坎很多安装失败发生在执行 install.sh 的 prepare 阶段这类错误最容易让人一头雾水因为报错信息只有一行。我遇到最多的是两种情况harbor.yml 的 YAML 格式错误或者 https 证书路径指向的文件不存在。YAML 格式错误很难用肉眼发现尤其是缩进不一致。我的习惯是先用 python 解析一遍配置文件# 用 python 做 yaml 语法校验 python3 -c import yaml; c yaml.safe_load(open(harbor.yml)); print(c[hostname], c[http][port])如果这条命令报错没输出说明 YAML 结构有问题逐行检查冒号和缩进。正常输出 hostname 和端口后再确认证书路径# 确认证书文件存在且权限是 600 左右 ls -l /data/cert/server.crt /data/cert/server.key还有一类情况是配置里写了 https 段但没有生成证书文件prepare 在读取证书时直接抛异常。解决方法是把 https 段整体注掉或者先准备好证书再执行 install.sh。这里有个小坑修改 harbor.yml 之后重新执行 install.shprepare 会重新生成 docker-compose.yml但如果之前已经启动过容器需要先 docker-compose down 再 up不能直接套用新配置。4.3 存储空间与配额镜像 push 失败常见错误 ENOSPC 和 403镜像 push 失败分两类一类是磁盘空间真满了另一类是 Harbor 配额限制。磁盘满的典型报错是ENOSPC: no space left on device这个错误可能出现在宿主机分区也可能出现在容器内挂载目录。先看宿主机空间# 查看 /data 和 docker 目录的空间 df -h /data /var/lib/docker如果宿主机空间没问题再看配额。Harbor 从 2.0 开始支持项目配额默认是无限但管理员可能给项目设置了存储上限。配额用尽时报错是403 Forbidden而且响应体里会有 quota 相关的信息。这种情况的解决方式是增加配额或者清理项目内不再需要的镜像。配额检查和清理可以看项目设置里的“配额”标签页。我一般会把项目配额设置成略低于宿主机可用空间的值比如宿主机 500G项目配额设成 450G防止镜像写满磁盘导致整个 harbor-db 容器崩溃。清理镜像后如果发现磁盘空间没有明显增加说明 GC 还没触发。Harbor 的 GC 不是自动清理需要管理员在“管理”页面手动执行或者配置定时 GC 策略。GC 策略可以设置保留天数比如保留最近 30 天的镜像更老的全清掉。这个功能适合镜像迭代快的团队能有效控制磁盘占用。5. 离线安装 Harbor五个我踩过的坑和对应解法这个包安装本身不复杂复杂的是各种环境差异导致的隐藏问题。这一章我把实际部署中踩过的五个坑整理出来按“现象 — 原因 — 解决”的方式写每一条都是现场经验供你对照处理。5.1 坑一自签名证书被 docker 拒绝login 报 x509 错误现象客户端执行docker login registry.internal.example.com直接报x509: certificate signed by unknown authority登录失败。原因Harbor 默认使用自签名证书客户端 docker 的证书校验链路里没有对应 CA所以拒绝建立 TLS 连接。这个问题在内网环境尤其常见因为没有公网信任的证书签发机构。解决把 Harbor 使用的根 CA 证书放到客户端 docker 的信任目录。Linux 客户端做法如下# 在客户端创建对应域名的目录 sudo mkdir -p /etc/docker/certs.d/registry.internal.example.com # 复制根 CA 证书 sudo cp ca.crt /etc/docker/certs.d/registry.internal.example.com/ca.crt # 重启 docker 使配置生效 sudo systemctl restart docker注意一个细节重启 docker 会中断这台机器上所有运行中的容器如果是生产机器建议在维护窗口操作或者先确认没有关键容器在跑。我一般会在客户端机器上先执行docker ps确认无业务容器再重启。5.2 坑二80 端口被已有 nginx 占用install.sh 卡在端口检查现象执行 install.sh 时脚本输出提示端口被占用或 harbor-nginx 容器反复重启web UI 无法访问。原因目标机器上已存在 nginx 或其他 web 服务占用了 80 端口而 harbor.yml 没有修改 http 端口配置仍然使用默认的 80。解决修改 harbor.yml 里的 http.port避开冲突http: port: 8080改完执行sudo ./install.sh。注意如果之前已经执行过一次 install.sh需要先进入 harbor 目录执行docker-compose down再重新执行 install.sh否则 compose 会沿用旧的端口配置。端口改成 8080 后访问地址变成 http://服务器:8080docker login 也要带上端口。5.3 坑三GC 清理后磁盘空间没释放看起来像没生效现象在 web UI 里删除了一批镜像然后手动触发 GC操作显示成功但df -h看到磁盘剩余空间几乎没有变化。原因Harbor 的镜像删除分为两步先删 manifest再等 GC 清理 blob。如果你的镜像被多个 tag 同时引用删除其中一个 tag 不会触发 blob 清理即使只有一个引用GC 也只在没有容器正在拉取该层的时候才会清理文件。另外最关键的坑是GC 清理的是未被引用的 blob但 harbor-db 中的关联记录需要 GC 完成后才真正释放而 docker 的 overlay 存储层旧层文件如果被容器进程占用同样不会释放。解决我的做法是确认删除和 GC 之间间隔一个完整周期。删除镜像后等 5 到 10 分钟确认没有正在进行的推送或拉取任务再触发 GC。GC 完成后如果空间还是没变检查 harbor-registry 容器是否仍持有旧层的文件句柄# 查看 registry 容器占用的文件句柄数量 ls -l /proc/$(docker inspect -f {{.State.Pid}} harbor-registry)/fd | wc -l如果句柄数异常多重启 harbor-registry 容器再观察空间变化。需要注意的是GC 本身对业务有影响生产环境建议在低峰期执行。5.4 坑四离线机器上没有 docker-composeinstall.sh 直接报错退出现象install.sh 执行到环境检查阶段提示 docker-compose 不存在或版本过低安装终止。原因离线机器的 docker 是手工装的默认只装了 docker 引擎没有安装 docker-compose。Harbor 的安装脚本依赖 docker-compose 做编排缺失就直接退出。解决提前准备 docker-compose 离线文件放到系统路径下# 把 docker-compose 二进制放进 /usr/local/bin cp docker-compose-linux-x86_64 /usr/local/bin/docker-compose # 加执行权限 chmod x /usr/local/bin/docker-compose # 验证版本 docker-compose --version这里建议用独立二进制而不是插件方式。Harbor 的 install.sh 调用的是 docker-compose 这个命令不是docker compose插件所以版本号要能通过docker-compose --version输出。如果机器上只有 compose 插件安装脚本不会识别需要单独放一份兼容脚本到 /usr/local/bin。这是离线环境里频率最高的环境问题提前做好这一步install.sh 会更顺利。5.5 坑五用机器人账号 push 镜像服务端返回 denied现象在 web UI 里创建了机器人账号客户端用它登录docker login 成功但 push 镜像时返回denied: requested access to the resource is denied。原因机器人账号虽然存在但它的权限范围没有覆盖对应项目或者项目的推送权限没有勾选。Harbor 的机器人账号默认权限是读不会自动获得项目的写权限。解决在 web UI 的“项目 - 机器人账号”里找到对应账号点击编辑在权限列表里勾选 push 和 pull 权限。如果你希望机器人账号能管理整个项目可以给它绑定“项目管理员”角色。客户端重新执行docker login不需要重新创建账号因为权限是服务端生效的登录凭证不受影响。这里还有一个常见误区机器人账号的密码是一个固定字符串创建后只显示一次丢了只能重新建。我一般会把密码先抄到密码管理工具里再做其他操作。6. 离线部署完我把验证脚本和配置项做成了一套固定动作部署完成不等于交付完成。我的习惯是最后跑一遍 API 验证和关键配置落项把这套动作固化下来以后每次离线部署都照做省掉很多返工。6.1 配置侧配额、GC 计划、复制并发限制生产环境的三个配置项我建议在首次部署时就设好。项目配额按照宿主机磁盘的 80% 设置留出缓冲GC 计划设置成每周日凌晨 2 点执行保留最近 30 天复制任务并发数限制在 2 到 3 个避免多个项目同时复制时把带宽打满。这些配置都是在 web UI 的管理界面操作不需要改配置文件但直接影响长期稳定性。6.2 脚本侧用 curl 打一套 API确认部署后功能完整最后我会执行下面这个验证脚本用 API 检查健康状态和登录链路#!/usr/bin/env bash set -e HARBOR_HOST10.0.0.5 ADMINadmin ADMIN_PASSyour-strong-password BASEhttp://$HARBOR_HOST/api/v2.0 # 1. 健康检查返回 200 表示核心服务正常 curl -s -o /dev/null -w health: %{http_code}\n $BASE/health # 2. 登录并拿到会话 cookie curl -s -c /tmp/harbor_cookie.txt \ -u $ADMIN:$ADMIN_PASS $BASE/users/current # 3. 创建一个临时项目验证 API 写权限 curl -s -b /tmp/harbor_cookie.txt \ -H Content-Type: application/json \ -d {project_name:verify-project,public:false} \ -o /dev/null -w create project: %{http_code}\n \ $BASE/projects # 4. 删除临时项目 curl -s -b /tmp/harbor_cookie.txt \ -X DELETE \ -o /dev/null -w delete project: %{http_code}\n \ $BASE/projects/verify-project这个脚本的核心逻辑是用 curl 走一遍 Harbor 的对外 API 链路确认核心服务、数据库、认证、项目操作都正常。health 端点如果返回 200说明核心服务起来了创建和删除项目如果都返回 2xx说明 core 到 db 的链路没问题。脚本里最后的verify-project是临时名称执行完会自动删除不影响正式数据。如果你只想验证登录把第 3、4 步去掉就行但完整跑一遍能更早暴露问题。从那以后每次离线部署 Harbor我都强制走一遍这套流程先检查环境和端口再解压改配置最后跑 API 验证和 push/pull 实测。这套动作虽然多花十分钟但帮我避开了不少凭感觉判断带来的返工。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑