简介:面向ARM64架构下的Kubernetes与Docker环境,Harbor v2.13.1离线安装包专为运维人员准备,核心价值是在无外网或内网隔离的ARM服务器上快速部署私有镜像仓库。压缩包为tgz格式,共6个文件,包含install.sh与common.sh两个Shell脚本,分别负责安装执行和公共函数加载;harbor.v2.13.1.tar.gz是完整的主镜像包,提供Harbor全部组件;prepare与harbor.yml.tmpl用于环境预检及核心配置模板,LICENSE文件则明确使用许可。整体约679MB,结构清晰,适合作为生产环境部署的基线资产。目前已有528人学习下载,特别适合在信创ARM平台、边缘计算节点或离线机房中搭建镜像管理系统的工程师。拿到手后可直接解压,依据模板修改端口、存储路径、证书等参数,再执行安装脚本即可完成部署;资源同时持续跟进新版离线包,便于后续升级维护。
1. 先讲清楚:Harbor 最新 v2.13.1 的 ARM64 离线安装包解决的是什么问题
一台只有 ARM64 CPU 的服务器,网络和公网隔离,却要搭一个生产可用的镜像仓库,这时候最常见的答案就是 Harbor 最新 v2.13.1 的 ARM64 离线安装包。它不是在线装完后“导出的备份”,而是官方为 aarch64 架构单独打的离线发行包:harbor-offline-installer-v2.13.1-arm64.tgz。包内置了 Harbor 全部组件镜像的 tar 捆,从解压到浏览器打开 UI,全程不需要外网。这个方案适合三类人:在做国产化适配的交付工程师、给边缘机房离线交付的平台组,以及接手 ARM64 服务器却不想折腾源码编译的运维。注意一个关键事实:它和 x86 的包是两个文件,拿错包在 ARM64 机器上启动时会直接报 exec format error,这一步走错后面全是黑匣子,后面会专门讲。
2. 安装之前:ARM64 离线包和 x86 包差在哪,环境怎么准备
2.1 架构差异与离线包的命名规则
标题里的“ARM64 版离线安装包”,在 Harbor 官方 Release 里对应的是带 arm64 后缀的 tgz。v2.13.1 这个版本同时发布几种安装介质:x86_64 机器上用 harbor-offline-installer-v2.13.1.tgz,aarch64 对应 harbor-offline-installer-v2.13.1-arm64.tgz,另外还有面向 Helm Chart 和 FIPS 加固的包。离线包内部结构一致,但 harbor.v2.13.1.tar.gz 里的镜像架构不同:x86 包导出的是 amd64 镜像层,ARM64 包导出的是 arm64/v8 镜像层。有人会问“Harbor 镜像不是 multi-arch 吗,我在 ARM64 上 load x86 包能不能跑?”manifest 列表确实是多架构的,但 docker save 导出的是具体某个镜像 manifest 下的层,不是把整个列表塞进去。你把 amd64 的 tar 在 aarch64 上 load 出来,docker images 能看到,docker run 才暴露问题:harbor-core、harbor-registry 这类容器一启动就抛 “exec format error”,反复 CrashLoopBackOff。
还有一类更隐蔽的情况:在 x86_64 开发机上用 qemu 模拟 ARM64 来“体验”这个离线包。qemu user-mode 确实能让 amd64 容器跑起来,但 Harbor 这种带数据库、JobService 多服务的编排,在 qemu 下经常遇到线程库和信号处理不兼容的问题,安装脚本里部分探测命令也会因为模拟器行为差异给出错误结果。可以做冒烟测试,但不建议作为交付依据。我一般拿到机器第一件事就是 uname -m 和 docker info 看 Architecture,再决定用哪个包。这个动作 10 秒钟,能省掉后面一整天的排障。
2.2 离线包里装的是什么:组件清单与数据流
解压离线包后,目录里最关键的是这几个文件:
mkdir -p /opt/harbor-install && cd /opt/harbor-install tar -xzf harbor-offline-installer-v2.13.1-arm64.tgz cd harbor ls -lh # 主要文件: # harbor.yml # 唯一需要手改的配置入口 # install.sh # 离线安装总入口 # prepare # 生成 docker-compose.yml 的预处理工具 # common.sh # 安装脚本公共函数,含镜像列表 # harbor.v2.13.1.tar.gz # 所有组件镜像的 docker save 产物 # LICENSE # 软件许可这里我不建议手动docker load -i harbor.v2.13.1.tar.gz,install.sh 会自动做,但你要知道这个 tar 很大。ARM64 版整包通常以 GB 计,加上解压后的镜像层、数据卷,磁盘预留至少要比 tar 大一倍。Harbor v2.13.1 的组件镜像包括:harbor-core(API 和调度核心)、harbor-registry(镜像存储,基于 Docker Distribution)、harbor-db(内嵌 PostgreSQL)、harbor-portal(前端页面和反向代理)、harbor-jobservice(GC、复制、漏洞扫描等后台任务)、harbor-log(统一日志收集)、harbor-registryctl(保护 registry 配置的辅助容器),再加上可选的 trivy-adapter(漏洞扫描)、notary-server / notary-signer(镜像签名)。这些服务安装后由 docker compose 编排,端口和数据卷都从 harbor.yml 映射出来。
理解这个组件清单对排错很重要。比如 push 失败时,你至少要知道流量先到 harbor-portal(监听 80/443),再反代到 harbor-core,最后由 core 把镜像层转发给 harbor-registry。任何一层的容器没起来,报错都像“连接被拒”。我见过有人把 harbor-portal 容器误删后,整整一天在改客户端 daemon.json,方向完全错了。
2.3 环境预检:磁盘、内存、Docker 与端口
离线包虽然免外网,但目标机器本身要满足最低运行条件。我习惯按生产标准而不是官方最低要求来预检,避免装完发现是纸面部署:
# 确认 CPU 架构必须是 aarch64 uname -m # 期望输出: aarch64 # 确认磁盘:镜像数据目录所在分区预留 100GB 以上(按实际业务量调整) df -h /opt /data # 确认内存:含 Trivy 建议 8GB 以上,不含至少 4GB free -h # 确认 Docker:版本不低于 20.10,且是标准的 containerd 运行时 docker version --format '{{.Server.Version}}'几个容易翻车的点注意一下。第一,如果是 Ubuntu 系,Harbor 容器默认用 host 网络和自定义 bridge,升级内核或重启 Docker 后 iptables 策略可能变化,安装前把 docker.service 设为开机启用,并确认没有防火墙规则挡 80/443。第二,Harbor 的 data_volume 不要放在系统盘根分区,镜像仓库的存量增长比想象快。第三,如果这台机器之前装过旧 Harbor,先确认 compose 项目名和网络名是否冲突,避免安装脚本“以为你升级”而实际是并存部署。我之前在一个残留环境上直接跑 install.sh,结果新旧两套容器同时监听 80 端口,谁也起不来。
Docker 与 compose 的版本配合也很关键。Harbor v2.13.1 的 install.sh 同时兼容 docker-compose v1(docker-compose 命令)和 v2(docker compose 子命令)。但如果你机器上同时有这两个命令,脚本默认用 compose v2,而你后续手动维护时用 v1 操作,两个命令看到的是不同的项目元数据,升级时就容易“找不到项目”。统一用一种语法,别混用。
3. 用离线包安装 Harbor v2.13.1:解压、改配置、跑脚本
3.1 解压与修改 harbor.yml:6 个必动参数
进入解压目录后,先备份默认配置再改,这是后悔药:
cd /opt/harbor-install/harbor cp harbor.yml harbor.yml.bak vim harbor.ymlHarbor v2.13.1 的配置项很多,但离线部署真正需要动的是下面这 6 个。改错了不至于立刻报错,但后续 push/pull 一定会反噬,所以一次改对。
| 参数 | 默认值 | 离线环境建议 |
|---|---|---|
| hostname | reg.mydomain.com | 填客户端能访问到的 IP 或域名,比如 192.168.209.133 |
| http.port | 80 | 保持 80,除非和系统服务冲突;客户端端口要与此一致 |
| harbor_admin_password | Harbor12345 | 至少 12 位,包含大小写和数字;首登后建议轮换 |
| data_volume | /data | 改成挂载大分区的绝对路径,例如 /data/harbor |
| database.password | root123 | 改成独立强密码,别和 admin 密码相同 |
| trivy.skip_update | false | 离线环境改成 true,否则 Trivy 启动会尝试连公网更新漏洞库 |
说明一下关键逻辑。hostname 是最容易踩坑的,如果填 localhost 或者 127.0.0.1,外部机器 push 时 Docker 客户端把仓库地址解析到它自己的回环地址,直接连接被拒。建议填局域网 IP 或规划好的域名,并让所有客户端能解析到这个地址。http.port 改动时,客户端 insecure-registries 里的端口也要跟着变,两处不一致是高频翻车点。data_volume 决定镜像 blob 落在哪,后续迁移备份都依赖这个路径,升级时路径不能变,否则旧数据就像消失了一样。
3.2 prepare 与 install.sh:核心命令到底干了什么
配置改完后,官方离线安装入口是 install.sh,但很多新人不理解 prepare 的作用。install.sh 内部会调用 prepare,不过我建议手动跑一次 prepare 来暴露问题,减少把错误攒到启动阶段:
# 预处理:基于 harbor.yml 生成 docker-compose.yml 和配置文件 ./prepare # 如果上面输出正常,再执行安装;按需开启 Trivy 和 Notary sudo ./install.sh --with-trivy --with-notaryinstall.sh 的执行顺序大致是:读取 common.sh 里的镜像列表 → 用 docker load 导入 harbor.v2.13.1.tar.gz → 检查 compose 是否存在 → 调用 prepare 生成 docker-compose.yml 与各组件配置 → 最后 docker compose up -d 拉起所有服务。几个容易忽略的点:install.sh 需要 root 或 sudo 权限,因为要创建数据卷目录、写日志相关配置;你不用事先生成 docker-compose.yml,prepare 会按 harbor.yml 生成,手动去改 docker-compose.yml 反而会在 prepare 时被覆盖。
--with-trivy 和 --with-notary 是按需组件。离线环境里 Trivy 的漏洞库如果不打算更新,必须保证 harbor.yml 里 skip_update: true,否则 trivy-adapter 容器反复重启。notary 只在需要镜像签名时开,默认可以不开,省一点内存。另外注意一个细节:prepare 脚本会检测 docker-compose 是否可用,如果系统里只有 docker 没有 compose 插件,安装会在这一步骤中断。Debian/Ubuntu 系通常要单独装 docker-compose-plugin 或 docker-compose-v2 包。
3.3 首次验证:容器列表、健康检查与 UI
安装过程正常,等一两分钟后用 compose 看状态:
cd /opt/harbor-install/harbor docker compose ps # 期望看到 harbor-core、harbor-db、harbor-registry、harbor-portal 都是 running # 用 docker ps 过滤,确认没有 CrashLoopBackOff docker ps -a --format '{{.Names}}\t{{.Status}}' | grep -E 'harbor|trivy|notary'我没有加 --with-chartmuseum 这类旧组件开关。Harbor 从 2.8 左右的版本开始默认不装 chartmuseum,新版本里 Chart 仓库能力已经调整,所以在 v2.13.1 上不要硬找这个开关,除非你明确需要旧版兼容。UI 验证直接浏览器访问 http:// ,账号 admin 加 harbor.yml 里设置的密码。命令行验证更靠谱:
curl -u admin:'你的密码' http://192.168.209.133/api/v2.0/projects # 返回 JSON 数组即说明核心 API 正常如果这里通但页面打不开,先看 harbor-portal 容器日志,往往是前端静态文件权限或者代理配置问题,和核心服务无关。到这里,一个 ARM64 的 Harbor 已经能用了,但上线前把下一章的四个坑过一遍,能少走不少弯路。
4. ARM64 离线环境避坑:4 个高频问题的现象、原因和解决
4.1 坑 1:qemu 模拟 ARM64 导致容器反复重启
现象:在 x86 开发机上用 qemu 模拟 ARM64 跑安装脚本,install.sh 执行完,docker compose ps 显示 harbor-db 一会儿 Up 一会儿 Restarting,日志里出现数据库初始化失败。偶尔还会看到容器以类似 “bad linux arm64 image magic!” 的格式错误退出,其实是宿主内核在尝试以自身架构解析镜像二进制。
原因:qemu user-mode 的“模拟”只覆盖用户态系统调用,Harbor 中 harbor-db 依赖的 PostgreSQL 对并发和信号处理比较敏感;而镜像格式检查发生在内核 exec 路径,qemu 配合 binfmt_misc 时,某些轻量环境没有注册 aarch64 解释器,于是内核拿 x86 的逻辑去读 ARM64 的 ELF,直接报错。这不是 Harbor 的问题,是运行环境没真正具备执行 ARM64 二进制的能力。
解决:不要在 x86 机器上交付 ARM64 部署。真的要测试,用支持硬件虚拟化的 ARM64 云主机,或者带 aarch64 的工控机。如果已经在模拟环境踩进去了,先把 binfmt_misc 注册好,比如 Debian 系上执行update-binfmts --enable qemu-aarch64,能救回来一部分场景,但也只是“能 run”,不代表生产可用。结论明确:ARM64 离线包必须跑在真 ARM64 主机上,否则你后续排查的所有问题都可能被模拟器噪声干扰。
4.2 坑 2:docker push 报 dial tcp 192.168.x.x 连接被拒
现象:在客户端机器上执行 docker push,报错形如:
get "https://192.168.209.133/v2/": dial tcp 192.168.209.133: connect: connection refused注意报错 URL 里 IP 后面的端口或协议不对。原因往往不是 Harbor 挂了,而是三选一:harbor-portal 没监听该地址;harbor.yml 里 hostname 配的是 localhost;客户端和 Harbor 不在同一网段但配置里用了无法路由的 IP。这类错误几乎每天都有同行遇到,单看报错确实像服务没起。
解决:先在 Harbor 服务器本机用 curl 验证:
curl -v http://192.168.209.133/v2/ # 本机通、客户端不通,查防火墙和安全组端口 # 本机也不通,回到 harbor.yml 检查 hostname 和 http.port确认 harbor.yml 中 hostname 是实际可路由的 IP,重新./prepare && sudo ./install.sh让改动生效。然后客户端 push 之前,把仓库地址显式写成 IP:端口,同时确认 docker 配置的 insecure-registries 覆盖了该地址,HTTP/HTTPS 协议才不会打架。
4.3 坑 3:HTTP registry 被 Docker 客户端拒绝(insecure-registries)
现象:Harbor 走 HTTP(未配置证书),客户端 docker login 提示:
Error response from daemon: Get "http://192.168.209.133/v2/": http: server gave HTTP response to HTTPS client原因:Docker 客户端默认只信任 HTTPS registry,HTTP 需要在 daemon.json 里显式声明为 insecure registry。这是自建 Harbor 最常踩的一道门槛,和服务端无关。很多新手看到报错里的 http 字样,以为是 Harbor 配置问题,其实问题在客户端 Docker 守护进程。
解决:在每台要 push/pull 的客户端机器上改 /etc/docker/daemon.json:
{ "insecure-registries": ["192.168.209.133", "192.168.209.133:80"] }改完先sudo systemctl reload docker,再 docker login。如果还报错,就重启 docker:sudo systemctl restart docker。注意 reload 对 daemon 配置不一定完全生效,重启更稳,但会造成节点上正在运行的容器短暂中断,生产环境挑窗口操作。这里有一个经验:insecure-registries 的列表是“地址+端口”的精确组合,只写 IP 不写端口,而你 push 时又写了端口,系统会认为这是另一台机器,重新走 HTTPS 验证,照样失败。所有节点上的地址、端口、协议要保持一致。
4.4 坑 4:从旧版跨版本升级,数据库迁移失败
现象:旧版本 Harbor(比如 2.9)直接用 v2.13.1 的 install.sh 覆盖,启动后 harbor-core 或 harbor-db 报迁移失败,日志里出现找不到表或列。原因:Harbor 数据库迁移是逐个版本累积的,跨两个以上大版本时,install.sh 不一定帮你补中间步骤,prepare 生成的数据库初始化脚本只针对当前版本。
解决:不要在 ARM64 离线环境里强行“跳级”。升级前备份整个 data_volume,尤其是 /database 子目录,然后按官方路径逐版本升级。比如 2.9 → 2.10 → 2.11 → 2.12 → 2.13.1,每个版本下载对应离线包、改好 harbor.yml 的路径保持不变、跑 prepare 和 install.sh。如果你拿的是 ARM64 包,确认每个中间版本都有 arm64 产物,没有的话说明该版本不支持 ARM64,不要硬用 x86 包加 qemu 凑合。这条没有捷径,数据库迁移不是玄学,是建表语句的依赖链。
5. 把离线部署变成可持续操作:升级路径与三层验证
到这里,Harbor v2.13.1 的 ARM64 离线安装已经不是一次性动作。我建议把“装完”当起点,把升级和验证固化成脚本,因为它直接决定这个离线包投入值不值。
升级路径方面,常见做法是:备份 data_volume → 停旧服务 → 解压新版本 ARM64 离线包 → 沿用旧的 data_volume 路径和数据库密码 → 执行 prepare → 执行 install.sh,组件开关保持和升级前一致。升级后健康检查要单独做,尤其是数据库迁移。我给一个三层验证脚本的最小示例:
#!/bin/bash # 验证脚本:check_harbor.sh HOST="192.168.209.133" ADMIN="admin" PASS="你的密码" # 第一层:容器都起来,且没有 CrashLoopBackOff docker ps -a --format '{{.Names}}\t{{.Status}}' | grep harbor | grep -v Up # 第二层:核心 API 返回 200 curl -s -o /dev/null -w '%{http_code}' -u "$ADMIN:$PASS" \ "http://$HOST/api/v2.0/health" # 第三层:实际推拉一个测试镜像(离线环境用 busybox arm64 镜像) docker push $HOST/library/test:arm64 && docker pull $HOST/library/test:arm64第三层最接近真实用户体验,最容易暴露配置不一致问题,比单纯看 docker compose ps 更可靠。我习惯在一次升级后完整跑一遍三层,前面两层挂掉立即停止后续操作,因为数据库迁移失败后再推镜像,故障现场会被污染。
还有一个验证升级后配置的技巧:升级前把旧的 docker-compose.yml 复制一份,升级后 diff 一下,看数据卷映射和网络是否有非预期变化,这是容器化部署里少有的便宜可靠的后悔药。凡是容器、存储、网络卷标有漂移,优先怀疑 compose 项目名和 network 名冲突,而不要先怀疑 Harbor 程序本身。
硬件层面,保留一条快速回滚动作:备份 data_volume 后压缩到独立文件系统,万一升级失败,解压回去再把旧版本离线包 install 一遍。在 ARM64 机器上做这件事比在 x86 上更慢,因为 Postgres 数据文件的 io 压力会直接拖慢恢复。所以我的习惯是:能一次升级到位,就不反复切版本,否则等待时间都会让你怀疑人生。
是否值得投入这个方向,我的判断是:离线、ARM64、私有化交付这三个词叠加时,Harbor 的官方 ARM64 离线包几乎是目前把方案落地成本压到最低的路径。它比在线安装少一个外网依赖,比自编译省掉一整个工具链,比跨架构模拟稳定得多。只要把 hostname、端口、insecure-registries 和版本升级路径这四个点管住,这个方案就是能长期运转的。把第一次排障学到的经验写进脚本,比记住“重启大法”更有用,希望帮到你。
本文还有配套的精品资源,点击获取