
简介这是一份面向运维工程师与容器平台建设者的 Harbor 离线安装资源包对应 v2.5.0-rc1 版本适合在无外网或内网隔离环境中快速搭建镜像仓库。包体共 6 个文件总大小约 623.92MB以安装脚本sh、配置模板tmpl、预检脚本prepare、许可文件license以及离线的 Harbor 镜像压缩包gz为主覆盖从环境检查、配置生成到镜像导入启动的完整离线安装链条。目前已有 256 人学习下载适用于需要批量交付或灾备演练的私有化部署场景。通过资源内的离线安装脚本与标准配置模板读者可以理解 Harbor 在离线模式下的镜像分发与部署要点同时可基于 prepare 脚本和 tmpl 模板做二次定制灵活调整端口、存储与证书等参数减少手工排查和试错成本。1. Harbor 离线安装包为什么内网环境必须用它在内网机房部署容器镜像仓库最头疼的不是 Harbor 本身而是它依赖的那一堆镜像——registry、nginx、postgresql、redis 全都要从 Docker Hub 拉没有外网寸步难行。harbor-offline-installer-v2.5.0-rc1.tgz 这个离线安装包把这件麻烦事一次解决了接近 600MB 的压缩包里预打包了 Harbor 2.5.0 用到的全部镜像、编排模板和安装脚本解压后不需要联网也能在 CentOS 7 上把整套服务拉起来。rc1 是候选发布版安装思路和正式版完全一致功能上没有任何缩水。它解决的不只是「装得上」还有「装得快」部署现场不用干等 docker pull 拖镜像。适合三类人政务内网的交付工程师、运维隔离区的实施人员、离线环境要搭镜像仓库的运维同学。准备在 CentOS 7 上搭建 Harbor 的话这份包是最省事的起点。2. 离线安装包的组成与原理tgz 预打包了什么2.1 离线安装包和在线安装包的差别Harbor 官方发布页会同时放两套包harbor-online-installer 和 harbor-offline-installer。在线包只有几 MB里面只有一个安装脚本和配置模板真正执行的时候现场从 Docker Hub 拉镜像离线包则把 Harbor 服务所需的全部容器镜像预打包进 tgz安装时先 docker load 再 docker-compose up。选哪个不用犹豫部署目标机只要不是能稳定访问 Docker Hub 的环境一律选 offline-installer否则 install.sh 跑到一半会卡在 docker pull 上。尤其是国内网络拉一个 registry 镜像都可能等到超时装到一半断了还得从头再来这种半拉子安装比不装还难受。离线包虽然体积大了两个数量级但换来的是确定性强镜像已经在包里tar 解压、docker load、docker-compose up三步走完不会因为网络波动出现状态不明的中间态。这套取舍逻辑放在交付场景里特别重要——现场实施最怕的就是「依赖外网」把依赖全部内嵌进安装包问题就消灭在源头。2.2 解压后的目录结构与加载原理拿到包第一件事是解压命令没有任何花活tar -xzvf harbor-offline-installer-v2.5.0-rc1.tgz cd harbor ls -lh命令参数说明-x 解压、-z 解 gzip、-v 打印解压过程、-f 指定文件。v 参数建议留着解压过程中如果某个镜像包损坏能在输出里第一时间看到 tar 报错而不是解压完才发现少文件。解压后进入 harbor 目录2.5.0-rc1 这个包里关键文件是这几个harbor.yml.tmpl 是配置模板首次安装必须先复制成 harbor.ymlinstall.sh 是安装入口prepare 是 Python 3 脚本负责校验配置并生成 docker-compose.ymlcommon.sh 是公共函数库docker 版本和 docker-compose 版本的硬性检查逻辑都在这里面。体积最大的那个 harbor.v2.5.0.tar.gz 就是核心镜像包里面合并打包了 harbor 核心、registry、nginx、postgresql、redis、jobservice、log 等组件镜像。install.sh 运行时内部做了三件事第一执行环境检查包括 docker 版本、docker-compose 版本、Python 版本第二用 prepare 脚本读取 harbor.yml生成最终的 docker-compose.yml 和 nginx 路由配置第三docker load 镜像包再用 docker-compose up -d 启动全部容器。所以「离线」两个字根本落在那个最大的 tar.gz 上它承载了整套 Harbor 的容器镜像加载完几百个镜像进入本地 Docker 之后整个安装过程就和外网完全解耦了。2.3 安装前的环境检查装之前把环境查一遍能省掉后面一半的排查时间。下面这套命令是每台新机器我都会跑的docker version docker-compose version python3 --version free -h df -h /data参数说明docker version 同时看客户端和服务端版本Harbor 2.5 官方要求 Docker 20.10 以上docker-compose 要求 1.29.2 以上python3 是给 prepare 脚本用的Harbor 2.5 的 prepare 已经迁到 Python 3CentOS 7 默认不带 python3需要先安装free 和 df 确认内存和磁盘我的经验是内存至少 4GB/data 所在分区至少留 40GB 剩余空间不然推几个镜像就会把磁盘撑爆。另外一个容易忽略的点是 hostname 解析。Harbor 2.x 要求 hostname 必须能被客户端解析到要么配 DNS要么客户端写 /etc/hosts要么直接填 IP。很多人装完 Web 页面打不开排查半天发现不是 Harbor 的问题是域名解析没通。这个细节我会在后面的参数部分专门展开。如果你担心环境不达标导致安装中断可以手动先跑一遍 common.sh 里的版本检查逻辑它会明确告诉你缺什么。但更省事的做法是提前把 docker、docker-compose、python3 全部按版本要求准备好再开始操作。3. CentOS 7 上搭建 Harbor解压、改配置、启动一条线3.1 解压与复制配置模板承接上一章的准备工作真正动手时我习惯把安装包先拷到 /opt 下面再解压避免在家目录里跑来跑去遇到权限问题。sudo mkdir -p /opt/harbor-install sudo cp harbor-offline-installer-v2.5.0-rc1.tgz /opt/harbor-install/ cd /opt/harbor-install sudo tar -xzvf harbor-offline-installer-v2.5.0-rc1.tgz命令逻辑说明cp 到 /opt 再解压是为了让后续所有操作都固定在一个干净路径下。如果你随便解压到用户家目录后面 install.sh 用 sudo 执行时可能因为目录属主问题出现奇怪的文件写权限报错那种问题最浪费时间。解压完成后进入 harbor 目录复制配置模板cd harbor cp harbor.yml.tmpl harbor.yml vim harbor.ymlcp 而不是直接改模板是为了留一份原始参考。正式环境我一般只编辑 harbor.yml改错了随时对照 harbor.yml.tmpl 恢复。vim 打开文件后能看到所有可配置项注释掉的部分都是可选功能比如 HTTPS、外部数据库、外部 Redis初装时不必动。3.2 按环境改四个关键配置最小可用配置只需要改四行hostname、harbor_admin_password、http.port、data_volume。拿一台 IP 是 192.168.10.20 的 CentOS 7 服务器举例配置长这样hostname: 192.168.10.20 http: port: 80 harbor_admin_password: Harbor.Admin123 data_volume: /data参数说明hostname 必须是客户端能访问到的地址填 IP 就填 IP填域名就必须确保 DNS 能解析否则 docker login 时证书校验会翻车。harbor_admin_password 至少八位这是初始管理员 admin 的密码首次安装时写入数据库安装完成后在 Web 界面改密码不会反向更新这个配置项。http.port 默认 80如果目标机器上已经有 nginx 或 httpd 占着 80 端口改成 8080 规避冲突。data_volume 是镜像层和数据库的落盘目录必须指向大分区默认 /data 就挺好不要图省事放根目录。3.3 执行安装脚本sudo ./install.shinstall.sh 不带参数会启动 Harbor 核心组件不装 Trivy、Chartmuseum 这些附加模块。需要镜像漏洞扫描就带上 --with-trivysudo ./install.sh --with-trivy需要 Helm Chart 仓库就追加 --with-chartmuseum。我的习惯是第一遍只装核心组件先验证登录、push、pull 都通了再补 --with-trivy。这样做的考虑是一次装太多组件出问题时分不清是哪个服务起不来日志混在一起排查效率极低。安装过程持续几分钟中途会看到 docker load 镜像的输出以及每个容器从 Created 到 Running 的状态变化。最后看到✔ ----Harbor has been installed and started successfully----这行输出就说明装成了。如果安装过程中出现红色 ERROR先别急着重跑把报错信息里提到的文件路径和服务名记下来对照第 5 章的避坑清单逐条排查。3.4 安装后的验证与日常启停sudo docker-compose ps这个命令显示所有 Harbor 容器状态。正常情况下应该看到 nginx、harbor-core、harbor-db、harbor-registry、harbor-jobservice、registryctl、redis、harbor-log 这些容器全部处于 Up 状态。只要有一个容器显示 Exited 或者 Restarting就去查对应容器日志sudo docker logs --tail 200 harbor-core日常维护里我最常用的三个命令分别是 stop、start、restart。stop 会停止所有 Harbor 容器但保留数据start 重新拉起restart 在修改配置后使用。注意 stop 和 down 的区别down 会连带删除容器虽然数据卷还在但下次启动要重新走一遍 prepare 流程所以日常维护不要随意用 down。真要彻底重置环境停掉服务后清理 data_volume 目录内容再重新执行 install.sh这个动作风险极高每次动手前我都强制自己先确认数据已经备份。4. 关键参数详解hostname、密码、端口和数据卷怎么配不返工4.1 hostname 决定访问入口更决定证书hostname 是最容易因为想当然而配错的参数。很多人图省事填 localhost结果局域网其他机器访问不了填了 IPdocker login 又报证书错误。原因在于 Harbor 内部签发的自签名证书绑定的是 hostname 对应的地址客户端 docker daemon 校验时必须用同样的地址访问并且把这个地址加进 insecure-registries 列表。如果一套 Harbor 要同时给 dev、test 两套环境用我建议用域名而不是 IP比如 registry.example.com。域名的好处是以后迁移 IP客户端不用改配置只改 DNS 解析记录。离线环境没有内部 DNS 服务器就直接填 IP简单干脆。一个需要留意的点是hostname 一旦配置好后期想改不是改个配置文件重启就能完事证书、nginx 路由、数据库里的配置都可能不一致所以首装时这个值一定要想清楚。4.2 初始管理员密码的安全设置harbor_admin_password 只在首次执行 prepare 时生效。如果你安装完成后想改 admin 密码必须到 Harbor Web UI 的个人中心改改的是数据库里的值。这里有个隐藏细节重新跑 install.sh 时它不会用 harbor.yml 里的新密码覆盖数据库所以指望改配置文件重置密码是行不通的。我的习惯是首次安装前定好强密码混合大小写字母和特殊字符然后把 harbor.yml 归档到配置管理仓库里。一旦之后在 Web 界面改过密码harbor.yml 里的旧密码就成了无效信息别人拿到配置文件也不能登录。这个细节对交付场景特别重要——甲方拿到的默认密码文档必须和实际运行时的密码一致否则就是一次交付事故。4.3 数据卷规划与外部存储data_volume 默认 /data里面分成 database、registry 等子目录。registry 目录存的是镜像层数据database 目录存的是 PostgreSQL 元数据。规划数据盘时镜像数据会随业务增长迅速膨胀我一般至少预留 100GB并单独挂一块数据盘在 /data 路径下避免和系统盘抢空间。如果要接入外部存储Harbor 2.5 支持在 registryctl 的配置里把存储后端换成 S3、Ceph RGW 等对象存储。离线内网最常见的做法是搭一套 MinIO然后修改 common/config/registry/config.yml 里的 storage 段。这个操作要提前规划清楚因为存储后端是写死在配置里的后期切换等于迁移整个镜像仓库工程量极大。有人把这种决策叫「后悔药级别的前置选择」——现在贪省事用本地磁盘数据量上来之后想换对象存储流程够你折腾半个月。4.4 HTTPS 配置与自签名证书生产环境我强烈建议打开 HTTPS。以内网 IP 192.168.10.20 为例先生成自签名证书mkdir -p /data/cert cd /data/cert openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 365 -out ca.crt -subj /CN192.168.10.20 openssl req -newkey rsa:4096 -nodes -sha256 -keyout server.key -out server.csr -subj /CN192.168.10.20 openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365命令参数说明第一条生成自签名根证书CN 必须和 harbor.yml 里的 hostname 完全一致否则证书校验不通过第二条生成服务端私钥和证书签名请求第三条用根证书给服务端证书签名-days 365 表示有效期一年。内网环境证书有效期到了要记得重新签发我见过有人把有效期设成 825 天结果到期日正好赶上节假日整个镜像仓库不能登录教训相当深刻。然后在 harbor.yml 里打开 HTTPS 配置https: port: 443 certificate: /data/cert/server.crt private_key: /data/cert/server.key还要处理客户端侧所有需要 push/pull 镜像的机器都得把这个 ca.crt 装进系统信任库或者在 /etc/docker/daemon.json 里加 insecure-registries。前者是正路后者是绕路但内网环境绕路最省事具体做法我在避坑章节详细写。4.5 常见配置错误速查改参数配错时最容易出现三种现象。第一修改 harbor.yml 后直接 docker-compose restart配置不生效——正确操作是重新执行 sudo ./install.sh它会重新运行 prepare 并重建配置关联的容器。第二改了 http.port 后 nginx 一直重启多半是端口冲突或防火墙拦截用 ss -lntp 看端口占用。第三hostname 填了域名但没配 /etc/hosts表现为 Web 页面打不开而所有容器都是 Up 状态。这三条我基本每次都踩过提前写在这里各位安装时对照自查能少走弯路。/data/cert 目录权限也要注意Harbor 的 nginx 容器以非 root 用户运行证书私钥不能设置成 600 只允许 root 读否则容器内进程读不到证书会反复重启。5. 避坑离线安装最容易翻车的五个点5.1 docker-compose 版本过低install.sh 直接拒绝执行现象CentOS 7 上用 yum 装的 docker-compose 是 1.18.0跑 ./install.sh 时输出docker-compose version is too low, need 1.29.2 or higher然后退出。原因Harbor 2.5 的编排文件用了新版本 compose 语法官方在 common.sh 里做硬性版本检查低于 1.29.2 直接拒绝继续执行不给任何商量余地。解决在有网的机器上下载 docker-compose 2.x 二进制拷贝进内网替换sudo mv /usr/local/bin/docker-compose /usr/local/bin/docker-compose.bak sudo cp docker-compose-linux-x86_64 /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose docker-compose version命令逻辑说明第一步备份旧文件以防回滚第二步把新二进制放到 PATH 下第三步加执行权限。特别注意旧文件要备份而不是删除万一新版 compose 和当前 Docker 版本存在兼容问题一条 mv 命令就能切回旧版本。这个习惯是从一次线上事故里学来的那次的教训就是升级工具前没留后路。5.2 CentOS 7 缺 python3prepare 脚本直接崩现象环境检查全部通过install.sh 跑到 prepare 阶段报python3: command not found或者报No module named yaml。原因CentOS 7 默认只带 Python 2.7而 Harbor 2.5 的 prepare 脚本是 Python 3 写的而且依赖 pyyaml 库。操作系统运行环境和 Harbor 的要求之间存在断层这是 CentOS 7 上部署 Harbor 的一个隐蔽前置条件。解决先装 python3再装 pip 依赖sudo yum install -y python3 python3-pip sudo pip3 install pyyaml装完重新执行 sudo ./install.sh 即可。如果你在准备基础镜像或交付模板建议直接把 python3 和 pyyaml 预装进去省得每台机器都单独处理一遍。这个问题本质上不是 Harbor 的 bug是 CentOS 7 系统环境和 Harbor 2.x 之间的适配问题提前装好能让安装过程顺很多。5.3 SELinux 拦截postgres 和 registry 反复重启现象docker-compose ps 里 harbor-db 或 harbor-registry 处于 Restarting 状态docker logs 报Permission denied或者mkdir /data/database: permission denied但用 ls 检查目录归属怎么看都正常。原因CentOS 7 默认 SELinux 处于 enforcing 模式容器挂载宿主机目录需要放行对应的 SELinux 类型否则容器内进程写不进去。这种问题用常规权限检查根本看不出来极具迷惑性。解决先用临时关闭 SELinux 的方式验证是不是它的锅sudo setenforce 0重启 Harbor 服务后恢复正常那基本可以判定是 SELinux 拦截。生产环境我一般用 chcon 给数据目录打上容器专用标签这样能保持 SELinux 开启状态兼顾安全性和运行稳定性sudo chcon -R -t svirt_sandbox_file_t /data两种方式的差别setenforce 0 是全局放行机器重启后恢复 enforcing适合快速自查chcon 是针对 /data 的精准放行能够维持 SELinux 开启状态适合生产环境长期运行。注意 chcon 的标签类型要写对写错容器一样起不来。5.4 docker login 报 x509 证书错误不是密码错现象安装完成后执行 docker login 192.168.10.20报x509: certificate signed by unknown authority密码明明是对的。原因Harbor 默认用 HTTPS 启动自签名证书不被 docker daemon 信任。docker daemon 优先走 HTTPS所以即便是 Harbor 配置成 HTTP客户端默认行为也会指向 HTTPS 并报证书错误这个现象把很多人绕晕过。解决在客户机的 /etc/docker/daemon.json 里配置 insecure-registries{ insecure-registries: [192.168.10.20] }然后重启 docker 服务sudo systemctl restart docker注意两点第一重启 docker 会导致该机器上所有容器重启如果有正在跑业务必须选在窗口期操作第二insecure-registries 填的是客户端视角的访问地址不是 Harbor 服务器的出口 IP填反了照样报错。凡是 install.sh 执行成功后 docker login 失败的情况我都优先检查 daemon.json 而不是怀疑密码这是排查顺序的问题按这个顺序基本一次命中。5.5 磁盘空间和 inode 双耗尽push 镜像无声失败现象push 镜像到一半报no space left on device但 df -h 看分区剩余还有几个 GB更隐蔽的是推送超时日志里没有任何明确报错。原因镜像层文件小而多inode 可能先于容量耗尽。df -h 只查容量df -i 才能查到 inode 使用率。容量看着够inode 满了一样写不进文件错误信息还特别容易误导人。解决两个命令一起看df -h /data df -i /data确认是 inode 耗尽后清理 registry 里废弃的镜像。推荐用 Harbor 自带的垃圾回收功能系统管理 → 垃圾清理跑一遍能释放大量 inode。容量和 inode 双维度检查是我每次排磁盘问题时的固定动作只查 df -h 不看 df -i等于只检查了一半很容易被剩余容量骗过去。另外建议数据盘选 XFS 而不是 ext4XFS 对大量小文件的 inode 分配策略更友好。6. 进阶验证、备份、镜像迁移的几条实测路线6.1 安装后的一次完整验证装完不能只看容器都是 Up 就撒手。我有一套固定流程先 curl API 探测再 docker login最后 push 一个真实镜像走通全链路。curl -k https://192.168.10.20/api/v2.0/ping返回 Pong 说明核心 API 通了。然后再走一遍业务链路docker login 192.168.10.20 -u admin -p Harbor.Admin123 docker tag nginx:1.21 192.168.10.20/library/nginx:1.21 docker push 192.168.10.20/library/nginx:1.21 docker pull 192.168.10.20/library/nginx:1.21login 通过、push 成功、pull 回来能运行这一套走完才算交付完成。library 是 Harbor 自带的公开项目测试阶段用它最合适不会污染正式项目空间。6.2 离线环境备份数据库与镜像层分开备Harbor 的元数据全部在 PostgreSQL 里镜像层数据在 registry 存储目录里。我的备份方案分两条线数据库用 pg_dump 逻辑备份镜像层直接文件同步docker exec harbor-db pg_dump -U postgres registry -c registry_$(date %F).sql参数说明harbor-db 是 Harbor 2.5 中 postgres 容器名-U postgres 指定超级用户registry 是 Harbor 元数据库名-c 生成带 DROP 的建表语句方便恢复时重建。镜像数据直接 rsync /data/registry 目录。一个关键细节rsync 前先把 Harbor 停掉防止写到一半的镜像层文件被拷走产生损坏备份。备份文件务必放到独立磁盘或 NFS 挂载点放在同一块盘上等于没备份这是最朴素的道理。6.3 跨仓库迁移skopeo 比 docker save 更稳离线环境里把镜像从一个 Harbor 迁到另一个 Harbor我优先用 skopeo。它能直接跨 registry 复制 manifest 和镜像层不经过本地 docker daemon速度更快也不会把本地磁盘塞满skopeo copy --src-tls-verifyfalse --dest-tls-verifyfalse \ docker://192.168.10.20/library/nginx:1.21 \ docker://192.168.11.30/library/nginx:1.21--src-tls-verifyfalse 和 --dest-tls-verifyfalse 用于跳过两侧自签名证书校验内网环境必须带。如果目标机器没有 skopeo退而求其次用 docker save 加 docker loaddocker save 192.168.10.20/library/nginx:1.21 -o nginx-1.21.tar docker load -i nginx-1.21.tar docker tag 192.168.10.20/library/nginx:1.21 192.168.11.30/library/nginx:1.21 docker push 192.168.11.30/library/nginx:1.21save、load、tag、push 四个动作对应完整链路。save 方式要求本地磁盘能装下整个镜像大镜像时不推荐skopeo 仍是首选。从那以后我每次交付一套 Harbor都强制自己走一遍「API 探测 → login → push → pull → 记录版本」五步顺手把数据库导出一份放到独立磁盘。这套流程麻烦归麻烦但确实在好几次迁移事故里保住了整套镜像仓库。希望帮到你。本文还有配套的精品资源点击获取