ARM架构离线部署Harbor 2.4.0:从镜像准备到容器排错全攻略
简介面向 ARM 服务器与内网环境提供的 Harbor 2.4.0 离线部署资源包专门解决无外网条件下容器镜像仓库难以安装的问题。压缩包内共 6 个文件包括 2 个 shell 自动化脚本、1 个 Harbor 镜像离线压缩包、1 个 YAML 配置模板、1 个 LICENSE 许可文件和 1 个 prepare 预处理脚本整体大小约 402MB。部署流程简洁预先安装 Docker 与 Docker Compose 后执行 install.sh 即可完成配置生成、镜像导入与服务拉起无需手动干预多项底层参数。资源对 ARM 架构做了针对性适配在国产化服务器、树莓派等设备上也能稳定运行适用于企业私有镜像仓库搭建、离线交付、容器化改造等场景。目前已有 1576 人浏览学习文件数量少但功能闭环完整既能帮助入职团队快速上线 Harbor也为后续运维提供了配置入口与合规许可依据。1. 离线装 Harbor 2.4.0 不只是解压文件ARM 镜像差异才是第一道坎拿官方harbor-offline-installer-v2.4.0.tgz直接部署到 arm64 服务器上install.sh一路绿灯跑完等docker ps一看core 容器反复重启——这是我在某交付现场踩到的第一坑。Harbor 2.4.0 离线安装的难点从来不在解压和改 yml而在于 arm 架构下的镜像架构不匹配、docker compose 组件缺失、以及 prepare 阶段对配置文件的隐式要求。本文把从镜像准备、离线导入、配置修改到容器排错的全过程拆开讲适合手里只有 arm64 机器、且网络环境受限的开发者照着复现。版本固定、步骤固定跟着走一遍就能在纯内网环境把 Harbor 跑起来。2. ARM 离线包准备镜像清单、导出与导入全流程Harbor 官方发布页会同时提供在线和离线安装包但离线包里的harbor.v2.4.0.tar.gz是构建机上直接docker save出来的产物。这个 tar 包默认是 amd64 架构拿到 arm64 上 load 能成功跑起来就是反复重启。要在 ARM 环境做离线安装必须自己按平台拉镜像、重新打成离线 bundle再整体搬到目标机器。2.1 为什么 arm64 必须自己拉镜像而不是直接用官方 offline 包Harbor 官方镜像仓库里的大部分镜像本身是支持多架构的manifest list 里同时包含 amd64 和 arm64 的层。但官方离线安装包里的镜像 tar 是单架构快照docker save导出的是实际拉取下来的镜像层不是 manifest list。也就是说发布包在哪个架构的机器上构建出来的 tar 就只带哪个架构的层。docker load不会做架构转换它只是把镜像层原样塞进本地 Docker。arm64 机器加载 amd64 镜像时会提示 “Loaded image” 成功但容器运行时因为内核无法执行 x86 指令直接报exec format error。如果安装脚本执行完才发现这个问题前面所有步骤都得推倒重来。所以第一个动作就是在能联网的机器上按linux/arm64平台拉取全量镜像重新打成自己的安装包。很多团队把这个步骤固化到 CI 里每次升级 Harbor 版本都重新生成一套 arm64 bundle。2.2 在联网机器上按平台拉取镜像并导出Harbor 2.4.0 的核心组件镜像包括 prepare、harbor-core、harbor-db、harbor-jobservice、harbor-portal、harbor-registryctl、registry-photon、nginx-photon、redis-photon以及启用漏洞扫描时要用的 trivy-adapter-photon。下面这个脚本在一台能联网的机器上执行目标机是 arm64 就用linux/arm64拉取拉完直接打短 tag 再 save省掉目标机上二次 tag 的麻烦。#!/bin/bash # 在能联网的机器上执行生成 arm64 架构的 Harbor 镜像离线包 PREFIXyour.registry.example.com/harbor # 换成你实际使用的镜像仓库前缀 TAGv2.4.0 ARCHlinux/arm64 mkdir -p arm64_images images( prepare harbor-core harbor-db harbor-jobservice harbor-portal harbor-registryctl registry-photon nginx-photon redis-photon trivy-adapter-photon ) for name in ${images[]}; do docker pull --platform $ARCH $PREFIX/$name:$TAG docker tag $PREFIX/$name:$TAG $name:$TAG docker save $name:$TAG -o arm64_images/$name.tar done脚本里先显式指定--platform linux/arm64确保 Docker 从 manifest list 里挑 arm64 的层而不是按当前机器的架构拉取。之后打短 tag 是因为 Harbor 的prepare脚本和最终生成的docker-compose.yml里引用的镜像是harbor-core:v2.4.0这类短名不提前打短 tag目标机 load 后镜像会带着仓库前缀install.sh 找不到镜像。参数方面PREFIX根据你实际拉取源填如果官方仓库访问不稳定可以先同步到内网镜像仓库再从这里拉TAG固定 v2.4.0不建议跨版本混用Harbor 各组件镜像 tag 必须对齐同一个版本混 tag 会出现 core 和 jobservice 之间 API 不兼容。列表里没放 notary-server 和 notary-signer因为默认install.sh不启用 notary如果后续要做镜像签名需要把这两个镜像也加进列表重新生成。2.3 离线导入到目标机器load 与 tag 的顺序问题把arm64_images目录拷到目标机后导入命令很简单但要验证架构。下面这段代码在目标机上执行循环导入所有 tar再用image inspect确认架构字段。cd arm64_images # 逐个导入save 时用了短名load 后镜像名就是 name:tag for f in *.tar; do docker load -i $f done # 验证架构必须输出 arm64 docker image inspect harbor-core:v2.4.0 --format {{.Architecture}}docker load会打印 “Loaded image: harbor-core:v2.4.0”因为我们在联网机上 save 前已经重新 tag 过所以目标机上不需要再执行docker tag。如果架构验证输出不是 arm64说明拉取时--platform参数没生效或者源仓库里根本没有 arm64 的 manifest需要回到联网机上确认拉取的镜像层。这里还有个小细节不要把所有 tar 打成一个大的 tar 再拷一旦传输中断整个文件作废。保持每镜像一个 tar传输工具可以做断点续传报错时也能定位到具体是哪个镜像损坏。3. 系统侧准备Docker、Docker Compose 与依赖安装顺序镜像就绪后目标机的容器运行时环境是下一个关口。Harbor 的 install.sh 依赖完整的 Docker Engine 和 docker-compose 命令缺一个都跑不起来。ARM 服务器上常见的坑是厂商预装了老版本 Docker或者只有 podman 没有标准的 docker compose导致安装脚本卡在环境检查阶段。3.1 适配 ARM 的 Docker 版本选型arm64 架构下 Docker 的版本选择直接影响 Harbor 的稳定性。19.03 版本能跑容器但对多架构 manifest 的处理不完善docker pull --platform参数在部分场景下会失效20.10 之后 Docker 默认启用 manifest 支持--platform行为稳定离线导入导出也更可靠。建议直接用 20.10 及以上版本不要为了兼容老系统去选低版本。另一个容易被忽略的点是 containerd 和 runc 的配套关系。Docker 20.10 依赖 containerd 1.4 以上如果系统里残留旧版 containerddocker info可能正常但容器启动时会在 runc 阶段报错。稳妥的做法是把旧版本彻底清掉再按 containerd、docker-ce-cli、docker-ce 的顺序统一安装。3.2 离线环境下的 Docker 组件安装在联网机器上下载 arm64 架构的 deb 包拷到目标机后用apt install -y ./xxx.deb安装。注意 deb 包必须选 arm64 版本在 x86 机器上下载的包拷到 ARM 机器上会直接报 wrong architecture。# 在目标机执行三个包都放到当前目录 sudo apt install -y ./containerd.io_1.6.*.deb \ ./docker-ce-cli_20.10.*.deb \ ./docker-ce_20.10.*.deb sudo systemctl enable --now docker # 验证 client 和 server 两段都正常输出 docker version安装顺序不能乱containerd 是 docker-ce 的底层依赖必须先装docker-ce-cli 提供 docker 命令行工具docker-ce 是核心引擎。systemctl enable --now docker把 Docker 设为开机自启并立刻启动。验证时docker version会分 client 和 server 两段输出如果只看到 client 段没有 server 段说明 daemon 没起来查systemctl status docker。3.3 docker-compose 的安装方法与版本坑Harbor 2.4.0 的 install.sh 对 compose 的检测逻辑比较保守优先找docker-compose命令找不到才会尝试docker compose子命令。如果目标机上只装了新版 Docker 的 compose 插件脚本可能停在环境检查阶段而不是直接跑到镜像加载。最省事的做法是离线拷贝一个 aarch64 的 docker-compose 二进制到/usr/local/bin。# 把在联网机器上下载的 docker-compose-linux-aarch64 拷到目标机 sudo mv docker-compose-linux-aarch64 /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose # 验证版本1.29.x 和 2.x 都兼容 Harbor 2.4.0 docker-compose version这个二进制是在 x86 机器上下的但文件名里明确标注了 aarch64不要混用。装完后建议同时确认docker compose version也可用因为后续手动维护容器时两个命令风格不一样。docker-compose 1.29 和 2.x 在 Harbor 2.4.0 下都能正常工作关键是命令要能找到版本上没有必要追求最新。4. 正式安装 Harbor 2.4.0harbor.yml 配置与 install.sh 执行逻辑镜像和容器运行时都准备好之后正式安装反而只是解压、改配置、跑脚本三个动作。但配置文件的几个隐式要求会把不少人卡在 prepare 阶段尤其是 https 证书和 hostname 这两项必须在执行安装前处理好。4.1 harbor.yml 关键配置项解读解压harbor-offline-installer-v2.4.0.tgz后先把harbor.yml.tmpl复制成harbor.yml再做最小修改。下面是内网部署时最常用的一段配置hostname 填目标机的内网 IPhttps 整个注释掉密码和数据库口令改成自己的。hostname: 192.168.10.21 http: port: 80 # https: # port: 443 # certificate: /data/cert/server.crt # private_key: /data/cert/server.key harbor_admin_password: Harbor12345 database: password: root123 max_idle_conns: 100 max_open_conns: 900 data_volume: /data/harbor trivy: ignore_unfixed: false skip_update: true insecure: falsehostname不要写 localhost 或 127.0.0.1后面docker login和 Web 访问都要用这个地址解析服务写 localhost 会导致外部客户端无法访问。https段在首次部署时直接注释干净不注释的话 prepare 阶段会去读证书文件证书路径不存在直接报错退出。data_volume建议放到独立挂载盘Harbor 的数据库、镜像存储、redis 数据都在这下面系统盘空间不够会引发后续一系列问题。trivy.skip_update在离线环境必须设成 true否则漏洞扫描服务启动后会尝试联网更新漏洞库然后卡死在启动阶段。4.2 install.sh 的执行流程与常见报错配置改好后执行安装命令这里选择了开启 trivy因为镜像列表里已经包含了 trivy-adapter 镜像。sudo ./install.sh --with-trivyinstall.sh 的执行流程分四段先检查 docker 和 docker-compose 可用性再加载官方离线包里的镜像如果镜像已经 load 过会提示 already exists接着运行 prepare 脚本读取 harbor.yml 生成 docker-compose.yml 和一系列配置目录最后用 compose 把全部容器拉起。加--with-trivy才会启动漏洞扫描容器不加的话 harbor.yml 里 trivy 段会被忽略。脚本跑完看到 “Harbor has been deployed and is running” 才算成功。如果中途失败先看是停在哪一步环境检查失败说明 docker 或 compose 有问题镜像加载阶段失败说明 tar 包损坏prepare 阶段失败基本是 harbor.yml 配置问题最后容器拉起失败要看docker compose ps和容器日志。4.3 安装后的目录结构与日志位置安装完成后data_volume下会出现 database、secret、redis、registry 等子目录分别对应 PostgreSQL 数据、Harbor 密钥、缓存数据和镜像存储。排查问题时先看服务状态再看具体容器日志。cd /app/harbor # 解压安装包的目录 docker compose ps # 查看核心服务日志容器名以 harbor- 开头 docker logs harbor-core --tail 50docker compose ps会列出所有服务和健康状态正常情况下 8 个核心容器都是 running 状态可选服务看安装参数。harbor-core 是所有请求的入口它的日志里如果出现数据库连接失败优先检查 database 容器状态和harbor.yml里的数据库密码是否一致。5. 避坑记录ARM 离线安装 Harbor 的五个典型事故离线环境下出问题的特点就是报错信息往往模棱两可需要结合环境特征去推断原因。这五条是我实际踩过、以及身边同事反复遇到的坑每条都按现象、原因、解决三个维度拆开。5.1 现象install.sh 执行完容器反复重启core 和 jobservice 起不来装完看docker pscore、jobservice 这几个容器一直显示 Restartingdocker logs里只有一句exec format error。原因是镜像架构不对——要么直接用了官方 amd64 离线包要么拉镜像时没带--platform linux/arm64。docker load不校验架构所以导入阶段毫无提示。解决方法是登录目标机执行docker image inspect harbor-core:v2.4.0 --format {{.Architecture}}如果输出不是 amd64 就删除旧镜像按 2.2 节重新生成离线包再导入一次。5.2 现象install.sh 报 docker-compose not found卡在环境检查脚本开头就退出提示找不到 docker-compose。原因是目标机只装了 docker 引擎或者只有新版 compose 插件但命令行里没有docker-compose这个可执行文件。Harbor 2.4.0 的脚本对 compose v2 的支持不完整优先找的还是独立二进制。解决方法是离线拷贝docker-compose-linux-aarch64到/usr/local/bin/docker-compose并加执行权限然后重新跑 install.sh不需要动 docker 引擎本身。5.3 现象prepare 阶段报证书文件不存在的错误日志里出现certificate /data/cert/server.crt not found安装直接中断。原因是harbor.yml里 https 段没有注释prepare 会去读配置里指定的证书路径文件不存在就报错。解决方法是把 https 段全部注释掉用 http 端口跑内网部署等有正式证书再补配。还有一个小坑不能只注释 certificate 行而保留 https 段prepare 会把https.enabled判为 true。5.4 现象容器全部 running但 Web 页面打不开docker compose ps显示所有容器都是 running健康检查也正常但浏览器访问 IP 就是不通。原因通常是 hostname 配置问题或端口被占。如果 hostname 写的是 localhostHarbor 生成的 nginx 配置只监听 localhost外部请求进不来如果 80 端口被其他服务占用容器会启动失败但状态偶尔显示 running。解决方法是把 hostname 改成内网固定 IPhttp.port改成 8080访问和docker login都带上端口号。排查时先执行ss -tlnp | grep 80确认端口占用情况。5.5 现象harbor-db 启动失败日志提示数据目录权限错误数据库容器起不来日志里出现data directory has wrong ownership。原因是data_volume目录属主不对容器内部运行用户无法写入数据目录。解决方法是执行chown -R 10000:10000 /data/harbor这是 Harbor 镜像内部运行用户常用的 uid 映射。如果问题依旧检查数据目录所在磁盘的 inode 是否耗尽数据库文件多小分区很快会被 inode 占满df -i看一下剩余值。6. 安装后的验证与备份给离线环境留条后悔药服务跑起来之后先用 API 做一轮快速验证确认 core、数据库、redis 这些组件是真的正常而不是容器活着但业务不可用。Harbor 2.4.0 原生支持 API v2.0健康检查和登录验证两条命令就够了。# 健康检查期望返回 {status:healthy} curl -s http://192.168.10.21/api/v2.0/health # 带基本认证请求项目列表返回 200 说明 core 和数据库正常 curl -s -u admin:Harbor12345 http://192.168.10.21/api/v2.0/projects?page_size10健康检查通过后再验证镜像上传用docker login 192.168.10.21登录push 一个测试镜像到项目里再 pull 回来走完这一步整个链路才算验证完整。离线环境的备份比在线环境更重要因为出问题后没有快速恢复手段只能靠备份兜底。备份的核心是data_volume下的 database、secret、redis 三个目录secret 一旦丢失所有已存镜像的访问凭证和密码都会失效。备份前先停服务保证 PostgreSQL 数据落盘一致。cd /app/harbor docker compose down cd /data tar czf harbor-backup-$(date %Y%m%d).tar.gz harbor/database harbor/secret harbor/redis # 重新拉起服务 cd /app/harbor docker compose up -d恢复时解压 tar 到原路径再执行docker compose up -d即可。这套备份流程我在多台 arm64 服务器上验证过每次升级或迁移前强制走一遍。有次同事在另一台机器上恢复因为少备份了 secret 目录所有已存项目的 robot 账号全部失效只能让各团队重新生成凭证。从那以后我每次装完 Harbor 都先把这三个目录 tar 一遍再开始传镜像这个习惯救过我好几次。希望帮到你少走点离线环境的弯路。本文还有配套的精品资源点击获取