简介:本资源为 Harbor 容器镜像仓库 v2.5.0-rc1 版本的离线安装包,面向 DevOps 工程师、容器平台运维人员及 Kubernetes 生态实践者,用于在无外网或受限网络环境中快速部署企业级镜像管理服务。压缩包共6个文件,含2个核心Shell脚本(install.sh、common.sh)负责自动化安装与环境准备,1个prepare工具用于生成配置与加载镜像,1个harbor.yml.tmpl模板文件支持灵活定制化配置,1个LICENSE协议文件及1个内嵌harbor.v2.5.0.tar.gz镜像归档,整体体积达623.92MB,确保所有依赖组件开箱即用。目前已有258人学习下载,适合需落地私有镜像仓库、开展CI/CD集成或进行Harbor高可用架构预研的技术人员。用户可直接解压执行安装流程,获得完整可运行的Harbor服务实例,并基于模板快速适配生产环境参数。
1. Harbor 离线安装包 v2.5.0-rc1:不是“下完就能装”的压缩包,而是需要你亲手校准环境、剥离依赖、验证签名的生产级部署起点
你手头这个harbor-offline-installer-v2.5.0-rc1.tgz,不是 Docker Hub 上随手docker pull的镜像,也不是一键图形化安装器。它是 Harbor 官方为高安全、强隔离场景(比如金融内网、政务专网、军工仿真环境)专门打包的离线部署套件——所有组件二进制、容器镜像、配置模板、证书工具、甚至 PostgreSQL 和 Redis 的预编译二进制,全被打包进一个.tgz里。它不联网下载任何东西,但也不自动适配你的操作系统内核、SELinux 策略、firewalld 规则或已存在的 Docker Socket 权限。我去年在某高校实验室部署时,就因跳过校验步骤,导致 Harbor Portal 页面白屏 3 小时,最后发现是core容器启动时读取/data/secret/core/private_key.pem权限被umask 0027拦截。这不是 bug,是设计:Harbor 离线包把“可控性”交还给你,代价是你得亲手拧紧每一颗螺丝。适合谁?运维工程师、信创项目交付人员、等保三级系统实施者——你不需要会写 Go,但必须清楚systemd如何接管容器进程、docker-compose的--env-file加载顺序、以及prepare脚本里哪一行真正生成了registryctl的 TLS 配置。别急着解压,先确认你的 CentOS 7.9 内核 ≥ 3.10.0-1160,或 Ubuntu 20.04 的systemd版本 ≥ 245。
2. 解压即启动?不,先做三件事:校验完整性、检查宿主机约束、理解 prepare 脚本的执行边界
Harbor 离线包不是“绿色软件”,它的可靠性建立在你对三个前置动作的严格执行上。跳过任意一项,后续./install.sh报错时你会陷入黑匣子——错误日志只说failed to start core service,但根本原因可能是prepare生成的common/config/core/env文件里CORE_SECRET变量为空,而空值又源于你宿主机/dev/urandom读取失败(某些国产 OS 内核模块限制)。下面这三步,我每次部署都强制手敲命令并截图存档,不是仪式感,是后悔药。
2.1 校验 SHA256 与 GPG 签名:为什么连官网下载页都可能被中间劫持
Harbor 官方发布页(harbor.github.io)会提供harbor-offline-installer-v2.5.0-rc1.tgz.sha256和harbor-offline-installer-v2.5.0-rc1.tgz.asc。但注意:.asc是 GPG 签名文件,不是公钥。你需要先导入 Harbor Release Team 的公钥(key IDD83E2A5F),再验证:
# 下载公钥(从可信密钥服务器) gpg --keyserver hkps://keys.openpgp.org --recv-keys D83E2A5F # 验证签名(必须用 .asc 文件,不是 .sig) gpg --verify harbor-offline-installer-v2.5.0-rc1.tgz.asc harbor-offline-installer-v2.5.0-rc1.tgz # 同时校验 SHA256(防止哈希碰撞) sha256sum -c harbor-offline-installer-v2.5.0-rc1.tgz.sha256提示:如果
gpg --verify显示BAD signature,常见原因是下载的.asc文件末尾多了换行符(Windows 编辑器保存导致)。用dos2unix harbor-offline-installer-v2.5.0-rc1.tgz.asc修复后再试。GPG 验证失败必须中止,这是离线部署的底线——你无法在断网环境下回滚到“更干净”的版本。
2.2 宿主机硬性约束检查:不是“支持 Linux”,而是具体到 cgroup v1/v2 和 overlay2
Harbor v2.5.0-rc1 的prepare脚本默认启用--with-trivy和--with-notary,这意味着它会拉起 8+ 个容器。你的宿主机必须满足:
| 检查项 | 命令 | 合格标准 | 不合格后果 |
|---|---|---|---|
| cgroup 版本 | stat -fc %T /sys/fs/cgroup | 输出cgroup2fs(v2)或cgroup(v1) | v2 模式下若内核未开启systemd.unified_cgroup_hierarchy=1,registry容器会 OOM kill |
| 存储驱动 | docker info | grep "Storage Driver" | 必须为overlay2(aufs已废弃) | registry启动后立即退出,日志显示failed to mount layer |
| SELinux 状态 | getenforce | 必须为Permissive或Disabled(Enforcing会导致core容器无法绑定 8080 端口) | install.sh运行成功,但curl http://localhost/api/v2.0/ping返回connection refused |
验证脚本可直接复用(保存为check-host.sh):
#!/bin/bash # 检查 cgroup if [[ $(stat -fc %T /sys/fs/cgroup) == "cgroup2fs" ]]; then echo "[OK] cgroup v2 detected" if ! grep -q "systemd.unified_cgroup_hierarchy=1" /proc/cmdline; then echo "[WARN] cgroup v2 requires systemd.unified_cgroup_hierarchy=1 in kernel cmdline" fi else echo "[OK] cgroup v1 detected" fi # 检查 overlay2 if docker info 2>/dev/null | grep -q "Storage Driver: overlay2"; then echo "[OK] overlay2 storage driver active" else echo "[ERROR] overlay2 not active. Run: sudo modprobe overlay && echo 'overlay' >> /etc/modules" exit 1 fi # 检查 SELinux if [[ $(getenforce) == "Enforcing" ]]; then echo "[ERROR] SELinux Enforcing blocks Harbor ports. Set to Permissive: sudo setenforce 0" exit 1 fi2.3prepare脚本的真相:它不生成最终配置,只生成“可被 install.sh 消费的中间态”
很多开发者误以为./prepare执行完就万事大吉,其实它只是install.sh的前置编译器。它干三件事:
- 解压
harbor.v2.5.0-rc1.tar.gz(内含所有镜像)到./images/目录; - 根据
harbor.yml模板生成common/config/下各服务的配置文件(如core/env,registry/config.yml); - 生成 TLS 证书(若
harbor.yml中https开启)和密钥对(/data/secret/)。
关键点在于:prepare不会校验harbor.yml里的hostname是否能被 DNS 解析,也不会检查data_volume路径是否有 20GB 可用空间。它只做文本替换和文件拷贝。所以prepare成功 ≠ 配置正确。我见过最典型的翻车是:harbor.yml中hostname: harbor.internal,但/etc/hosts未添加127.0.0.1 harbor.internal,导致core容器启动后反复重试连接https://harbor.internal/api/v2.0/health超时,最终自毁。
3. 安装流程拆解:从install.sh到docker-compose up,每一步的参数含义与可干预点
install.sh表面是黑盒脚本,实则是docker-compose的封装层。它的核心逻辑是:读取harbor.yml→ 调用prepare→ 生成docker-compose.yml→ 执行docker-compose up -d。但你可以且应该干预其中三处关键节点,否则遇到问题只能删库重来。
3.1install.sh的隐藏参数:--with-notary和--with-trivy不是开关,而是镜像加载开关
install.sh默认只加载core,portal,registry,redis,postgresql五个基础服务。当你加--with-notary时,它实际执行的是:
# 在 prepare 阶段,从 harbor.v2.5.0-rc1.tar.gz 中解压出 notary-server 和 notary-signer 镜像 tar -xzf harbor.v2.5.0-rc1.tar.gz -C ./images/ --wildcards 'notary-*' # 并在生成的 docker-compose.yml 中取消注释以下 services: # notary-server: # image: goharbor/notary-server-photon:v2.5.0-rc1 # notary-signer: # image: goharbor/notary-signer-photon:v2.5.0-rc1同理,--with-trivy会解压trivy-adapter-photon:v2.5.0-rc1镜像并启用trivy-adapterservice。注意:--with-notary会额外占用 1.2GB 磁盘(Notary 数据库存储),且要求postgresql的max_connections≥ 200(默认 100),否则notary-server启动失败。解决方案是在harbor.yml中显式设置:
database: max_idle_conns: 50 max_open_conns: 200 # ← 必须手动加这一行3.2docker-compose.yml的生成逻辑:prepare输出的文件才是真实配置源
install.sh最终调用docker-compose -f ./common/docker-compose.yml up -d。但这个./common/docker-compose.yml是prepare动态生成的,不是源码包里的静态文件。它的关键字段来源如下:
docker-compose.yml字段 | 来源 | 可修改方式 |
|---|---|---|
services.core.environment.HARBOR_ADMIN_PASSWORD | harbor.yml中harbor_admin_password | 直接改harbor.yml,重新./prepare |
services.registry.volumes[0](即/data/registry) | harbor.yml中data_volume | 必须在harbor.yml中设绝对路径,如/opt/harbor/data |
services.core.depends_on.postgresql.condition | 固定为service_healthy | 无法修改,但可检查postgresql的 healthcheck 是否通过:docker-compose exec postgresql pg_isready -U postgres |
注意:不要手动编辑
./common/docker-compose.yml!它每次./prepare都会被覆盖。所有定制必须回到harbor.yml—— 这是 Harbor 离线包的设计契约。
3.3install.sh执行后的状态验证:别只看Creating network... done,要看容器日志链
install.sh输出✔ ----Harbor has been installed and started successfully.----只代表docker-compose up -d命令返回 0,不代表所有容器健康。必须立刻验证:
# 1. 检查所有容器是否 Up 状态(非 Restarting/Exited) docker-compose ps | awk '$4 !~ /Up/ {print $0}' # 2. 检查核心服务日志是否有 fatal 错误(重点看 core, registry, portal) docker-compose logs core 2>&1 | grep -i "fatal\|panic\|failed to" # 3. 验证 API 可达性(用 curl,不用浏览器,绕过 DNS 缓存) curl -k -I https://localhost/api/v2.0/ping # 应返回 HTTP/2 200 curl -k http://localhost/api/v2.0/systeminfo # 应返回 JSON,含 "harbor_version": "v2.5.0-rc1"如果curl -k https://localhost/api/v2.0/ping超时,90% 是core容器未就绪。此时docker-compose logs core通常会暴露真实原因,例如:
2023-04-12T08:23:41Z [FATAL] [/core/main.go:180]: failed to initialize the system: failed to migrate: dial tcp 172.19.0.2:5432: connect: connection refused这表示postgresql容器没起来,需查docker-compose logs postgresql,大概率是/data/database目录权限不对(应为10000:10000,即postgres用户 UID/GID)。
4. 避坑指南:五个血泪经验总结的高频故障点与根因定位法
Harbor 离线部署的坑,90% 集中在环境假设与配置脱节。以下是我在 12 个不同客户现场踩出的共性问题,按现象→原因→解决三段式整理,拒绝模糊描述。
4.1 现象:install.sh执行卡在Preparing environment ...,10 分钟无响应
原因:prepare脚本内部调用openssl req生成证书时,阻塞在/dev/random读取熵值。某些精简版 OS(如部分国产发行版)的熵池长期低于 100 bit,openssl默认等待足够熵。
解决:
- 临时补充熵:
sudo rng-tools -r /dev/urandom(需先yum install rng-tools) - 或修改
prepare脚本:找到gen_cert.sh中openssl req -x509 -nodes ...行,在末尾加-rand /dev/urandom - 预防:在
harbor.yml中关闭 HTTPS(https: false),用反向代理终结 TLS,避免本地生成证书。
4.2 现象:docker-compose ps显示registry状态为Restarting (1),日志循环输出failed to mount layer
原因:overlay2存储驱动未正确挂载。docker info显示Storage Driver: overlay2,但/var/lib/docker/overlay2目录实际是ext4文件系统,且未启用d_type=true。
解决:
- 卸载并重新挂载:
sudo umount /var/lib/docker && sudo mount -t ext4 -o d_type=true /dev/sdb1 /var/lib/docker - 永久生效:在
/etc/fstab中对应行添加d_type=true参数 - 重启 Docker:
sudo systemctl restart docker
4.3 现象:curl http://localhost/api/v2.0/ping返回200,但网页登录时提示Internal Server Error,core日志出现failed to get user info: pq: password authentication failed for user "harbor_user"
原因:postgresql容器启动时,/data/database目录存在旧数据(如上次安装残留),导致初始化 SQL 脚本未执行,harbor_user密码仍是默认空值。
解决:
- 彻底清理:
sudo rm -rf /data/database /data/redis /data/registry - 删除
common/config/下所有env文件(强制prepare重生成) - 重新
./prepare→./install.sh
4.4 现象:启用--with-trivy后,扫描任务始终卡在Scheduled,trivy-adapter日志显示failed to connect to redis: dial tcp 172.19.0.3:6379: connect: connection refused
原因:trivy-adapter服务在docker-compose.yml中依赖redis,但redis容器的healthcheck脚本(redis-cli ping)因requirepass密码未配置而失败,导致trivy-adapter等待超时。
解决:
- 在
harbor.yml中显式设置redis.password(不能留空) - 确保
redis的healthcheck命令包含密码:redis-cli -a YOUR_PASSWORD ping(此行在prepare生成的docker-compose.yml中已自动注入,前提是harbor.yml有password字段)
4.5 现象:harbor.yml中hostname: harbor.example.com,但curl -k https://harbor.example.com/api/v2.0/ping失败,而curl -k https://localhost/api/v2.0/ping成功
原因:core容器内的core进程绑定的是0.0.0.0:8080,但portal容器的前端 JS 代码中硬编码了API_BASE_PATH = "https://harbor.example.com/api/v2.0"。当浏览器访问harbor.example.com时,JS 发起跨域请求,而core服务未配置Access-Control-Allow-Origin。
解决:
- 在
harbor.yml中添加https配置块,并确保certificate和private_key路径正确 - 或在反向代理(如 Nginx)中添加 CORS 头:
add_header 'Access-Control-Allow-Origin' '*' - 根本解法:让
hostname与实际访问域名严格一致,避免前端跨域。
5. 进阶技巧:如何用docker-compose命令精准控制单个服务生命周期,实现零停机升级与配置热重载
Harbor 离线包的install.sh是“全有或全无”式部署,但生产环境常需灰度升级core或热更新registry配置。这时必须绕过install.sh,直接操作docker-compose.yml。我总结了一套最小侵入式操作法,已在某金融客户连续使用 18 个月无故障。
5.1 精准重启单个服务:core配置变更后,无需重启全部容器
core服务的配置文件是common/config/core/app.conf(由harbor.yml生成)。当你修改harbor.yml中的log_level后,只需:
# 1. 重新生成 core 配置(不碰其他服务) ./prepare --with-notary --with-trivy # 保持原有选项 # 2. 仅重启 core 容器(不重启 postgresql/redis,避免连接中断) docker-compose up -d --no-deps --force-recreate core # 3. 验证 core 是否加载新配置(检查日志是否输出新 log_level) docker-compose logs core | tail -n 20 | grep "log level"原理:
--no-deps跳过依赖服务(如postgresql,redis),--force-recreate强制重建容器并挂载最新app.conf。core容器启动时会读取挂载的配置文件,无需重启数据库。
5.2registry配置热重载:不用重启容器,动态更新镜像垃圾回收策略
registry的主配置是common/config/registry/config.yml。Harbor v2.5.0-rc1 支持 SIGHUP 信号触发配置重载。步骤如下:
# 1. 修改 common/config/registry/config.yml(例如调整 gc 的 schedule) # 2. 找到 registry 容器 ID REGISTRY_ID=$(docker-compose ps -q registry) # 3. 发送 SIGHUP(registry 进程会 reload config.yml) docker kill -s HUP $REGISTRY_ID # 4. 验证是否生效(查看 registry 日志是否有 "reloaded configuration") docker-compose logs registry | grep "reloaded configuration"注意:此操作要求
registry镜像版本 ≥ v2.7.1(Harbor v2.5.0-rc1 自带的是 v2.7.1,满足条件)。若日志无 reload 提示,说明config.yml语法错误,用yamllint检查。
5.3 零停机升级 Harbor 版本:用docker-compose的--project-name实现双轨运行
当需从 v2.5.0-rc1 升级到正式版 v2.5.0 时,可并行运行两套 Harbor,用 Nginx 流量切分。关键在--project-name隔离网络和卷:
# 1. 解压新版本离线包到 /opt/harbor-v2.5.0/ tar -xzf harbor-offline-installer-v2.5.0.tgz -C /opt/harbor-v2.5.0/ # 2. 修改其 harbor.yml 的 hostname 为 harbor-v250.example.com # 3. 生成新 compose 文件(指定独立 project 名) cd /opt/harbor-v2.5.0 && ./prepare && \ docker-compose --project-name harbor_v250 up -d # 4. 此时两个 Harbor 共存: # - harbor_v250_network(独立桥接网络) # - /data/v250/registry(独立数据卷) # 5. Nginx 配置按 Host 头分流: # server_name harbor.example.com; → proxy_pass http://harbor_v250; # server_name harbor-v250.example.com; → proxy_pass http://harbor_v250;5.4 故障快速回滚:备份common/config/比备份整个/data/更高效
/data/目录含镜像层(GB 级),备份慢且冗余。真正需要备份的是common/config/下的配置快照,它记录了所有服务的运行时状态:
| 目录 | 作用 | 备份频率 | 恢复命令 |
|---|---|---|---|
common/config/core/env | core服务环境变量(含数据库密码 hash) | 每次./prepare后 | cp -r /backup/core-env-20230412 ./common/config/core/env |
common/config/registry/config.yml | Registry 镜像存储策略 | 配置变更后 | cp /backup/registry-config.yml ./common/config/registry/config.yml |
common/config/portal/nginx.conf | Portal 前端路由规则 | 极少变更 | cp /backup/nginx.conf ./common/config/portal/nginx.conf |
我的习惯:每次
./prepare前,自动执行tar -czf /backup/harbor-config-$(date +%Y%m%d-%H%M%S).tar.gz ./common/config/。从那以后我每次升级前都强制走一遍这个备份,哪怕多花 3 秒。因为一次rm -rf /data/的代价,是 4 小时重建私有镜像仓库。希望帮到你。
本文还有配套的精品资源,点击获取