简介面向ARM64架构的Harbor离线部署包版本为当前最新的v2.13.1专供在鲲鹏、飞腾等ARM处理器服务器上搭建镜像仓库使用尤其适合Kubernetes与Docker离线环境下的运维场景。压缩包以tgz格式封装共6个文件包含2个shell脚本负责安装与配置处理、1个镜像tar.gz文件内含Harbor本体镜像以及license、prepare工具和配置模板整体大小679.05MB。资源下载后可直接执行安装脚本完成部署无需在线拉取大量容器镜像适合内网隔离或网络受限的机房环境通过附带的prepare和yml模板可灵活调整存储、TLS及认证参数。该资源已持续更新至v2.13.1浏览学习人数已有526人对于需要在ARM64平台上快速上线Harbor的运维或开发人员来说是一份省时省力的工具包。1. 拿到 ARM64 服务器Harbor v2.13.1 离线安装包先别急着装拿到一台飞腾或鲲鹏的 ARM64 服务器系统是麒麟 V10 或 CentOS 7下一步要在内网部署 Harbor v2.13.1。别急着从网上随便找一个“ARM64 版离线安装包”就装我在这里翻过不只一次车下载的 tgz 解压后docker load 时提示 manifest 不匹配或者镜像加载成功容器一启动就报 exec format error。Harbor 的离线安装包不是源码包它本质上是“预打包的 Docker 镜像 安装脚本”镜像架构决定这个包能不能在当前主机直接跑。这篇笔记从离线包的拆解、ARM64 离线包的自制、内网 install.sh 完整落地到常见排错按一条可复现的流程讲完。适合负责内网镜像仓库交付、帮机房做离线部署的人照着走能直接复现。2. 拆解 Harbor v2.13.1 离线包镜像架构、文件组成和识别方法安装包文件名按版本号来常见的是harbor-offline-installer-v2.13.1.tgz单看文件名很难直接分辨 amd64 还是 arm64。真正决定架构的是包内那个镜像压缩包。先把离线包的组成和架构判断方法说清楚后面做 ARM64 版才有依据。2.1 离线安装包解开后核心其实是一个镜像归档把官方离线包解压进入harbor目录关键文件是可预期的install.sh负责安装prepare负责根据harbor.yml生成 compose 配置harbor.yml.tmpl是配置模板common.sh是脚本公共函数。这里最值得注意的文件是harbor.v2.13.1.tar.gz它是用docker save导出的全部 Harbor 镜像归档。tar -xzf harbor-offline-installer-v2.13.1.tgz cd harbor ls -lh我通常先看这个列表再判断离线包完成度。一个合格的离线包不需要网络install.sh会先把harbor.v2.13.1.tar.gz用docker load加载进本地再由docker compose up启动。所以只要这个镜像归档的架构和当前主机不匹配后面全部白搭。看一个离线包是不是能直接用第一件事不是改配置而是查镜像归档里的架构字段。docker save出来的 tar 内部有manifest.json和每层镜像的 config 文件config 文件里的architecture字段会明确写amd64还是arm64。文件内部结构大概是manifest.json、若干layer.tar或blobs/sha256/...、还有一份记录镜像和 tag 对应关系的repositories。这些信息在安装失败时是排查的第一线索。2.2 ARM64 和 x64 的镜像差异为什么绕不过去ARM64 和 x64 的差异不是改个文件名就能解决的。Harbor 的容器镜像里harbor-core、harbor-jobservice是 Go 编译的二进制harbor-portal是 Nginx 加静态文件harbor-db是 PostgreSQL基础镜像各自对应官方平台版本。x86 指令集编译出来的二进制在 ARM64 内核上无法执行反过来也一样。就算docker load把镜像加载成功容器起来时也会因为缺exec format error或exec user process caused: exec format error而退出。在 ARM64 v8a 上部署还有一个容易忽略的点ARM64 下存在 v8.0、v8.1、v8.2 等微架构差异大部分商用镜像都按linux/arm64/v8或更低的兼容级别打包飞腾、鲲鹏这类处理器通常能兼容运行 v8.0 基础镜像。所以看到arm64/v8直接采用即可不必为某颗具体芯片型号单独找安装包。很多“伪 ARM64 离线包”的问题也出在这有的人只是把 amd64 的镜像 tar 原样改了个名或者在 x86 机器上没有经过docker buildx --platform linux/arm64构建就重新打了一个压缩包。这种包在 ARM64 机器上要么加载报错要么运行时报格式错误。判断标准只有一个镜像或镜像归档里的实际 platform 字段而不是文件名带了什么后缀。2.3 一分钟内定位离线包架构的检查手段在目标 ARM64 机器上原地验证最直接。先docker load再对任意一个 Harbor 镜像做inspect看看 Architecture 字段是不是 arm64。docker load -i harbor.v2.13.1.tar.gz docker image inspect goharbor/harbor-core:v2.13.1 --format {{.Os}}/{{.Architecture}}输出如果出现linux/arm64说明镜像归档确实是 ARM64 可用如果显示linux/amd64这个离线包在当前 ARM64 机器上是起不来容器的。还有人习惯用docker run --rm goharbor/harbor-core:v2.13.1 true做冒烟测试如果直接报exec format error基本可以确认架构不匹配。这个方法在拿到任何第三方离线包时都适用不用等整个安装流程跑完才后悔药。3. 制作并安装 Harbor v2.13.1 的 ARM64 版离线包从导出镜像到 install.sh 跑通如果官方或第三方给的离线包架构不对最常见的做法不是等别人重新发布而是自己拿一台能联网的 ARM64 机器重新导出镜像再替换到离线包里。这套流程我至少走了三遍把步骤固定下来能省很多时间。3.1 准备一台能联网的 ARM64 机器或者用 QEMU 模拟 arm64 环境先决条件是有 Docker 服务并且这台机器能访问 Harbor 镜像仓库的源站。常见做法是在临时的一台 ARM64 云主机或飞腾开发板上完成导出再把产物拷贝到内网。没有 ARM64 实体机时用 QEMU 模拟 arm64 也成立宿主 x86 机器上装qemu-user-static配合 Docker 的 binfmt 机制pull 时指定--platform linux/arm64/v8一样能把 ARM64 镜像拉到本地归档。我一般更推荐直接找一台真实 ARM64 机器而不是长期依赖 QEMU。原因很简单Harbor 安装过程里容器涉及网络、存储、systemd 资源限制QEMU 下的运行表现和物理 ARM64 机器有差异特别是权限和 sysctl 相关的错误只有真机才能暴露。3.2 拉齐 Harbor 镜像清单并导出 ARM64 镜像归档Harbor v2.13.1 安装涉及的镜像包括 core、jobservice、portal、registry、registryctl、db、log、nginx、redis、trivy 等。先在一台 ARM64 机器上配置好 Docker逐个 pull再统一用docker save导出一个归档文件。IMAGE_LISTgoharbor/harbor-core:v2.13.1 \ goharbor/harbor-jobservice:v2.13.1 \ goharbor/harbor-portal:v2.13.1 \ goharbor/harbor-registry:v2.13.1 \ goharbor/harbor-registryctl:v2.13.1 \ goharbor/harbor-db:v2.13.1 \ goharbor/harbor-log:v2.13.1 \ goharbor/nginx-photon:v2.13.1 \ goharbor/redis-photon:v2.13.1 docker pull goharbor/harbor-core:v2.13.1 docker image inspect goharbor/harbor-core:v2.13.1 --format {{.Architecture}}/{{.Os}} | grep arm64 docker save $IMAGE_LIST | gzip harbor.v2.13.1.arm64.tar.gz这段命令里docker pull会按当前机器的架构拉取ARM64 机器上拉到的就是 arm64 镜像。docker image inspect用 Go 模板只输出os/architecture用来确认拉出来的确实是 arm64。最后docker save把镜像归档成单个 tar 流再 gzip 压缩避免内网拷贝时占用太多空间。如果你的镜像源不是默认仓库需要提前做好 registry mirror 或直连源站的网络配置否则在 ARM64 机器上拉镜像也会卡在第一步。在这之后要把官方离线包里的原镜像归档替换掉。官方离线包里的harbor.v2.13.1.tar.gz如果确认是 amd64 的先备份再把新导出的归档改成同名文件。cd harbor mv harbor.v2.13.1.tar.gz harbor.v2.13.1.tar.gz.amd64.bak cp ../harbor.v2.13.1.arm64.tar.gz ./harbor.v2.13.1.tar.gzinstall.sh调用时并不校验内容是否来自官方只认文件名是否存在。替换完成后这个离线包就成了真正可用的 ARM64 版。需要提醒一点tar 文件体积通常不小建议在拷到内网前先算一次 sha256和目标机上的文件做比对避免传输中断造成归档损坏。3.3 按内网场景修改 harbor.ymlhostname、存储与端口离线替换做完接着改harbor.yml。官方包解压后自带harbor.yml.tmpl先复制成harbor.yml。核心配置项有三个hostname、http/https、data_volume。cp harbor.yml.tmpl harbor.yml典型的内网最小配置长这样hostname: 192.168.10.20 http: port: 80 https: port: 443 certificate: /data/cert/harbor.crt private_key: /data/cert/harbor.key data_volume: /data/harbor log: level: info database: password: ChangeMe123参数说明hostname必须是客户端能访问到的地址不能写 localhost否则其他机器docker login会失败内网没有 DNS 时直接用管理 IP 最省事。http.port建议保留 80Harbor 的prepare脚本会对 hostname 和端口生成对应的docker-compose.yml。https默认是打开的生产环境建议用自签证书如果前期只想在隔离网络里跑通可以把https整段注释掉后面再补证书也来得及。data_volume是镜像存储目录务必预留出比离线包本身大三倍以上的磁盘空间Harbor 的 registry 存储层和数据库都会写在这里。改完配置下一步就交给install.sh。它内部先跑prepare生成 compose 文件再docker load加载替换后的镜像归档最后启动全部容器。离线环境里可以先把外部组件关掉比如./install.sh --with-trivy这种参数在没有外网、无法更新漏洞数据库的阶段先不启用更稳妥。3.4 跑 install.sh 并验证三个关键状态执行安装需要 root 权限或者把当前用户加入 docker 组。直接跑sudo ./install.sh脚本输出的最后一行如果出现类似Harbor has been installed and started successfully的内容说明安装主体完成。只看到这行还不够我用三条命令做启动验证docker compose ps curl -k https://192.168.10.20/api/v2.0/health docker login 192.168.10.20 -u admin -p Harbor12345docker compose ps看所有容器是不是处于 Up 状态curl打/api/v2.0/health返回{status:healthy}才算服务就绪docker login是镜像上传前的最后一道验证登录成功了说明 registry、portal、db、nginx 这一整条链路是通的。第一次启动后还可以把install.sh的日志留底后续排查容器重启问题时省得反复翻docker logs。ARM64 环境里docker-compose.yml由prepare生成镜像 tag 固定跟随 v2.13.1如果出现某个容器反复 Restarting多半还是镜像架构或存储权限问题这一块放到下一章专门说。4. ARM64 离线部署 Harbor 的五个硬坑现象、原因和解决办法过程中踩过的坑基本可以分成长这样五类每一条都按“现象 → 原因 → 解决”的顺序拆开方便后面照着排查。4.1 docker load 时报 “no matching manifest for linux/arm64”现象在 ARM64 机器上执行docker load -i harbor.v2.13.1.tar.gzDocker 直接报no matching manifest for linux/arm64 in the manifest list entries。原因镜像归档是 amd64 的 manifestDocker 尝试解出当前平台的镜像实例找不到 arm64 的匹配项。这个问题在替换前最容易发生原因是网上很多人下载的“ARM64 版”实际是把官方 amd64 离线包改名重新打包没有真正替换过镜像归档。解决不要在这里做任何绕过老老实实按第 3.2 节的方式导出 arm64 镜像归档再替换。如果改文件名的思路已经进行到一半可以用docker manifest inspect goharbor/harbor-core:v2.13.1查看远端镜像的 platform 列表确认arm64/v8存在然后重新在 ARM64 机器上 pull 和 save。4.2 install.sh 卡在拉取镜像而不是使用本地离线归档现象sudo ./install.sh执行到一半日志显示Pulling goharbor/harbor-core:v2.13.1内网环境里网络不通就一直卡在那。原因install.sh加载离线包后docker compose up如果发现某个镜像在本地不存在Compose 会退到默认行为去远程仓库拉取。这通常意味着docker load阶段没有真正加载成功最常见的是harbor.v2.13.1.tar.gz文件名不对或者docker load因为磁盘空间不足而中止。解决先看 install.sh 前面几行日志确认docker load是否出现Loaded image的输出。没有输出就手动执行docker load -i harbor.v2.13.1.tar.gz看完整报错。空间不足时df -h会看到根分区或 docker>setenforce 0 sudo ./install.sh如果生产环境不能关 SELinux更精细的做法是把data_volume、日志目录放到固定路径再用chcon -R -t container_file_t /data/harbor设置正确的上下文。也可以在所有容器启动前创建一个/data/harbor目录并写成属主属组都是 10000很多 Harbor 容器进程是以 UID 10000 运行的这是我在踩坑后才检查到的位置。4.4 数据目录容量判断偏差离线包解压半路中断现象docker load执行到一半中断报no space left on device或者磁盘明明够但install.sh生成的日志目录写入失败。原因离线包harbor.v2.13.1.tar.gz看着只有 1GB 多但这是 gzip 压缩后的体积docker load解压后占用接近原始层体积通常翻倍。再加上data_volume里 registry 的存储目录又需要一份空间很多人只按压缩包体积规划磁盘装上才发现不够。解决规划容量时按离线包解压后的 3 倍预留。检查时不要只盯一个分区/、/var/lib/docker、/data可能是三个不同分区。docker info | grep Docker Root Dir可以看到 docker>{ insecure-registries: [192.168.10.20] }然后重启 docker。完整操作顺序是先修改daemon.json执行systemctl restart docker再docker login 192.168.10.20。生产环境不要一直用 insecure 模式正确做法是自建 CA把 CA 证书分发给客户端并在daemon.json里指向私有 registry 地址和证书。ARM64 的客户端机器同样可以在/etc/docker/certs.d/192.168.10.20/下放ca.crtDocker 会自动信任这对内网大量 ARM64 客户端分批配置时更可控。5. 落地前最后一道工序验证 ARM64 镜像清单并按批导入业务镜像安装成功只是第一步真正的交付还要把业务镜像送进 Harbor。我习惯在部署前先验证镜像源是否真的支持 ARM64然后才安排批量导入。5.1 用 docker buildx imagetools 在离线前核对所有平台在能联网的机器上用docker buildx imagetools inspect检查远端镜像的 platform 列表比直接 pull 更省流量。docker buildx imagetools inspect goharbor/harbor-core:v2.13.1输出里的Platforms字段会列出linux/arm64/v8、linux/amd64等。这一步能在离线操作前就把“这个镜像支不支持 ARM64 机器”的黑匣子打开避免拉到不带 arm64 的镜像后才发现。对于业务系统镜像同样可以用这个命令验一遍特别是那些基础镜像是 alpine 或 debian 的一般都有多架构支持但一旦基础镜像是第三方定制的 x86-only 二进制就得联系上游重新提供。5.2 在目标机上批量 load 业务镜像并推入 Harbor离线业务镜像通常也是用docker save导出的。在 ARM64 目标机上加载一套镜像再推入 Harbor命令如下docker load -i business-images.tar.gz docker tag my-app:arm64-v1.0 192.168.10.20/library/my-app:arm64-v1.0 docker push 192.168.10.20/library/my-app:arm64-v1.0参数说明docker load会原样还原 save 时的 image tagdocker tag在本地给镜像增加一个带 Harbor 地址的 tag推送时 Docker 才知道要去哪个 registrydocker push前确保已经用 admin 账号或新建的项目账号做过docker login。这里有个细节离线导入的镜像如果架构不对docker load不会报错要等docker run才会暴露所以我建议推之前先docker image inspect my-app:arm64-v1.0 --format {{.Architecture}}确认一次。5.3 一张部署检查表和我的固定动作检查项验证结果离线包镜像归档架构docker image inspect输出linux/arm64install.sh 完成后容器状态docker compose ps全部 UpHarbor API 健康curl /api/v2.0/health返回 healthy磁盘空间style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />
