☰
ARM64服务器离线部署Harbor v2.13.1:从镜像架构到安装配置避坑指南
2026/10/8 8:39:07 网站建设 项目流程

简介:一份专为ARM64架构下Kubernetes与Docker环境打造的离线部署包,内置Harbor最新v2.13.1版本,并以tgz格式封装,方便直接传递与部署。压缩包内共含6个文件,核心镜像压缩包harbor.v2.13.1.tar.gz承载仓库服务镜像,install.sh与common.sh负责安装流程与公共函数,harbor.yml.tmpl是配置模板,另有prepare准备文件及许可证文件,整体大小约679MB。这种打包方式免去在线拉取镜像的不确定性,特别适用于内网隔离或网络受限的生产环境,运维工程师依此即可快速搭建企业级镜像仓库,并根据业务需求灵活调整存储后端、TLS证书与认证策略。截至目前,已有528人学习下载,说明离线交付方案在真实场景中已获得充分验证。一次获取即拥有完整物料,有助于显著缩短Harbor部署周期,降低因网络故障导致的交付风险。

1. ARM64 服务器上部署 Harbor v2.13.1,离线安装包为什么不能直接用

Harbor v2.13.1 的 ARM64 离线安装包,听起来就是把官方离线包下载下来解压再install.sh的事,实际动手的人会发现,这条路经常走不通。官方离线安装包里的镜像包,默认按 amd64 架构打进去;ARM64 服务器上执行安装脚本,镜像能 load 进去,容器一运行就报exec format error,服务根本起不来。这篇文章先把离线安装包的构成拆开讲清楚,再给一条在 ARM64 环境下手动拉镜像、替换镜像包、跑通install.sh的完整路径,顺手把推送失败、架构不匹配这类高频坑一起排掉。适合正在搭内网镜像仓库的运维和交付工程师,尤其适合手里只有一台 ARM64 服务器、机器还不能联网的场景。

2. 在 ARM64 机器上把镜像拉全:先解决镜像清单和架构核对问题

搞 ARM64 离线包的第一步不是急着下离线包,而是先搞清楚离线安装包里的镜像包到底装了什么、是什么架构。官方发布的harbor-offline-installer-v2.13.1.tgz,核心是里面那一个harbor.v2.13.1.tar.gz。install.sh做的事很直接:docker load导入这个 tar 里的镜像,再用prepare渲染出docker-compose.yml,最后docker compose up -d把服务拉起来。所以这个 tar 里的镜像架构,决定了整套 Harbor 能不能在目标机器上起来。

2.1 官方离线包和 ARM64 的错位出在哪个环节

先看离线安装包解压出来的结构,确认每个文件的作用:

文件作用ARM64 离线安装要不要动
harbor.v2.13.1.tar.gzHarbor 全部容器的镜像包,gzip 压缩需要替换成 ARM64 架构的镜像包
docker-compose.ymlcompose 模板,install.sh用prepare渲染一般不手改,用prepare生成最终版
install.sh一键安装入口,负责 load 镜像和启动服务不用改脚本本身
harbor.yml.tmpl配置模板复制为harbor.yml后修改
prepare配置生成二进制不用动,但它决定 compose 里的镜像名

官方离线包在打包时,镜像包默认按构建机所在的 amd64 架构导出了一份harbor.v2.13.1.tar.gz。你把它搬到 ARM64 机器上docker load,Docker 不会拦,镜像名、tag 都对,但容器真正执行二进制时,CPU 不认识 amd64 指令集,于是容器反复重启或直接退出。这就是很多人第一步踩的坑:包能装,但跑不起来。

那能不能把官方包里的 tar 解出来重新打成 arm64?也可以,但没必要。社区里更常规的做法是自己在可联网的 ARM64 机器上,把所有镜像拉一遍、导出、再替换回离线包。这个过程最怕的就是镜像清单背错,Harbor 各个小版本改过几次镜像名,比如 registry 相关镜像从goharbor/registry-photon改成了goharbor/harbor-registry。背死名单不如每次从 compose 模板里现提。

2.2 在 ARM64 机器上批量拉取镜像并导出:镜像清单与 docker pull 脚本

准备一台能联网、并且架构确实是 arm64 的机器,在上面执行下面的脚本。这一步的关键,是让 Docker 根据当前机器的架构去拉对应的镜像层。

#!/bin/bash # 在可联网、架构为 arm64 的机器上执行 # 拉取 Harbor v2.13.1 全部服务镜像,并导出成一个 tar set -euo pipefail HARBOR_VERSION="v2.13.1" IMAGES=( "goharbor/prepare:${HARBOR_VERSION}" "goharbor/harbor-log:${HARBOR_VERSION}" "goharbor/harbor-registry:${HARBOR_VERSION}" "goharbor/harbor-registryctl:${HARBOR_VERSION}" "goharbor/harbor-db:${HARBOR_VERSION}" "goharbor/redis-photon:${HARBOR_VERSION}" "goharbor/harbor-core:${HARBOR_VERSION}" "goharbor/harbor-portal:${HARBOR_VERSION}" "goharbor/harbor-jobservice:${HARBOR_VERSION}" "goharbor/nginx-photon:${HARBOR_VERSION}" "goharbor/harbor-exporter:${HARBOR_VERSION}" ) for img in "${IMAGES[@]}"; do echo "==> pulling ${img}" docker pull "${img}" done docker save "${IMAGES[@]}" -o harbor-arm64-images.tar gzip -9 harbor-arm64-images.tar mv harbor-arm64-images.tar.gz harbor.v2.13.1-arm64.tar.gz ls -lh harbor.v2.13.1-arm64.tar.gz

脚本逻辑不复杂但有几个地方要注意。镜像数组里特意放了prepare和harbor-log,这两个是install.sh和 compose 启动时都会用到的辅助镜像,漏掉它们,安装脚本执行到生成配置那一步就会报找不到镜像。HARBOR_VERSION单独设成变量,以后升级到下一个版本,只改这一处就能复用脚本。

docker save一次性把数组里所有镜像导出成一个 tar,比逐个 save 再合并省事得多。导出的 tar 用的是原始镜像名和 tag,比如goharbor/harbor-core:v2.13.1,到目标机器上docker load之后,compose 里引用的镜像名能直接对上,不需要再 tag。gzip 压缩是必须的,因为替换回离线包时,install.sh认的是.tar.gz后缀。

如果你拿到的官方离线包里已经有了一份现成的镜像清单,也可以先解包,再从docker-compose.yml里抓image:字段核对一遍:

cd harbor grep -E 'image:' docker-compose.yml | sed -E 's/.*image:\s*"?([^"]+)"?/\1/' | sort -u

把这份清单和上面脚本里的数组对一下,缺谁补谁。以 compose 模板实际引用为准,别只信网上的旧教程。

2.3 架构核对:docker image inspect 和 manifest 两种查法

拉完镜像不要急着传走,先就地核对一次架构,这一步能省掉后面一整轮排错。最直接的命令:

docker image inspect goharbor/harbor-core:v2.13.1 --format '{{.Os}}/{{.Architecture}}'

在 arm64 机器上执行,正常输出应该是linux/arm64。如果输出linux/amd64,说明这台机器本身架构不对,或者 Docker 服务的平台参数被改过,拉下来的镜像仍然是 x86 的。

还有一种情况,镜像仓库本身是多架构的,Docker 会根据当前系统的uname自动选择对应的 manifest。想确认镜像仓库支持哪些架构,用docker manifest inspect:

docker manifest inspect goharbor/harbor-core:v2.13.1

返回的manifests列表里会列出amd64、arm64等平台的 digest。这里有个容易误解的点:manifest 里有 arm64,不代表你本地拉下来的镜像就是 arm64。Docker 在你 pull 的时候才解析平台,所以还是要以docker image inspect本机实际镜像的结果为准。

如果你在当前机器上看到的是 amd64,后面传到 ARM64 真机上,执行时就会碰到exec format error。这个错在 x86 机器上跑 arm64 镜像时也会出现,严重情况下内核会直接报类似bad linux arm64 image magic!的信息,那说明镜像文件头与 CPU 架构完全不匹配。看到这类问题先别急着排查 Harbor 配置,先回头查架构。

3. 组装离线安装包:替换镜像包,让 install.sh 在 ARM64 上跑通

镜像拉好、架构也验证过,接下来就是把自制的 ARM64 镜像包装回官方离线安装包里。这个环节做法很多,有人直接到目标机器上手动docker load,也有人把整个离线包重新打包一份。这里我推荐替换官方包里的harbor.v2.13.1.tar.gz,因为install.sh的执行流程是死板的,它一定会 load 包内自带的那份镜像包,手动提前 load 也会被它再次覆盖,所以直接从源头替换才最干净。

3.1 两种装配思路,为什么选替换 tar 而不是手动 load

一种常见做法是:目标机器先手动docker load自制的 ARM64 镜像,然后再执行官方install.sh。听着合理,但install.sh内部会自带执行一次docker load -i ./harbor.v2.13.1.tar.gz。如果包里的镜像还是 amd64,这次 load 会把你手动加载的 arm64 镜像按同名 tag 覆盖掉,等于白做。

第二种做法是替换 tar 包。把第 2 章导出的harbor.v2.13.1-arm64.tar.gz改名成harbor.v2.13.1.tar.gz,替换掉官方离线包里的原文件。之后install.shload 到的就是 arm64 镜像,compose 启动时镜像名和 tag 也完全对得上。这个方案还能保留官方安装脚本的原始流程,后续升级维护也贴近官方操作习惯。

3.2 替换命令与第一次执行 install.sh 的完整流程

把自制镜像包和官方离线包都上传到目标 ARM64 服务器后,按下面步骤操作:

# 进入工作目录,解压官方离线安装包 tar -xzf harbor-offline-installer-v2.13.1.tgz cd harbor # 原包改名留底,别删,出问题还能找回 amd64 原版 mv harbor.v2.13.1.tar.gz harbor.v2.13.1.tar.gz.x86_backup # 自制 ARM64 镜像包复制进目录,并替换成官方脚本期望的文件名 cp /data/harbor.v2.13.1-arm64.tar.gz ./harbor.v2.13.1.tar.gz # 生成配置 cp harbor.yml.tmpl harbor.yml vim harbor.yml # 一键安装;脚本会自动 load 当前目录的镜像包 sudo ./install.sh

参数上说明几个点:/data是镜像包临时存放的路径,按自己习惯改;替换后的harbor.v2.13.1.tar.gz必须保持这个文件名,install.sh脚本里写死的就是这个名字;留底的原包名改成.x86_backup后缀,是为了避免和新的.tar.gz冲突。

执行install.sh时,注意屏幕输出的Loaded image:行。正常情况下应该能看到goharbor/harbor-core:v2.13.1等一长串镜像逐个加载。如果这一阶段出现exec format error,说明这个自制包本身就不是 arm64,回去做第 2 章的核对。如果加载顺利,但后面docker compose up起容器时报某个镜像 missing,大概率是镜像数组漏了,回可联网机器补拉对应镜像再重新导出。

3.3 目标机器没有 Docker 时,怎么离线装 Docker 环境

有的 ARM64 目标服务器是真正的裸机,连 Docker 都没有。这时先把 Docker 引擎装上再谈 Harbor。如果你的内网源里有 Docker 的 apt 源,那直接 apt 安装即可;完全没有内网源时,我一般会在可联网的同架构机器上把 docker 相关 deb 包用apt download抓下来,或者直接拷贝 docker 二进制和 containerd 静态包过去。

# 在可联网的 Ubuntu ARM64 机器上 mkdir docker-debs && cd docker-debs apt-get download docker-ce docker-ce-cli containerd.io docker-compose-plugin # 打包传输到内网机器 tar -czf docker-debs-arm64.tar.gz ./docker-debs

到目标机器解压后执行:

tar -xzf docker-debs-arm64.tar.gz cd docker-debs sudo dpkg -i ./*.deb || sudo apt-get -f install -y

要注意版本,Harbor 2.x 对 Docker 版本有硬性要求,Docker 版本太低,compose 的某些配置项不识别,装起来会莫名报错。装完后用docker version看一眼,Server 和 Client 版本都别太老。

4. harbor.yml 配置与部署:端口、密码、数据目录三个必调参数

镜像和安装脚本都准备好了,最后成不成,一半看harbor.yml配得对不对。Harbor 的配置集中在harbor.yml,模板里有大量注释和默认项,真正部署时只需要抓住三个必调参数:hostname、HTTP/HTTPS 端口、data_volume。其他项保持默认也能跑,但这三个参数定得不合理,后面改起来非常痛苦。

4.1 hostname、端口和 data_volume 怎么设

hostname是 Harbor 对外提供服务的地址,这个值不仅是页面访问地址,还会写进镜像 tag 里。你 push 一个镜像时的完整地址,例如192.168.209.133:8080/library/nginx:v1,这前面的主机名就必须和hostname参数一致,否则 push 出去的项目路径都是错的。内网部署直接把hostname写成服务器 IP 最省事,不要写localhost或127.0.0.1,那样外网机器没法访问,docker 客户端登录时还会因为地址不匹配出现奇怪的连接问题。

端口方面,Harbor 默认走 80 和 443。如果 80 端口被占用,或者你想让页面用8080起,改http.port就行。这里有一个常见误区:改了http.port之后,访问地址变成http://ip:8080,docker login 和 docker tag 的地址也要跟着带端口,一个地方漏改,后面 push 就找不到仓库。HTTPS 部分如果暂时没有证书,直接把注释解开并填证书路径就行,但多数内网离线环境第一轮都是先跑 HTTP,后者更简单也更不容易踩证书坑。

data_volume是数据落盘目录,Harbor 的数据库、镜像存储、证书密钥全部存在这个目录下面。默认值是/data/harbor,建议改到一个空间大、最好单独挂载的路径,例如/opt/harbor/data。这个参数最坑的地方在于,一旦容器跑起来生成了数据,再改路径不会自动迁移,等于把已有数据丢在一边。所以第一次部署就要定好。

4.2 最小可用配置:先跑 HTTP,把 HTTPS 留到以后

下面是一份内网 ARM64 环境最小可用的harbor.yml:

# Harbor v2.13.1 最小配置,适用于内网离线部署 hostname: 192.168.209.133 http: port: 8080 # 暂时注释掉 https,避免因为证书问题导致起不来 # https: # port: 443 # certificate: /data/harbor/certs/server.crt # private_key: /data/harbor/certs/server.key # 初始管理员密码,要求至少 8 位且包含大小写和数字 harbor_admin_password: Harbor12345 # 数据目录,务必提前规划,后续迁移很麻烦 data_volume: /opt/harbor/data

配置里的harbor_admin_password是初始密码,首次登录admin时用的就是它。模板里默认值是Harbor12345,上线前一定改掉。database相关参数如果是单机部署、使用内置 PostgreSQL,可以不动;只有外部数据库时才需要显式配置database段的连接信息。

这里要特别说一句,https段如果当前不用,直接注释掉而不是留空路径。之前见过有人把证书路径填成一个不存在的文件,结果./install.sh执行到生成配置时,因为找不到证书文件直接退出。Harbor 对配置的校验比想象中严格,宁可先全注释、跑通再加密。

4.3 部署后验证:容器清单、接口探活和 docker login 一条线

./install.sh跑完后,用下面的命令验证服务状态:

# 查看 Harbor 相关容器是否全部进入 Up 状态 docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}' | grep -E 'harbor|nginx|registry|core|jobservice|portal|redis|db|exporter' # 接口探活,返回字符串 pong 即正常 curl -s http://192.168.209.133:8080/api/v2.0/ping # 用 docker 客户端做一次真实登录 docker login 192.168.209.133:8080 -u admin -p Harbor12345

探活时,如果curl返回一串 HTML 或跳转页面,别急着下结论,先用curl -s -o /dev/null -w "%{http_code}"看 HTTP 状态码。Harbor 的 API 路径/api/v2.0/ping在 2.x 里是健康检查接口,返回pong才代表核心服务正常。页面能打开但 ping 不通,多半是 core 服务没起来,要去docker logs里找原因。

docker ps输出里,容器名以harbor-开头,比如harbor-core、harbor-portal、harbor-registry。正常时全部是Up状态,如果出现循环重启,立刻看日志,尤其关注是不是因为架构不对导致exec format error。

5. ARM64 离线部署避坑:架构报错、推送失败与升级前后的排查记录

这一章把我在 ARM64 离线部署 Harbor 过程中踩过的、以及在群里看别人踩过的五个高频问题列出来。每个问题都按现象、原因、解决三步走,大部分问题和 Harbor 本身没关系,全是环境或使用习惯造成的。

5.1 容器反复重启,日志只给一句 exec format error

现象:docker ps看到 harbor-core 或 harbor-registry 状态是 Restarting,docker logs harbor-core只显示一行exec /usr/bin/core: exec format error。

原因:镜像包里的二进制是 amd64 架构,放到 ARM64 主机上跑不起来。最常见于直接把官方离线包拿去装,或者手动 load 时 load 错了包。

解决:先在安装机上执行docker image inspect goharbor/harbor-core:v2.13.1 --format '{{.Architecture}}',确认输出是arm64。如果架构不对,按第 2 章重新拉取,按第 3 章替换harbor.v2.13.1.tar.gz,然后sudo ./install.sh重新安装。

5.2 harbor 推送失败:登录时 get https://192.168.209.133/v2/ dial tcp 连接被拒

现象:docker login 192.168.209.133:8080或docker push时,报下面这类错误:

Error response from daemon: Get "https://192.168.209.133/v2/": dial tcp 192.168.209.133: ... connect: connection refused

原因分三种:第一种,Harbor 容器没起来,尤其是 nginx 或 core 挂了;第二种,harbor.yml里http.port改成了别的端口,但 docker login 命令还是用默认 80,流量被拒;第三种,目标机器和 Harbor 之间有防火墙,端口没放通。

解决:先curl -s http://192.168.209.133:8080/api/v2.0/ping看服务通不通;通的话检查 docker 客户端地址是否带端口,不带端口默认走 443,和配置不一致就会出现 dial tcp 连不上。确认端口没问题后,再检查宿主机防火墙,ufw status或firewall-cmd --list-all看有没有放行对应端口。这个错最常见的原因不是配置而是端口没带对,登录和推送地址必须与hostname:port完全一致。

5.3 在 x86 上用 qemu 模拟 arm64 拉镜像,真机上根本不能用

现象:你在 x86 笔记本上装了个 qemu 模拟的 arm64 虚拟机,在里面用 docker 拉了一堆 goharbor 镜像,导出后传到真机 ARM64 服务器,却仍报架构错误;有的场景直接报bad linux arm64 image magic!。

原因:qemu 用户态模拟并不能改变 Docker 宿主机解析镜像的方式。镜像层到底是 arm64 还是 amd64,取决于镜像构建时的架构和 Docker Engine 解析 manifest 的平台,而不是 qemu 模拟出来的uname。在 x86 机器上做出来的东西,拿到真机上跑,往往还是 amd64。

解决:不要在 x86 上用 qemu 模拟出来的环境做这个事。老老实实找一台真实的 ARM64 机器,哪怕是云厂商的 ARM64 实例,在上面执行docker pull和docker save。这个环节省不得,我也在这里翻过车,抱着侥幸心理省一台机器,结果浪费了整个下午排错。

5.4 docker login 被证书拦截,连私服都连不上

现象:Harbor 服务正常,登录时却报x509: certificate signed by unknown authority,或者提示证书 CN 不匹配。还有一种是http: server gave HTTP response to HTTPS client。

原因:Harbor 配置开了 HTTPS,但用的是自签证书,docker 客户端不信任这本证书;或者 Harbor 配了 HTTP,而 docker 客户端默认对非 localhost 仓库走 HTTPS。

解决:两种选一个。第一种,继续用 HTTPS,把 Harbor 的 CA 证书加到每台 docker 客户端的/etc/docker/certs.d/目录里。第二种,内网环境图省事,直接让 docker 跳过安全校验:编辑/etc/docker/daemon.json。

{ "insecure-registries": ["192.168.209.133:8080"] }

改完重启 docker:

sudo systemctl restart docker

这里提醒一下,修改daemon.json会重启 Docker,本机所有容器都会短暂中断,不要在业务高峰期操作。而且insecure-registries里的地址要带端口,和登录地址保持一致。

5.5 升级前没有备份,数据库 schema 迁移失败后什么都找不回来

现象:从低版本升级到 v2.13.1,upgrade.sh执行到数据库迁移阶段报错,Harbor 起不来。有人想直接回退镜像版本,但数据库已经做过迁移,低版本连不上高版本的库,整个数据目录变成半死不活的状态。

原因:Harbor 的版本升级不只是镜像 tag 变了,数据库结构也会变。迁完一旦失败,没有停机备份就只能拿残留数据碰运气。

解决:升级前把data_volume整个目录打包备份,再把 docker 卷也备一份。备份命令如下:

# 停服务,避免备份过程中数据写入 cd harbor sudo docker compose down # 打包整个数据目录,这一步是后悔药 sudo tar -czf harbor-data-backup-$(date +%Y%m%d).tar.gz /opt/harbor/data

备份完再解压新版离线包,按第 3 章方法替换镜像,把旧harbor.yml复制到新版目录,执行sudo ./upgrade.sh。升级脚本会先检查当前版本,再做数据库迁移。备份文件放机器上别删,至少保留到确认业务正常一周。

6. 升级到 v2.13.1 并做冒烟验证:备份、救回、推送三连

如果是已经跑着 Harbor v2.11 或 v2.12 的环境想升级到 v2.13.1,不能直接把新镜像替换上去重启。Harbor 的版本升级有固定套路,官方脚本叫upgrade.sh,它会读取旧的版本信息,然后按顺序迁移数据库结构。我一般这么走:先停服备份,再把新版离线包解压,把旧harbor.yml复制过去,最后执行sudo ./upgrade.sh。升级脚本跑完后,容器会重建,这个阶段不要急着进页面,先等两分钟让数据库连接池起来。

升级完之后的验证,我习惯做一次 docker push 冒烟测试,既能验证镜像服务,也能把权限、网络、存储一次测到:

# 登录新版本 Harbor docker login 192.168.209.133:8080 -u admin -p Harbor12345 # 拉一个本地镜像,打好 tag,push 到 Harbor 的 library 项目 docker pull busybox:latest docker tag busybox:latest 192.168.209.133:8080/library/busybox:smoke docker push 192.168.209.133:8080/library/busybox:smoke # 从 Harbor 拉下来,验证完整闭环 docker rmi 192.168.209.133:8080/library/busybox:smoke docker pull 192.168.209.133:8080/library/busybox:smoke

整个过程跑通,说明升级后的核心链路没问题。别只看容器起来就宣布成功,到这里为止,最容易漏掉的是升级后数据库里旧的镜像仓库清单还在不在;如果 push 后页面里能看到这个smoketag,那升级确实没丢数据。

最后说个习惯。我每次升级前都要做一次完整备份,而且备份文件命名里带上日期。有一次图省事没做备份,数据库在迁移中途报错,最后只能从残留数据里手工捞项目配置,折腾到凌晨。自此之后,凡是涉及 Harbor 这类带数据库状态的服务,停服备份和升级后冒烟测试都变成固定动作。这套流程不复杂,但能给你兜住绝大多数意外,希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询