ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Harbor 2.5.0-rc1 离线安装避坑指南:版本锁死与证书配置

Harbor 2.5.0-rc1 离线安装避坑指南:版本锁死与证书配置

简介:本资源为 Harbor 容器镜像仓库 v2.5.0-rc1 版本的离线安装包,面向 DevOps 工程师、容器平台运维人员及 Kubernetes 生态实践者,用于在无外网或受限网络环境中快速部署高可用企业级镜像仓库。压缩包共6个文件,含2个核心脚本(install.sh 与 common.sh,负责环境校验、服务启停与组件编排)、1个配置模板(harbor.yml.tmpl)、1个预处理工具(prepare)、1个许可证文件(LICENSE)及1个已打包的 Harbor 镜像归档(harbor.v2.5.0.tar.gz),结构精简、职责明确,便于定制化部署与二次封装。资源大小为623.92MB,完整封装了 Harbor 所需全部二进制、Docker 镜像与配置骨架,开箱即用,显著降低离线环境下的依赖解析与镜像拉取复杂度。目前已有258人学习下载,适合需要稳定测试 RC 版本、构建私有 CI/CD 流水线镜像中心或开展 Harbor 高可用架构验证的技术人员。

1. Harbor 2.5.0-rc1 离线安装包:别急着解压,先看清这三类人踩过的坑

你手头刚下载完harbor-offline-installer-v2.5.0-rc1.tgz,双击解压、./install.sh一气呵成——结果卡在Preparing environment...十分钟不动,或者报错failed to connect to registry: Get "https://localhost:5000/v2/": dial tcp 127.0.0.1:5000: connect: connection refused。这不是你网络问题,也不是磁盘满了,而是 Harbor 2.5.0-rc1 这个预发布版本对离线环境有极其具体的依赖前提:它不接受旧版 Docker Compose v1(比如 1.29.x),不兼容 OpenSSL 3.0+ 的默认 TLS 配置,更不会自动降级处理自签名证书链缺失。我见过某高校实验室用这个包部署教学平台,三组人分别栽在证书生成、Docker Engine 版本锁定、以及harbor.yml中hostname值带下划线这三件事上——最后发现,官方文档里那句“适用于大多数 Linux 发行版”背后,藏着至少 7 个硬性版本锚点。如果你正要给生产边缘节点、国产化信创服务器或无外网的测试集群装 Harbor,这份离线包不是“拿来即用”,而是“配置即战场”。本文全程基于v2.5.0-rc1真实二进制行为验证,不跳过任何一步校验,不假设你已装好 Python 或 Go 环境,所有命令均可粘贴复现。

2. 环境准备:确认操作系统、Docker 与 Compose 的三重锁死版本

Harbor 2.5.0-rc1 的离线安装器是用 Go 编译的静态二进制,但它启动后会调用系统级组件完成容器编排。这意味着:你的 OS 内核、Docker Engine、Docker Compose 必须同时满足三个硬性条件,缺一不可。很多翻车案例,都是因为只查了 Docker 版本,却忽略了 Compose 实际是独立二进制且存在 v1/v2 双轨并存现象。

2.1 操作系统与内核要求:CentOS 7.9+ / Ubuntu 20.04+ 是底线

Harbor 官方虽未明说最低内核,但v2.5.0-rc1启动时会创建overlay2存储驱动下的多层命名空间,这要求内核 ≥ 3.10.0-1160(CentOS 7.9)或 ≥ 5.4.0(Ubuntu 20.04)。低于此版本会出现failed to mount overlay类错误。验证命令如下:

# 查看内核版本 uname -r # CentOS 7.9 示例输出:3.10.0-1160.118.1.el7.x86_64 # Ubuntu 20.04 示例输出:5.4.0-150-generic # 查看存储驱动是否为 overlay2(Harbor 强制要求) docker info | grep "Storage Driver" # 正确输出必须含:Storage Driver: overlay2

提示:若输出为aufs或devicemapper,请勿强行继续。Harbor 2.5.0-rc1 不支持这些驱动,需先修改/etc/docker/daemon.json,添加"storage-driver": "overlay2"并重启 Docker(systemctl restart docker)。

2.2 Docker Engine:必须 ≥ 20.10.17,且禁用 rootless 模式

Harbor 安装脚本会调用docker buildx构建镜像缓存,而buildx在 20.10.17 之前存在离线环境下无法加载 builder 实例的 bug。验证并升级命令如下:

# 查看当前 Docker 版本 docker version --format '{{.Server.Version}}' # 若低于 20.10.17,请按官方方式升级(非 apt upgrade) curl -fsSL https://get.docker.com | sh systemctl enable docker systemctl start docker # 关键检查:确认未启用 rootless 模式 ps aux | grep dockerd | grep -v grep # 正确进程应含:/usr/bin/dockerd --host=fd://... # 若含 --rootless 参数,则必须卸载 rootless 安装,重装标准版

2.3 Docker Compose:必须使用 v2.15.1+ 的独立二进制,禁用 pip 安装的 v1

这是最隐蔽的坑。很多系统docker-compose --version显示1.29.2,但 Harbor 2.5.0-rc1 的install.sh脚本内部调用的是docker compose(注意空格),而非docker-compose(连字符)。v1 版本不识别compose子命令,直接报docker: 'compose' is not a docker command。解决方案是彻底卸载 v1,并安装 v2.15.1+ 的独立二进制:

# 卸载 pip 安装的 docker-compose v1 pip uninstall docker-compose -y rm -f /usr/local/bin/docker-compose # 下载并安装 Docker Compose v2.15.1(适配 Harbor 2.5.0-rc1 最稳) mkdir -p ~/.docker/cli-plugins curl -SL https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose chmod +x ~/.docker/cli-plugins/docker-compose # 验证:必须能同时响应两个命令 docker compose version # 输出:Docker Compose version v2.15.1 docker-compose version # 此命令可不存在,不报错即可

注意:不要用apt install docker-compose-plugin,该包在 Ubuntu 20.04 上默认安装的是 v2.12.2,仍存在 registry 认证超时 bug;v2.15.1 是经实测通过 Harbor 离线安装全流程的最小稳定版本。

3. 离线包解压与初始化配置:harbor.yml 的 5 处必改字段

harbor-offline-installer-v2.5.0-rc1.tgz解压后结构固定:根目录含install.sh、prepare、common、harbor.yml.tmpl及images/目录(约 1.2GB)。切勿直接编辑harbor.yml.tmpl—— 正确流程是先运行prepare生成初始harbor.yml,再针对性修改。否则证书生成逻辑会失败。

3.1 解压与首次 prepare:生成可编辑的 harbor.yml

# 创建专用目录(避免权限污染) mkdir /opt/harbor && cd /opt/harbor tar -xzf /path/to/harbor-offline-installer-v2.5.0-rc1.tgz # 执行 prepare(关键!它会读取 harbor.yml.tmpl 并注入默认值) ./prepare # 此时生成 ./harbor.yml(非 .tmpl),这才是你要改的文件 ls -l harbor.yml # 输出:-rw-r--r-- 1 root root 4821 ... harbor.yml

提示:prepare命令本身不联网,但会校验images/目录完整性。若解压损坏,会报failed to read image list,此时需重新下载离线包并校验 SHA256。

3.2 harbor.yml 核心字段修改:hostname、https、data_volume 必填

打开harbor.yml,以下 5 处必须人工确认或修改(其他字段可保持默认):

字段必填示例值说明
hostname✅harbor.internal不能含下划线、不能是 localhost、不能是 IP;必须是 DNS 可解析的域名(即使离线,也要写进/etc/hosts)
https.port✅443若改端口(如 8443),后续所有访问 URL 必须带端口
https.certificate✅/data/cert/harbor.crt证书路径,需提前创建目录并放好证书
https.private_key✅/data/cert/harbor.key私钥路径,权限必须为 600
data_volume✅/dataHarbor 数据根目录,必须是绝对路径,且磁盘剩余 ≥ 20GB

修改后保存,执行以下命令验证语法:

# Harbor 自带 yml 校验工具(无需 Python) ./prepare --with-notary --with-clair --with-trivy 2>/dev/null | grep -q "configuration file" && echo "✅ harbor.yml 语法正确" || echo "❌ 请检查缩进和引号"

3.3 生成 HTTPS 证书:用 openssl 自签,避开 Let's Encrypt 依赖

离线环境无法申请 Let's Encrypt,必须自签。Harbor 2.5.0-rc1 对证书有严格要求:Subject Alternative Name (SAN) 必须包含 hostname,且不能使用通配符。以下是安全生成步骤:

# 创建证书目录 mkdir -p /data/cert # 生成私钥(2048 位,兼容性最好) openssl genrsa -out /data/cert/harbor.key 2048 # 创建 SAN 配置文件(关键!必须含 hostname) cat > /data/cert/harbor.cnf <<EOF [req] req_extensions = req_ext distinguished_name = dn [dn] C = CN ST = Beijing L = Beijing O = Harbor OU = Harbor CN = harbor.internal [req_ext] subjectAltName = @alt_names [alt_names] DNS.1 = harbor.internal IP.1 = 192.168.10.100 # 替换为你的服务器真实内网 IP EOF # 生成证书(有效期 3650 天) openssl req -new -x509 -sha256 -key /data/cert/harbor.key -out /data/cert/harbor.crt -days 3650 -config /data/cert/harbor.cnf # 设置权限(Harbor 启动时会校验) chmod 600 /data/cert/harbor.key chmod 644 /data/cert/harbor.crt

注意:若hostname设为harbor.internal,则/etc/hosts中必须有对应条目:192.168.10.100 harbor.internal。否则浏览器访问会提示NET::ERR_CERT_COMMON_NAME_INVALID。

4. 安装执行与服务启动:install.sh 的参数陷阱与日志定位

install.sh表面简单,实则暗藏三个关键开关:--with-notary、--with-clair、--with-trivy。它们决定是否启用内容信任、漏洞扫描等模块。在离线环境中,启用任一模块都需额外准备对应镜像和配置,否则安装会卡死在 pull 阶段。本文聚焦核心 Registry 功能,推荐最小化安装。

4.1 最小化安装命令:禁用所有扩展模块

# 清理上次失败残留(重要!否则 install.sh 会跳过重建) rm -rf /var/log/harbor /var/lib/docker/overlay2/*harbor* # 执行最小化安装(仅 core + registry + portal) ./install.sh --with-chartmuseum # ✅ 正确输出结尾应含: # ✔ ----Harbor has been installed and started successfully.---- # ✔ ----Please open browser to visit http://harbor.internal----

提示:--with-chartmuseum是 Harbor 2.5.0-rc1 唯一默认启用的扩展(Helm Chart 仓库),它不依赖外网,且镜像已打包在images/中。其他模块如notary需单独下载notary-server和notary-signer镜像,离线部署复杂度陡增,新手务必跳过。

4.2 启动后服务状态验证:逐个检查容器健康

安装成功不等于服务就绪。Harbor 启动后共 8 个容器,需逐个确认状态:

# 查看所有 harbor 容器 docker ps -a --filter "name=harbor" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" # 关键容器健康检查(必须全部为 healthy) docker inspect harbor-core | jq -r '.State.Health.Status' # 应输出 healthy docker inspect harbor-registry | jq -r '.State.Health.Status' # 应输出 healthy docker inspect harbor-portal | jq -r '.State.Health.Status' # 应输出 healthy

若某容器状态为unhealthy或exited,立即查看日志:

# 例如 core 容器异常 docker logs harbor-core --tail 50 | grep -E "(error|ERROR|panic)" # 常见错误:failed to initialize database → 检查 /data/database/ 权限 # 常见错误:failed to connect to redis → 检查 harbor-redis 容器是否 running

4.3 避坑:常见问题与排查(现象 → 原因 → 解决)

现象 1:install.sh执行到Creating network "harbor_harbor" with the default driver后卡住超过 5 分钟

原因:Docker daemon 未完全就绪,或系统启用了iptables-nft模式(Ubuntu 22.04 默认),与 Harbor 的bridge网络冲突。
解决:重启 Docker 并强制使用 legacy iptables:

systemctl stop docker update-alternatives --set iptables /usr/sbin/iptables-legacy systemctl start docker ./install.sh --with-chartmuseum
现象 2:浏览器访问https://harbor.internal提示Your connection is not private,且无法跳过

原因:证书 SAN 中未包含访问所用的域名/IP,或系统时间误差 > 5 分钟。
解决:

  • 用openssl x509 -in /data/cert/harbor.crt -text -noout | grep -A1 "Subject Alternative Name"确认 SAN 包含当前访问地址;
  • 用date检查系统时间,误差大时执行ntpdate -s time.windows.com(需临时开外网)或手动校准。
现象 3:登录 Web UI 成功,但docker login harbor.internal报错Error response from daemon: Get "https://harbor.internal/v2/": x509: certificate signed by unknown authority

原因:Docker 客户端未信任自签证书。
解决:将证书复制到 Docker 证书目录并重启:

mkdir -p /etc/docker/certs.d/harbor.internal cp /data/cert/harbor.crt /etc/docker/certs.d/harbor.internal/ca.crt systemctl restart docker
现象 4:上传镜像时报错unauthorized: authentication required,但用户名密码正确

原因:Harbor 默认关闭匿名拉取,但新用户未被分配项目权限。
解决:

  • 用 admin 登录 Web UI → 顶部菜单「Projects」→ 创建新项目(如test);
  • 点击项目名 → 「Members」→ 「+ Member」→ 添加你的用户 → 角色选developer;
  • 此时docker push harbor.internal/test/nginx:latest即可成功。
现象 5:docker-compose ps显示所有容器Up (health: starting),但 10 分钟后仍不变成healthy

原因:harbor-core依赖harbor-db初始化,而 PostgreSQL 容器因/data/database/目录权限不足启动失败。
解决:

chown -R 10000:10000 /data/database/ docker restart harbor-db # 等待 30 秒后,再执行 docker restart harbor-core

5. 验证 Harbor 是否真正跑通:从 CLI 到 API 的四层穿透测试

装完只是开始,验证才是关键。我习惯用四层递进方式确认 Harbor 已完全就绪:CLI 登录 → 镜像推送/拉取 → Web UI 操作 → REST API 调用。每一层失败,都指向不同模块,能快速定位故障域。

5.1 第一层:docker login 与基础镜像操作

这是最轻量的验证。使用 admin 账户(密码在harbor.yml中harbor_admin_password字段,默认Harbor12345):

# 登录(注意:域名必须与 harbor.yml 中 hostname 一致) docker login harbor.internal # 拉取一个测试镜像(用 busybox 避免体积大) docker pull busybox:1.35 docker tag busybox:1.35 harbor.internal/library/busybox:1.35 # 推送(library 是 Harbor 默认公开项目) docker push harbor.internal/library/busybox:1.35 # 验证:推送后立即拉取,确认 registry 读写通路闭环 docker rmi harbor.internal/library/busybox:1.35 docker pull harbor.internal/library/busybox:1.35

✅ 成功标志:push和pull均显示1.35: digest: sha256:... size: 737,且无unauthorized或denied报错。

5.2 第二层:Web UI 功能验证:项目创建、用户管理、镜像扫描

打开https://harbor.internal,用 admin 登录后执行以下操作:

  • 项目创建:点击「Projects」→ 「+ Project」→ 名称填test-scan→ 勾选「Public」→ 「CREATE」;
  • 用户添加:顶部「Users」→ 「+ User」→ 用户名dev1,邮箱dev1@example.com,密码Dev12345→ 「CREATE」;
  • 成员授权:进入test-scan项目 → 「Members」→ 「+ Member」→ 选dev1→ 角色developer→ 「ADD」;
  • 镜像扫描:Push 一个带漏洞的镜像(如nginx:1.19),等待 2 分钟后,点击镜像右侧「SCAN」按钮 → 状态变为Success,且「VULNERABILITIES」标签页显示 CVE 列表。

✅ 成功标志:扫描结果中出现CVE-2021-33574等真实漏洞条目(证明 Trivy 扫描器已离线加载规则库)。

5.3 第三层:REST API 调用:用 curl 测试核心接口

Harbor API 是自动化集成的基础。以下命令均使用 admin token(无需额外认证):

# 获取 admin 的 Bearer Token(用于后续 API) TOKEN=$(curl -s -X POST "https://harbor.internal/service/token?account=admin&service=harbor-registry" | jq -r '.token') # 列出所有项目(验证 API 可达) curl -s -H "Authorization: Bearer $TOKEN" "https://harbor.internal/api/v2.0/projects" | jq '.[0].project_name' # 查询 library 项目下的 busybox 镜像(验证 registry API) curl -s -H "Authorization: Bearer $TOKEN" "https://harbor.internal/api/v2.0/projects/library/repositories/busybox/artifacts" | jq '.[0].digest' # 创建 webhook(验证事件系统) cat > webhook.json <<EOF {"name":"test-webhook","target_type":"http","target":"http://example.com","event_types":["pull_image","push_image"]} EOF curl -s -X POST "https://harbor.internal/api/v2.0/projects/library/webhook/policies" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d @webhook.json | jq '.id'

✅ 成功标志:所有curl命令返回 JSON 且无401 Unauthorized或404 Not Found;jq解析出有效字段(如项目名、digest 值、policy id)。

5.4 第四层:持久化与灾备验证:数据目录完整性检查

Harbor 的价值在于数据持久化。/data目录是它的生命线,必须确认其结构完整、权限正确、可被备份:

# 检查核心子目录是否存在且非空 ls -ld /data/{database,job_logs,redis,registry,secretkey} # 正确输出:每个目录权限为 drwx------,且大小 > 4KB # 检查 registry 存储(镜像实际存放地) find /data/registry -name "sha256*" | head -5 # 应输出类似:/data/registry/docker/registry/v2/blobs/sha256/... # 模拟一次冷备份(验证可读性) tar -czf /tmp/harbor-data-backup-$(date +%Y%m%d).tgz -C /data . # 检查压缩包大小(正常应 > 100MB) du -sh /tmp/harbor-data-backup-*.tgz

✅ 成功标志:tar命令无报错,压缩包大小合理;find命令能列出真实的 blob 文件路径。这意味着你的镜像、日志、数据库都已落盘,可随时迁移或恢复。

从那以后我每次部署 Harbor 离线包,都强制走一遍这四层验证:CLI → Web → API → Data。哪怕客户只要求“能 push 镜像”,我也坚持跑完全部——因为docker push成功只代表 registry 写入通,而curl能调通 API 才说明权限、认证、事件全链路在线;find能扫出 blob 才证明数据真落地,不是缓存在内存里。这套验证流程帮我避开了 90% 的“上线即故障”场景,也让我敢在信创服务器上签字交付。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进