简介面向ARM64架构服务器的Harbor v2.13.1离线安装包专为在鲲鹏、飞腾等国产化平台及树莓派环境中部署Docker镜像仓库的运维、开发人员准备。由于官方安装包长期以x86架构为主要分发对象该资源精准补齐ARM设备无法直接使用离线包的短板适用于Kubernetes集群镜像流转、多云场景下Harbor的快速搭建。压缩包共6个文件包含负责安装与公共配置的2个shell脚本、承载镜像数据的gz核心包、以及配置模板、许可证和prepare预处理文件整体679.05MB覆盖从环境检查到服务启动的关键环节。目前已有526人学习下载使用者可摆脱联网拉取镜像和手工编译的麻烦借助内置模板修改主机名、存储目录等参数后即可完成标准部署。资源还附带用于定制HTTP/HTTPS访问、TLS证书和端口参数的tmpl模板及prepare脚本既适合快速验证也可作为中高级运维人员制定ARM生产环境镜像管理方案的参考基线。1. 为什么生产环境都在找Harbor v2.13.1的ARM64离线安装包它不是简单的架构替换在ARM64服务器上装Harbor第一道坎不是配置而是找对安装包。Harbor v2.13.1是目前最新的2.x维护版本但官方release里的离线安装包默认按amd64编译直接拿到鲲鹏、飞腾这类ARM64机器上docker load能成功一启动就报exec format error。真正的ARM64版离线安装包不是换个文件名那么简单它涉及镜像清单、prepare工具和compose编排三处架构一致性。我会把制作、校验、部署和排雷的完整路径讲清楚适合正在维护国产化基础设施的运维和容器平台工程师。2. 为什么ARM64离线包不能直接用官方包镜像清单与prepare工具的架构陷阱2.1 官方离线包tgz里到底装了什么install.sh怎么工作Harbor v2.13.1的官方离线安装包文件名是harbor-offline-installer-v2.13.1.tgz解压后是一个harbor目录。里面结构向来稳定tar -zxf harbor-offline-installer-v2.13.1.tgz cd harbor ls -la # common.sh install.sh harbor.yml.tmpl prepare images/harbor.v2.13.1.tar.gzinstall.sh是总入口common.sh放着安装时的公共变量和函数prepare是编译器产物用来把harbor.yml转换成docker-compose.yml最后是images目录下的harbor.v2.13.1.tar.gz这是所有服务镜像的打包文件。install.sh的执行顺序大致是加载common.sh、检查docker和docker compose、调用prepare生成配置文件、再用docker load导入镜像包最后docker compose up -d启动全部容器。这里有个易忽略的环节install.sh生成的docker-compose.yml不是现成的而是prepare根据harbor.yml和自定义存储路径动态渲染出来的。prepare本身需要解析yaml、合并默认值、生成nginx配置和若干子配置文件因此它对目标主机的架构非常敏感。如果你只替换了images/下的镜像tar没动prepare在ARM64机器上执行./install.sh会直接在prepare那一步报Exec format error连镜像都不会加载。很多拿到所谓“ARM64安装包”的用户在这里翻车回头还以为是镜像打包过程中漏了文件。common.sh里定义了Harbor安装时的各种路径和参数但它的重点不是架构而是把prepare和docker compose的调用串联起来。有人以为把common.sh里的uname判断改了就算支持ARM64这不够。prepare二进制来自Go编译Go本身是跨架构的但官方在release流程里只产出了amd64的Linux编译产物所以必须单独提供arm64版prepare。这也是自制离线包和官方包唯一的本质差异。2.2 exec format error背后是什么docker镜像架构和运行时校验docker镜像本身是一堆层每层是文件系统快照但最上面的config对象记录了这个镜像运行时需要的内核和指令集架构。当你docker pull时默认拉取当前主机架构对应的变体除非显式指定--platform。假如你把一份amd64的镜像tar在arm64机器上docker load进去docker不会拦你因为load出来的镜像tag可能是一样的。直到你docker compose up容器运行时去执行第一个进程CPU发现指令集对不上内核直接抛exec format error容器秒退。docker image inspect --format {{.Architecture}} goharbor/harbor-core:v2.13.1 # amd64 或 arm64取决于你之前pull的是哪个变体这个Architecture字段是构建镜像时写入的有时是arm64有时是aarch64脚本里判断时要同时接受两种写法。更深一层的问题在于同一个镜像tag在registry里往往同时存在多个架构的manifest但docker save导出的只是本地缓存中的那个具体架构。这是很多自制离线包翻车的根源——开发者在一台x86_64机器上docker pull没有加--platform拉下来的全是amd64然后docker save打包拿到ARM64机器上自然起不来。人眼看镜像tag完全一致但实际架构完全不同。所以在制作离线包时拉镜像和导出镜像必须严格控制在同一架构下。2.3 哪些镜像需要重新按ARM64拉取goharbor核心、postgres、nginx、redis与trivyHarbor v2.13.1的服务镜像数量在12到15张左右具体取决于是否启用trivy和chartmuseum。一个最小集至少包括这些goharbor/前缀的镜像goharbor/harbor-core:v2.13.1goharbor/harbor-jobservice:v2.13.1goharbor/harbor-registryctl:v2.13.1goharbor/harbor-registry:v2.13.1goharbor/harbor-portal:v2.13.1goharbor/harbor-log:v2.13.1goharbor/harbor-db:v2.13.1goharbor/nginx-photon:v2.13.1goharbor/redis-photon:v2.13.1以上镜像在Docker Hub和Quay上都有官方arm64构建。harbor-db实际是postgresql的定制版arm64支持很成熟nginx-photon是Nginx加基础调试工具arm64也没问题。真正需要警惕的是基础组件里不带goharbor前缀的那几张比如redis和postgresql原版镜像有些历史版本只有amd64或者多架构发布不全。Harbor v2.13.1官方默认捆绑的是photon-based的定制镜像通常已经发布arm64但如果你在制作时手滑用了社区版本的redis镜像就可能在harbor-log或jobservice启动时碰到exec format error。同样trivy-adapter镜像本身支持arm64但它启动后要去联网下漏洞数据库离线环境要额外处理。如果要快速判断一个镜像是否支持arm64用docker manifest inspect看它的platform列表即可docker manifest inspect goharbor/harbor-core:v2.13.1 | grep -A6 arm64如果输出里没有arm64这张镜像就不能用于ARM64离线包。这个检查在开始制作前就要完成而不是等打包后才发现缺镜像。3. 在QEMU模拟环境下制作Harbor v2.13.1 ARM64离线安装包3.1 用qemu-user-static挂上ARM64执行环境避免先买一台实机制作ARM64离线包最稳妥的办法是直接在一台ARM64机器上在线安装一遍再打包但很多团队手头没有飞腾、鲲鹏机器。我一般会在x86_64开发机上用qemu用户态模拟让docker能够拉取正确架构的镜像同时验证prepare等二进制能不能在模拟环境中跑通。第一步安装和启用sudo apt install -y qemu-user-static binfmt-support docker run --rm --privileged multiarch/qemu-user-static --reset -p yes第一条命令给系统装上qemu对ARM64用户态的支持和binfmt的注册工具。第二条命令通过特权容器把binfmt的解析规则写进内核系统重启后会失效需要重新运行。注册完成后可以验证docker run --rm --platform linux/arm64 alpine uname -m # aarch64如果这里输出的不是aarch64说明binfmt没生效后续在你启动任何arm64容器时都会遇到“exec format error”。要注意的是qemu模拟的是用户态指令集不模拟硬件加速所以在模拟环境里完整跑Harbor所有容器会慢但用来做镜像拉取和prepare替换是够用的。在Ubuntu/Debian上包名叫qemu-user-static在CentOS 7上EPEL源里也有但版本较旧有时对ARM64新特性支持不全。更省心的做法是直接从多架构镜像项目里下载独立的qemu-aarch64-static二进制放到/usr/bin/后手动注册binfmt。我用过的麒麟V10同样适用这个思路因为系统自带源里的qemu可能不完整。注册binfmt的命令格式是echo :aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xa3\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64-static: /proc/sys/fs/binfmt_misc/register这段内容看着像黑匣子但它解决的问题是让Linux内核能识别ARM64的ELF文件并交给qemu解释执行。x86_64主机上如果不注册docker pull之后容器内一启动就会Exec format error和ARM64机器上遇到的现象一模一样。3.2 按官方镜像清单拉取linux/arm64镜像并重新打包harbor.v2.13.1.tar.gz准备好arm64执行环境后第二步是按镜像清单拉取。我先建一个image-list.txt把2.3节里列出的镜像tag写进去然后循环拉取cat image-list.txt EOF goharbor/harbor-core:v2.13.1 goharbor/harbor-jobservice:v2.13.1 goharbor/harbor-registryctl:v2.13.1 goharbor/harbor-registry:v2.13.1 goharbor/harbor-portal:v2.13.1 goharbor/harbor-log:v2.13.1 goharbor/harbor-db:v2.13.1 goharbor/nginx-photon:v2.13.1 goharbor/redis-photon:v2.13.1 EOF while read -r img; do docker pull --platform linux/arm64 $img done image-list.txt注意--platform linux/arm64必须要加。因为docker在x86_64主机上默认还是会拉amd64变体即使本机装了qemupull阶段仍然遵循Docker Hub的manifest选择逻辑。只有显式指定platformdocker拉下来的镜像的Architecture字段才是arm64。如果某个镜像只有amd64变体pull时会报“no matching manifest for linux/arm64”这就是早期预警需要换版本或者自行构建。拉完后把本机所有goharbor镜像导出成一个tar文件替换离线包里的harbor.v2.13.1.tar.gzdocker save $(docker images --format {{.Repository}}:{{.Tag}} | grep ^goharbor/ | sort -u) -o harbor.v2.13.1.tar.gz cp harbor.v2.13.1.tar.gz ../harbor/images/harbor.v2.13.1.tar.gz这里有个坑docker save如果镜像在本地存在多个架构变体会把所有架构的层都导出到tar里导致包体积变大而且load到目标机上并不会自动过滤可能又出现架构混用。更好的做法是先把本机不需要的镜像tag清理掉确保只保留arm64变体。实际操作中我会先执行docker image ls确认每一张镜像的架构再save。3.3 用arm64版prepare替换install.sh依赖并修正common.sh里的架构判断镜像tar换好后prepare是下一个必须处理的对象。官方离线包里的prepare在解压目录根下是amd64的ELF。在qemu环境下可以继续从goharbor/prepare镜像中把arm64版提取出来docker pull --platform linux/arm64 goharbor/prepare:v2.13.1 docker create --name prepare-tmp goharbor/prepare:v2.13.1 docker cp prepare-tmp:/harbor/prepare ./prepare docker rm prepare-tmp chmod x ./preparegoharbor/prepare镜像的入口是prepare程序它在镜像里的路径一般是/harbor/prepare。如果你的tag不是v2.13.1或者镜像内部路径有变化可以先进入容器找一下docker run --rm --entrypoint sh goharbor/prepare:v2.13.1 -c which prepare; ls -l /harbor把提取出来的./prepare覆盖到离线包目录下。然后打开common.sh搜索uname -m或uname。有的版本里有针对x86_64的架构判断例如case $(uname -m) in x86_64|amd64) ...如果遇到ARM64机器上被拒绝的情况把对应分支改成同时接受aarch64和arm64。common.sh里的其他变量一般不用改因为prepare生成docker-compose时使用的是相对路径和harbor.yml里的配置。这个替换动作做完后install.sh才能像在x86_64上一样顺畅走完。3.4 校验产物docker manifest inspect与tar包内的镜像一一对应打包完成别急着交付先在制作机上做一轮完整校验。第一步对每一张镜像执行manifest验证while read -r img; do echo $img docker manifest inspect $img | jq -r .manifests[] | .platform.architecture | sort | uniq done image-list.txt检查输出里是否有arm64。如果某张镜像只有amd64这一项就会缺失。第二步解压新生成的harbor.v2.13.1.tar.gz看看manifest.json里记录的RepoTags和归档内的层引用是否齐全tar -xOf harbor.v2.13.1.tar.gz manifest.json | jq .[].RepoTags这个输出应该和image-list.txt里的tag一致。第三步如果条件允许把整个离线包拷贝到一台临时ARM64机器上执行./install.sh --with-trivy --with-chartmuseum然后docker compose ps看所有服务是否正常。这个“真机冒烟测试”比任何静态校验都可靠我每次交付前都至少做一遍。4. 把自制ARM64离线包部署到目标机从harbor.yml到install.sh参数4.1 解压后配置harbor.yml的hostname、端口和存储路径拿到做好的离线包在目标ARM64服务器上先解压tar -zxf harbor-offline-installer-v2.13.1-arm64.tgz cd harbor cp harbor.yml.tmpl harbor.yml vi harbor.ymlharbor.yml是安装的唯一入口。最少要改四个位置。hostname填实际访问域名或IP不能是localhost否则Harbor的页面登录会403。http部分是监听端口默认80如果和系统Nginx或已有Web服务冲突改成8080。如果不用https把https段整个注释掉因为prepare读取到certificate和private_key路径的文件不存在时会直接退出。harbor_admin_password设置初始化管理员密码必须至少8位且带大小写和数字。database的password是给Postgres用的建议也改掉避免弱密码风险。最后是data_volume这个目录存放registry数据、数据库和证书必须单独挂载到大分区。一个常见误区是只改hostname其他都用模板默认值。这样在纯离线环境里确实能装起来但后续要配https再回头看harbor.yml时容易漏改。我习惯把所有涉及安全的口令都明确写上哪怕保持默认也在文件里留下痕迹方便交接。整段配置参考hostname: registry.internal.example.com http: port: 80 https: port: 443 certificate: /data/harbor/cert/server.crt private_key: /data/harbor/cert/server.key harbor_admin_password: N8sTrm64#2025 database: password: D8brm64#2025 max_idle_conns: 50 max_open_conns: 100 data_volume: /data/harbor注意这里的https端口和证书路径要真实存在否则install.sh的prepare阶段会报证书文件缺失。如果只是测试建议先把https段整个注释掉用http跑通再说。4.2 install.sh常用参数--with-trivy、--with-chartmuseum以及证书模式下必开的选项执行安装sudo ./install.sh --with-trivy --with-chartmuseuminstall.sh支持的常见参数如下表。注意参数只在首次安装时有效后续配置变更都要重新执行prepare再compose up。参数作用适用场景--with-trivy启用Trivy漏洞扫描需要安全漏洞报告--with-chartmuseum启用ChartMuseum Helm仓库需要管理Helm Chart--with-notary启用Notary镜像签名需要内容信任一般是金融政企强制要求--with-clair启用Clair漏洞扫描老版本遗留新项目建议用Trivy-d以debug模式运行输出脚本每一步日志排障时使用如果你在离线包制作时没有启用某组件那install.sh就不要带对应参数。比如image-list.txt里没拉trivy-adapter执行--with-trivy时Harbor会因找不到镜像而报错。在纯离线环境--with-trivy还会带来一个额外的坑trivy启动后需要下载漏洞数据库因此你需要在离线包中额外准备goharbor/trivy-db或者调整trivy的离线扫描配置。这部分没有绝对通用做法我通常是先不加trivy部署等后面有外网条件再补。同样--with-chartmuseum只在你想要一个Helm Chart仓库时才需要不是默认功能。4.3 部署后健康检查docker compose ps、curl /api/v2.0/pinginstall.sh结束后先看服务状态docker compose ps所有服务应该处于Upharbor-db和redis的health列是(healthy)。如果某个服务显示Restarting马上看日志docker logs --tail 50 harbor-core docker logs --tail 50 harbor-db再调用API做基本验证curl -k -u admin:YourPassword https://127.0.0.1/api/v2.0/ping返回PONG表示core服务正常。最后创建项目docker login到Harborpush一个测试镜像再pull回来形成闭环。注意docker客户端如果报x509证书错误需要把Harbor的ca.crt添加到/etc/docker/certs.d/harbor域名/目录下或者在daemon.json配置insecure-registries。在国产化操作系统上这个证书信任动作经常被忽略导致能登录但推送失败日志提示“http: server gave HTTP response to HTTPS client”实际上是因为harbor.yml里配置了https而客户端走http需要检查harbor.yml中的http和https配置还要检查容器内的nginx端口映射。5. 避坑与排查ARM64离线包部署最容易踩的5个坑5.1 docker load成功但容器崩溃日志说exec format error现象docker compose up后harbor-core容器秒退docker logs显示standard_init_linux.go:228: exec user process caused: exec format error。原因镜像tar里的架构仍然是amd64docker load时没有做任何拦截它只是把层解开并不检查是否能在本机运行。解决检查制作流程里是否真的指定了--platform linux/arm64用docker image inspect逐一核对。如果只有少数服务报错可以单独拉取arm64变体再替换tar不需要全部重来。这个坑在所有跨架构离线包里排第一因为很多人从网上下载一个“ARM64离线包”其实源头机器是x86_64docker save导出的镜像仍然是amd64。5.2 prepare执行时Exec format error导致install.sh进行到一半就停现象执行./install.sh屏幕显示prepare: Exec format error但前面的脚本检查都正常。原因官方离线包内置的prepare是x86_64二进制ARM64内核无法执行。解决使用3.3节的方法从goharbor/prepare镜像里提取arm64版本并替换。可以在制作离线包前先把这一步做掉也可以在目标机上临时用docker run方式单独执行prepare再接手工docker compose up后者适合着急上线的场景。如果不想动包里二进制也可以改install.sh把./prepare那行替换成docker run --rm -v $PWD:/harbor goharbor/prepare:v2.13.1 prepare但这样依赖网络离线环境不推荐。5.3 harbor-db起来了但harbor-core连不上数据库日志反复报password authentication failed现象harbor-core容器日志出现connection refused或password authentication failed但harbor-db容器状态是healthy。原因harbor.yml中的database.password与数据库初始化时使用的密码不一致或者数据库镜像初始化时已经用了旧密码数据卷是旧的。解决如果数据卷里的postgresql数据已经存在初始化脚本不会重复执行改密码也不会生效。要么删除data_volume下的database子目录重新初始化要么在harbor.yml中保持原密码。这是Harbor一个老问题和ARM64无关但在离线包上更容易踩因为很多人是从amd64机器复制数据卷过来的。删除数据卷的代价是丢失全部镜像数据操作前务必备份data_volume。5.4 Trivy扫描报无法初始化漏洞数据库不是架构问题现象镜像能push但点击漏洞扫描后任务失败日志提示failed to download the vulnerability database。原因trivy-adapter启动后会去GitHub或官方镜像源下载trivy-db离线环境没有外网或者防火墙只允许走代理。解决在在线环境提前docker pull aquasec/trivy-db再手动导入到Harbor所在节点的docker镜像缓存并修改harbor.yml中trivy相关的offline_scan为true。也可以更彻底地把trivy-db镜像传给用户在离线包中额外附带。要注意trivy-db也有arm64变体别又拉成amd64。这个坑跟ARM64没有强关联但很多人在前几步折腾完架构问题后会异想天开地怀疑是ARM64导致的实际上trivy镜像本身是有arm64的。5.5 install.sh提示docker compose版本不满足但docker-compose命令能执行现象脚本检查到docker compose不存在或版本低于2.0但docker-compose带横线能正常工作。原因Harbor install.sh判断的是docker compose v2插件不是旧版python实现的docker-compose。现在的发行版默认装的是docker-compose v1或者只有v2插件但没链接到PATH。解决安装插件版sudo apt install docker-compose-plugin或从docker官方二进制包拷贝到/usr/local/lib/docker/cli-plugins/docker-compose并加执行权限。ARM64的国产化系统有些源里没有这个包需要从docker官方下载arm64编译好的二进制注意别下成amd64的。验证命令是docker compose version而不是docker-compose version。这个坑和架构无关但如果你用官方离线包在ARM64上栽在这一步会特别泄气因为前面明明是架构问题到这里又变成了工具链问题。6. 进阶用docker manifest自动校验镜像架构并固化自制离线包的脚本上面几条坑如果能挨着趟过去离线包基本能用了。我再分享一个自己常用的校验脚本它在每次打包前后跑一遍目的只有一个确保images/目录下的tar里每个镜像的架构都是arm64。#!/usr/bin/env bash set -euo pipefail image_list$(docker images --format {{.Repository}}:{{.Tag}} | grep ^goharbor/ | sort) for img in $image_list; do arch$(docker image inspect --format {{.Architecture}} $img) if [ $arch ! arm64 ]; then echo [FAIL] $img is $arch, not arm64 exit 1 fi done echo all matched arm64这段脚本的逻辑很直白docker image inspect输出的Architecture就是镜像配置里的原始架构arm64或者aarch64都可能出现视构建工具而定。如果脚本发现任何一个镜像不是arm64就立刻退出。实际使用中我会把它放在一个build-offline.sh里让它紧接着docker pull和docker save之后执行。注意这里的镜像范围限定在goharbor/下如果你在离线包里额外加了redis等非goharbor镜像要把正则再扩大。如果想要更强的校验可以进一步比对docker-compose.yml里用到的镜像tag是否都出现在tar中。做法是compose_refs$(grep -E image: docker-compose.yml | awk {print $2} | sort -u) tar_refs$(tar -xOf harbor.v2.13.1.tar.gz manifest.json | jq -r .[].RepoTags[] | sort -u) comm -23 (echo $compose_refs) (echo $tar_refs)如果输出有内容说明compose里引用了tar里没有的镜像tag启动时必然报image not found。这个步骤在手工制作时容易漏掉因为在拉镜像时少拉一个很简单而docker compose up只会在用到时才发现。我自己的习惯是离线包在进生产前一定在隔离环境里完整跑一遍install.sh加push/pull验证再封装成交付物。虽然多花十分钟但它能把这些架构陷阱、依赖缺失的后悔药提前吃完。记住一条ARM64离线包的难点不在“包”而在包里的镜像、prepare和compose配置三者是不是同一架构。希望这套制作和排查路径能帮你在国产化服务器上把Harbor顺利跑起来少踩几个坑。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?