☰
ARM服务器离线部署Harbor:aarch64离线包安装与避坑指南
2026/10/10 3:52:10 网站建设 项目流程

简介:面向国产化ARM架构服务器,此离线安装包提供Harbor 2.10.2镜像仓库的完整部署能力,适用于内网隔离或无法直连外网的环境,帮助运维人员快速搭建私有容器镜像仓库。资源压缩包为tgz格式,整体约650.11MB,共包含6个文件:两个Shell安装配置脚本、一个Harbor镜像离线压缩包、一个环境预检脚本、一个配置模板以及一份开源授权文件,各文件用途明确,便于按需查阅。当前已有98人学习/浏览该资源,适合正在进行国产化适配、ARM平台迁移或内网安全建设的团队参考。通过该资源可获得一套开箱即用的离线部署方案,包括自动化安装脚本、可修改的配置文件模板和预打包的镜像文件,无需繁琐下载与编译,执行脚本即可完成Harbor部署,为后续镜像管理、权限控制和运维监控提供可靠基础,也可作为同类国产化项目部署的参考样例。

1. 为什么在 ARM 服务器上部署 Harbor 就得用这个 aarch64 离线包

拿到harbor-offline-installer-aarch64-v2.10.2.tgz这个安装包,说明你正准备在 ARM64 架构的服务器上部署 Harbor 镜像仓库,而且大概率是个内网环境——没有互联网,没法在线拉镜像、跑在线安装器。很多第一次接触 ARM 服务器的工程师会直接去下载 x86 版的离线包,结果install.sh一执行就报“exec format error”,这才意识到 aarch64 和 x86 是两套完全不同的二进制世界。这份离线包就是把 Harbor 运行所需的全部镜像、二进制、配置模板和安装脚本按 ARM64 架构打包好,解压、改配置、执行安装脚本三步就能在不通外网的 ARM 机器上把仓库跑起来。它适合三类人:正在搭信创环境的运维、把镜像仓库迁到 ARM 边缘节点的开发,以及给内网做基础设施交付的集成工程师。这篇文章就把这个离线包的目录结构、关键配置、安装流程和常见坑一次讲透。

2. 先看清楚离线包:目录结构、内置镜像与安装流程

2.1 离线包和在线安装的本质区别

在线安装 Harbor 时,install.sh会去 Docker Hub 拉取goharbor仓库下的多个镜像,包括核心组件、数据库、Redis、Nginx 入口等。这个过程在公网环境畅通时体验很好,版本也永远跟随你下载的安装器。可一旦到了内网,Docker Hub 的域名直接被防火墙挡住,docker pull超时重试到怀疑人生。

离线安装包解决的是“镜像从哪里来”的问题。它把安装所需的全部容器镜像预先导出成 tarball,打包进一个 tgz 里。安装脚本在启动服务前会先执行docker load把这些镜像导入本地 Docker,再通过docker-compose把全部服务拉起。也就是说,离线安装变成了“本地导镜像 + 本地起容器”两个动作,完全不依赖外网。

在 aarch64 架构上,这个区别被放得更大。ARM 服务器上跑的任何容器镜像,都必须是linux/arm64架构的版本。x86 离线包里的镜像,在 ARM 机器上docker load能成功,但容器一启动就会因为 CPU 指令集不匹配直接崩掉。所以拿到安装包后,第一件事就是确认包名里带的是不是aarch64,而不是amd64。这个核验只需要一条命令:

file harbor-offline-installer-aarch64-v2.10.2.tgz # 或者 tar -tzf harbor-offline-installer-aarch64-v2.10.2.tgz | head -20

file命令输出的结果里会标明 tgz 文件的压缩格式和架构信息,但更直接的是用tar -tzf列出包内文件清单。如果你看到common.sh、harbor.v2.10.2.tar.gz、install.sh、docker-compose.yml这类文件,说明包结构是标准离线安装包;如果第一屏就出现大量.buildinfo或manifest.json,那可能是容器镜像归档文件而不是安装器,处理方式完全不同。这个差异值得在下文展开。

2.2 解压后先看这两处:harbor.yml 和镜像 tarball

拿到离线包后,我的习惯是先解压到一个固定目录再动手,不要直接在/root下乱铺。Harbor 安装目录本身会作为数据目录的一部分被引用,后续做备份或迁移时,一个干净的根目录会省很多事。

mkdir -p /opt/harbor && tar -xzf harbor-offline-installer-aarch64-v2.10.2.tgz -C /opt/harbor cd /opt/harbor ls -lh

解压完成后你会看到install.sh、harbor.yml.tmpl、common.sh、harbor.v2.10.2.tar.gz等文件。其中harbor.v2.10.2.tar.gz才是真正的镜像仓库归档文件,几 GB 到十几 GB 都很常见,它内部包含了 Harbor 全组件镜像的 Docker 格式归档。安装脚本执行时,会先对这个文件做docker load,所以磁盘空间一定要留够,按照归档文件体积的 1.5 到 2 倍预留比较稳妥。

另一个关键文件是harbor.yml.tmpl。它是 Harbor 配置的模板,里面写了所有可配置项的默认值和注释。安装脚本不会直接读取这个模板,它要求你先把它复制一份为harbor.yml并按需修改:

cp harbor.yml.tmpl harbor.yml vim harbor.yml

这一步是整个部署里唯一需要人工介入的配置环节。后续的install.sh会读取harbor.yml里的参数,去生成docker-compose.yml和各类服务的环境变量。如果跳过复制和修改直接执行install.sh,脚本会提示缺少配置文件并退出。所以先复制、再修改、后安装的顺序是固定的。

2.3 执行 install.sh 之前,先搞清楚它到底做了什么

install.sh表面上看是一条命令的事,但它内部按顺序做了四件事。第一,检查目标机器上 Docker 服务是否可用、docker-compose是否存在,版本太低会直接中断。第二,执行docker load导入harbor.v2.10.2.tar.gz中全部镜像,这个过程在 ARM 机器上通常比 x86 慢不少,因为磁盘 IO 和压缩解压都依赖 CPU。第三,根据harbor.yml生成全套运行时配置,包括 Nginx 路由、核心服务环境变量、数据库初始化参数等。第四,调用docker-compose up -d把服务全部拉起来,然后执行一轮健康检查。

理解了这一步,你就知道安装时最怕什么:磁盘空间不够、Docker 版本太老、harbor.yml里写错了参数。前两种会直接报错退出,第三种最隐蔽——配置语法没问题,但 hostname 和 IP 对不上,导致服务起来后客户端访问不到。

在 aarch64 机器上还有一件 x86 上很少遇到的事:镜像导入完成后,脚本会用docker images检查 goharbor 镜像的架构标签,确保全部是arm64。这本来不需要人工参与,但如果你的机器上之前残留过同名 x86 镜像,docker load会保留旧的 tag 并标记为新导入的架构,导致组件之间出现架构不一致。所以干净的 Docker 环境是安装成功的前提:

docker images | grep goharbor

安装前执行一次,如果有残留镜像但确认它们没被容器使用,建议直接删掉。这个习惯能避免不少看起来像配置问题的架构混乱。

3. 改好 harbor.yml:aarch64 环境下的关键配置

3.1 hostname 和端口在离线环境下的正确写法

harbor.yml里第一个必改项是hostname。它不能是localhost,因为 Harbor 内部的组件需要通过这个域名或 IP 互相访问,Nginx 也会拿它来做路由。在内网环境,最常见的选择是直接写服务器的 IP,比如192.168.209.133。如果你有内部 DNS 且解析正常,也可以写完整域名,但要注意 Docker 客户端所在机器必须能解析并通过这个域名访问到 Harbor。

端口方面,默认配置是 HTTP 80、HTTPS 443。离线内网环境通常没有正规 CA 签发的证书,所以我一般只保留 HTTP 端口,把 HTTPS 配置注释掉。这样做的好处是客户端配置简单,坏处是 Docker 必须把该地址加入insecure-registries,否则会拒绝通过 HTTP 传输镜像。这个在后面会专门讲。

hostname: 192.168.209.133 http: port: 80 https: port: 443 certificate: /your/cert.pem private_key: /your/key.pem

注意,如果你不打算启用 HTTPS,就把https段整个注释掉而不是保留端口却删掉证书文件路径。Harbor 的配置校验很严格,给了 HTTPS 端口却没有证书文件,install.sh会直接报“missing certificate or private key”并退出。反过来,只注释 HTTPS 段但保留端口也是错误——校验逻辑会读取该段,发现端口和证书都存在但证书路径不存在,同样会中断安装。最干净的做法是整段注释。

另外,http.port不建议改成 8080 之类的非默认端口。虽然 Harbor 支持,但 Docker 客户端配置insecure-registries时,如果你用 IP:端口 的方式仍然需要显式标端口。默认 80 端口在 Docker 客户端里可以省略端口直接写 IP,省掉很多不必要的麻烦。

3.2 数据目录和存储后端的选型

data_volume是 Harbor 存放数据库文件、Redis 持久化数据、注册表存储和日志的根目录。横向对比 x86 部署,ARM 服务器很多是磁盘性能一般的整机,所以数据目录的选型不能只看剩余空间,还要看 IO 能力。

data_volume: /data/harbor

这个路径会在install.sh执行时被创建并挂载进多个容器。如果/data是一个单独的数据盘,最好提前确认它已经完成格式化并挂载,不要等到脚本创建目录时才暴露问题。Harbor 对数据目录的权限要求是root或具备完整读写权限的系统用户,如果目录权限不对,PostgreSQL 容器会初始化失败,反复重启。

从存储后端角度说,Harbor 默认把镜像存在data_volume下的registry子目录。这个目录本质上就是 Docker Distribution 的存储目录,格式是分层存储的 blob 和 manifest。如果你未来打算做冷备或迁移,直接拷贝整个data_volume是最稳妥的方式;如果追求更大容量,也可以在harbor.yml里配置外部对象存储,比如 S3 或 MinIO 兼容接口。但在 ARM 内网环境,外部对象存储意味着又多一个服务要维护,我一般不去动它,保持默认目录存储。

还有一个容易被忽略的参数是log段。默认日志级别是info,但调试安装问题时,可以先临时改成debug。注意这只是运行级别,不影响持久化日志文件的位置:

log: level: info local: rotate_count: 50 rotate_size: 200M

rotate_count和rotate_size控制日志轮转策略。ARM 服务器如果存储紧张,这两个值可以适当调小。如果只是排障,装完再改回info并重启服务即可,不用重新跑安装脚本。

3.3 TLS 证书:没有公网域名的内网怎么做

离线内网环境的证书问题,本质上是“要不要自签”和“自签证书怎么分发”的问题。如果你能接受 HTTP 明文传输,那就按前面说的,把整个https段注释掉,走insecure-registries方案。这个方案对镜像仓库来说足够安全,因为镜像内容通常不是最高机密,而内网链路本身相对可信。

如果你的安全策略强制要求仓库必须走 HTTPS,那就得生成自签证书并在每台客户端机器上配置信任。生成证书的标准做法是用openssl一次性生成 CA 证书、服务器证书和私钥:

openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -days 3650 -out ca.crt -subj "/CN=Harbor-CA" openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/CN=192.168.209.133" openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650

这段命令生成三层关系:CA 自签根证书、用它签发服务器证书、服务器证书的 CN 必须和harbor.yml里的hostname完全一致,除非你加了 SAN。IP 地址做 CN 在现代 OpenSSL 里需要配置 SAN 扩展,否则 Docker 客户端校验时依旧报证书不匹配。实际生产中我通常会直接写一个带subjectAltName的扩展配置文件,把 IP 和可能的域名都写进去,一劳永逸。

关键点在于,自签证书模式下客户端 Docker 需要两件事同时满足:insecure-registries或 CA 信任列表里必须有这个 CA,且服务器证书的 SAN 里必须包含访问地址。很多工程师只配置了第一个,忽略了第二个,结果依然报证书校验失败。这个坑在 aarch64 环境里更容易让人困惑,因为 ARM 上 Docker 版本较老,对 SAN 的支持和报错信息都不太直观。

4. 跑通安装:install.sh 执行、客户端配置与推送验证

4.1 执行安装命令:从脚本输出里读出真实进度

配置好harbor.yml后,执行安装脚本。官方推荐带--with-notary或--with-trivy等参数的扩展安装,但离线包环境下我建议先做最小安装,不带任何扩展:

cd /opt/harbor ./install.sh

脚本会先打印一条检查清单,包括 Docker 版本、docker-compose 版本、Python 版本等。如果 Docker Compose 版本低于要求的 1.10,脚本会提示你升级;在 ARM 机器上最容易踩的是 yum 源里只有老版本 docker-compose,装出来的 Python 依赖不完整。需要特别留意:Harbor 2.x 要求 Docker Compose 支持版本 2 语法,docker-compose --version至少要 2.0 以上才算过。

随后脚本会输出类似Loading harbor.v2.10.2.tar.gz的日志,并打印每一个被导入的镜像名称。这一步最耗时,也最容易因为磁盘满而中断。观察方法很简单:docker images里 goharbor 仓库下的镜像 tag 全部出现,且 IMAGE ID 的前几位彼此不同,说明导入完整:

docker images | grep goharbor

导入完成后会进入Creating network、Creating volume阶段,最终以一段完整的服务状态列表收尾。脚本结束后,用docker ps确认全部容器处于Up状态。注意这里不要只看一个容器,Harbor 2.10 的完整服务集中包含 nginx、核心服务、数据库、Redis、注册表等多个容器,任何一个不在运行都会影响功能。

4.2 配置 docker daemon 的 insecure-registries

安装完成不代表客户端就能直接推镜像。Docker 客户端默认只信任 HTTPS 仓库,而我们在 3.1 里选择了 HTTP 模式,所以必须在所有需要访问该仓库的机器上,把 Harbor 地址加入 Docker daemon 的不信任地址列表。修改/etc/docker/daemon.json:

vim /etc/docker/daemon.json

写入如下内容:

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

注意,如果你在harbor.yml里保留了 HTTP 默认端口 80,这里写 IP 不需要带端口;如果你改成了 8080,则必须写"192.168.209.133:8080"。修改后重启 Docker:

systemctl restart docker

这一步在 ARM 机器上有个特别容易忽略的副作用:重启 Docker 会中断所有正在运行的容器。如果这台机器上还跑着其他业务容器,你需要提前确认它们的重启策略,否则 Docker 重启后它们不会自动恢复,直接造成业务中断。实际操作中,我一般会在执行systemctl restart docker前,先用docker ps检查当前容器列表,并逐一看一下RestartPolicy。

4.3 登录并推送一个镜像:验证安装是否真正可用

配置好 daemon 后,从一台客户端机器或本机验证整个链路。先做登录测试:

docker login 192.168.209.133 -u admin -p Harbor12345

默认管理员账号是admin,默认密码是Harbor12345。如果你在安装前没有修改,这里直接登录会成功。如果登录报错,先检查 daemon.json 的格式是不是合法 JSON,再检查 Harbor 的 nginx 容器是否在监听 80 端口。

登录成功后,推送一个本地镜像做全链路验证。例如本地有一个名为demo-app:latest的 aarch64 镜像,需要先打上仓库地址的 tag 再推送:

docker tag demo-app:latest 192.168.209.133/library/demo-app:latest docker push 192.168.209.133/library/demo-app:latest

library是 Harbor 内置的公开项目,推送进去不需要额外创建项目,适合做冒烟测试。推送成功的标志是输出latest: digest: sha256:...,并且最后一行是status: pushed。如果推送时报denied: requested access to the resource is denied,说明该项目不存在或者你不是该项目的成员。要么去 Web UI 创建一个项目,要么直接推到library。

推送成功后可以顺手把镜像拉回来测试完整性——虽然刚推上去的镜像拉取一般不会出问题,但用一个docker pull确认 manifest 和 blob 读写正常,等于把 Harbor 的后端存储链路也验证了。这一步不能省,因为有的安装失败是异步发生的:镜像推写成功,但数据库里的元数据写入失败,这时候拉取就会被拒绝。

5. 避坑排查:ARM 离线部署的常见问题与修复

5.1 现象:install.sh 执行后卡在docker load阶段,或长时间无输出

原因排查:最常见的是磁盘空间不足。harbor.v2.10.2.tar.gz解压出来后的镜像数据会写入 Docker 的 overlay2 目录,这个目录默认在/var/lib/docker。ARM 机器上/var分区往往很小,如果docker load过程中写满,Docker 会静默挂起而不是主动报错。

解决:先执行df -h检查/var/lib/docker所在分区的可用空间,确认是否大于归档文件体积的 1.5 倍。如果空间不足,把 Docker 的数据目录迁移到大分区,修改/etc/docker/daemon.json中的>{ "data-root": "/data/docker" }

然后重启 Docker 再重新执行./install.sh。注意,重新执行前要把上次未完成导入的残留镜像清掉,否则同名镜像会被 skip 或冲突:

docker system prune -a

另一个导致卡住的原因是 ARM 机器上 Docker 版本过低,docker load处理压缩归档异常缓慢。升级 Docker 到 24.x 以上即可解决。

5.2 现象:docker login 报错http: server gave HTTP response to HTTPS client

原因排查:这条报错信息非常典型,含义是 Harbor 的 nginx 监听的是 HTTP 80 端口,但 Docker 客户端默认对未标记的仓库走 HTTPS 请求,结果收到 HTTP 响应直接中止握手,客户端认为服务器配置有问题。

解决:确认你已按 4.2 节正确配置了insecure-registries。如果确认改了还报错,先看daemon.json的 JSON 格式是否合法,可以用python -m json.tool校验,再确认重启 Docker 动作真的生效了。很多 ARM 机器上用systemctl restart docker后,Docker 进程确实重启了,但 daemon 读取的还是旧配置,因为daemon.json被放到了错误路径。正确的路径永远是通过docker info输出来确认。

docker info | grep -A2 "Insecure"

如果输出里没有192.168.209.133,说明配置没有被读取,检查/etc/docker/daemon.json是否存在且属于 root 用户。

5.3 现象:docker push 报错405 Method Not Allowed或 manifest 不兼容

原因排查:这个在 ARM 环境比 x86 更常见。Docker 客户端推送镜像时,会根据镜像的 manifest 类型发送对应请求。如果你本地镜像是通过docker buildx构建的多架构镜像,或者某个镜像平台字段写的是linux/amd64但实际文件是 ARM 指令集,Harbor 的 registry 组件在解析 manifest 时会拒绝写入。

解决:先核验镜像的真实架构:

docker image inspect demo-app:latest | grep Architecture

输出必须包含arm64或aarch64。如果显示amd64,说明镜像本身就是 x86 的,Harbor 拒绝是正确的。需要重新在 ARM 机器上构建或拉取对应架构的镜像。如果是 buildx 构建的 manifest list,推送前先合并成单架构镜像或直接推送 manifest list 到支持多架构的 Harbor 项目。Harbor 2.10 本身支持多架构 manifest,但默认项目可能需要显式开启“允许 manifest list”的配置。内网环境用不到多架构分发时,建议直接禁用该特性,避免误推送多架构镜像导致磁盘浪费。

5.4 现象:Harbor 服务全部启动,但 Web UI 打开极慢,或登录后页面报错

原因排查:ARM 机器的 CPU 核数普遍较少,内存也偏小,而 Harbor 默认给数据库和 Redis 分配的资源参数是按 x86 服务器估的。如果机器只有 4GB 内存,docker-compose up会把 PostgreSQL 和 Redis 全部启动,但系统内存吃紧触发 swap 频繁换页,表现就是页面响应要十几秒,登录后列表加载失败。

解决:降低组件资源占用。最直接的办法是在harbor.yml的database和redis段调整参数。对 PostgreSQL 设置共享缓冲区上限,对 Redis 关闭持久化或缩短保存频率。还有一招很多项目里有效:只保留必要组件。离线包默认启动全组件,但如果你只需要做镜像仓库,不涉及漏洞扫描和签名,在install.sh时不要带额外参数,--with-trivy和--with-notary都会额外拉两个容器,白白吃掉内存。这些参数默认就是关闭的,所以确认你没加就行。

如果 UI 慢的问题只在首次访问时出现,后续就正常了,大概率是浏览器缓存和首次页面编译的问题,不需要处理。如果持续慢,检查docker stats看哪个容器占用 CPU 最高,通常需要给数据库容器增加shm_size:

database: shm_size: 1GB

Harbor 官方把数据库的/dev/shm默认设得很小,ARM 机器上默认值是 64MB,docker-compose里如果不显式指定,PostgreSQL 的临时文件写不满就会报错或卡顿。

6. 把离线安装的价值放大:批量导入存量镜像与日常维护

离线安装跑通只是第一步。真正让你省时间的是把现有服务器上的一批镜像批量搬到 Harbor 里。内网环境没有镜像中转机,最可靠的做法是镜像导出再导入。在一台源机器上把所有需要同步的镜像 tag 到同一仓库前缀下,然后循环导出:

docker save $(docker images --format '{{.Repository}}:{{.Tag}}' | grep '^demo' ) | gzip > images-backup.gz

然后在 Harbor 所在机器上导入:

gunzip -c images-backup.gz | docker load

再逐条打 tag 推送。这个过程不需要 Harbor 配合任何额外 API,只走 4.3 的推送链路,最稳妥。如果镜像数量特别多,我习惯写一个 for 循环,把仓库名和 tag 解析出来后直接 push,推送失败的单独记录到日志文件里再重试,避免一条失败中断整个批次。

日常维护方面,最重要的习惯是定期清理未使用的镜像和日志。Harbor 自带垃圾回收功能,但它回收的是后端存储层里没有被任何 manifest 引用的 blob,不是你在 UI 里删除的镜像。真正要定期做的是通过 API 或 UI 删除无用的仓库 tag,然后再触发垃圾回收。命令行的方式是:

docker exec -it harbor-registry registry garbage-collect /etc/registry/config.yml --dry-run

先试运行,看清楚哪些 blob 会被删除,再去掉--dry-run真正执行。ARM 机器磁盘空间宝贵,这个习惯能避免存储写满导致的镜像推送失败。整套流程跑一次之后,你的内网 ARM 环境就有了一个完全自持的镜像仓库,后续所有节点的镜像分发都不再依赖外网。最后留个我自己踩过的教训:不要在安装后立刻删除离线安装包,至少保留到第一批镜像验证推送完成,否则排障时你想看原始配置模板都找不到。希望帮到你。

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

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

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

立即咨询