简介:针对国产化ARM架构(aarch64)环境中容器镜像仓库的离线部署需求,这份资源提供了Harbor v2.10.2的完整软件包。包内共6个文件,主要包括两个Shell脚本(install.sh与common.sh,负责安装流程与公共函数)、Harbor镜像离线压缩包(harbor.v2.10.2.tar.gz,承载镜像内容的主体压缩包)、LICENSE许可文件、prepare初始化组件以及harbor.yml.tmpl配置模板,整体约650.11MB,结构清晰,为内网和信创环境而设计。目前已有98人学习下载,适合运维工程师、DevOps人员以及负责国产化迁移的技术团队使用。利用该离线包,用户只需按模板调整配置并执行安装脚本,即可完成Harbor的部署与基础配置,无需在线拉取镜像,有效规避网络隔离或不稳定因素;同时可在此基础上开启Harbor的RBAC权限、镜像复制、存储管理等能力,形成企业内部可复用的生产级镜像仓库基线。对于需要快速交付、稳定运行的ARM服务器环境,这份资源能显著降低部署门槛,缩短落地周期。
1. 拿到harbor-offline-installer-aarch64-v2.10.2.tgz,先弄清楚它解决什么问题
一个 2GB 出头的离线安装包,文件名里把架构写死在aarch64上,这基本就说明了它的使用场景:一台没有外网、或者外网极不稳定的 ARM64 服务器(鲲鹏、飞腾、或者 Apple Silicon 上的 Linux 虚拟机),需要在内网搭一套 Harbor 镜像仓库。如果你正被docker pull超时、yum 源连不上、内网机器上连个基础镜像都得靠 U 盘拷贝这些问题折磨,这个包就是用来绕开所有网络依赖的——它把 Harbor 的容器镜像、安装脚本、配置模板全部打在一个 tgz 里,拷进去就能装。
我见过不少团队第一次用这个包时,以为它和在线安装器一样,解压后跑install.sh就万事大吉。结果卡在docker load的镜像导入时间上,或者因为没提前装好 docker-compose 而翻车。这篇文章从选型逻辑讲起,逐步拆解从解压到配置再到排错的全部过程,重点放在 aarch64 平台上那些和 x86 不一样的坑。
适合谁看?两类人。一类是要在 ARM64 内网环境交付的运维和平台工程师,另一类是打算把 Harbor 作为团队镜像仓库、但不想在依赖管理上浪费时间的后端开发者。看完你至少能回答三个问题:这个离线包和在线安装器到底差在哪、在 aarch64 上安装有哪些必须留意的参数、以及推送和拉取失败时日志里的关键信息长什么样。
2. 为什么选离线包 + aarch64 专用包:架构差异比你想的更影响落地
2.1 离线安装器与在线安装器的本质区别
Harbor 官方提供的安装器分两种:在线版是一个很小的脚本,执行时会动态从 Docker Hub 拉取 Harbor 自身的组件镜像;离线版则把goharbor/下的所有镜像(portal、core、jobservice、registry、redis、postgresql、nginx 等)预先导出成 tar 包,和安装脚本一起封装。harbor-offline-installer-aarch64-v2.10.2.tgz里的.tgz后缀,意味着你需要先解压,再执行内部脚本。
选择离线包的核心原因只有一个:环境隔离。内网机器通常连不上 Docker Hub,甚至连接外网的链路本身就受限。在线安装器在docker pull这一步就会卡死,而离线包把网络依赖压缩到了安装前的文件拷贝阶段。代价是包体巨大,且必须和你的 CPU 架构严格匹配——x86 的离线包在 ARM64 机器上无法直接运行,反之亦然。
这里要特别注意一个常被忽略的点:离线包内的镜像在docker load之后,会被打上goharbor/...的标签,但安装脚本会再用docker tag把镜像重新标记为本地仓库地址。如果你之前手动docker load过某个组件镜像并打了自定义 tag,脚本执行时可能因为 tag 冲突报错。所以规范的流程是:让脚本自己管理镜像的导入和标记,不要提前干预。
2.2 aarch64 与 x86 在 Harbor 部署上的差异点
aarch64对应 ARM 64 位指令集,常见于鲲鹏 920、飞腾 FT-2000 这些国产芯片,以及 AWS Graviton、Ampere Altra 这类云实例。Harbor 的组件镜像对 ARM 的支持差距很大:redis、postgresql、nginx这些基础镜像官方一直有 multi-arch 构建,但 Harbor 自身的一些组件(比如harbor-core、harbor-jobservice)在某些版本上只有 amd64 的官方镜像。这也是为什么你会看到-aarch64-这个后缀——它表明这套镜像已经被重新构建过,能跑在 ARM 平台上。
安装时的直观差异体现在三个方面。第一,docker load的时间明显比 x86 长,因为 ARM 镜像层通常更多,我在鲲鹏机器上导入 2GB 离线包大约需要 8-15 分钟,取决于磁盘是 HDD 还是 SSD。第二,Harbor 依赖的docker-compose在 ARM 上的安装方式不同,Ubuntu 的 apt 源里那个docker-compose版本可能太老,需要单独处理。第三,日志里的错误信息往往带有架构相关特征,比如exec format error,这不是 Harbor 的问题,而是镜像架构不匹配导致的。
如果你打算把 x86 的离线包直接拷到 ARM 机器上,省掉重新下载的功夫,实践下来这条路走不通。docker load不会报错,但容器一启动就exec format error,最后还得老老实实找 aarch64 专用包。这个教训我们当时花了一个下午才定位到。
2.3 部署前的基础环境检查清单
在解压离线包之前,有一组环境检查值得做,能把后面一半的排错时间省掉。至少需要确认:Linux 内核版本不低于 3.10(这是 Docker 的硬性要求);docker和docker-compose已安装;磁盘剩余空间大于离线包体积的两倍(镜像导入会临时占用额外空间);80 或 443 端口没有被占用。
# 确认架构,必须是 aarch64 或 arm64 uname -m # 确认 Docker 版本,Harbor 官方对 20.10 以下版本兼容性不好 docker version --format '{{.Server.Version}}' # 确认 docker-compose 独立版本 docker-compose --version # 检查磁盘剩余空间,建议至少 20GB df -h /data逻辑说明:第一行uname -m是判断架构的起点,如果输出是x86_64,说明你拿错包了。第二行和第三行检查 Docker 与 Compose 的存在性,缺一个都不行——Harbor 的install.sh不会主动帮你装 Docker。第四行看数据盘剩余,Harbor 的镜像存储目录默认为/data,这个路径如果没空间,安装到后面docker load就不会报错,但推镜像时会突然失败。
参数拓展:/data是 Harbor 默认的数据卷目录,可以通过 harbor.yml 里的data_volume改成任意路径,比如/opt/harbor-data。但改路径要趁早,一旦install.sh执行过,目录结构已经生成,再改配置需要先执行docker-compose down再重新 prepare。
提示:如果你的机器内存小于 4GB,Harbor 安装后启动会非常吃力,尤其是同时跑起 postgresql 和 registry 两个容器。建议至少 8GB 内存,否则
docker ps能看到容器一直在 restarting。
3. 从解压到装完:完整安装步骤与核心参数解析
3.1 解压离线包并检查目录结构
拿到harbor-offline-installer-aarch64-v2.10.2.tgz后,第一步不是急着解压,而是先校验文件的完整性。tgz 在 U 盘和网盘之间来回拷贝,损坏的概率不低,而镜像包一旦有字节损坏,docker load会在某个镜像层上报archive/tar: invalid tar header,这个错基本等于白跑一趟。
# 计算 SHA256 校验值,和下载页提供的值对比 sha256sum harbor-offline-installer-aarch64-v2.10.2.tgz # 解压到 /opt 目录 tar -zxvf harbor-offline-installer-aarch64-v2.10.2.tgz -C /opt # 进入解压后的目录 cd /opt/harbor # 查看目录结构 ls -lh解压后你会看到install.sh、harbor.yml.tmpl、prepare、common.sh这几个关键文件,以及一个harbor.v2.10.2.tar.gz镜像包。这个内部 tar 包就是刚才说的所有组件镜像的合集,后续install.sh会调用docker load导入它。
参数说明:-C /opt指定解压目标目录,如果/opt/harbor已经存在,需要先删掉旧目录再解压,否则会混杂旧版本文件。common.sh被安装脚本引用,里面定义了日志级别、镜像仓库地址等公共变量,建议不要手动修改。
3.2 配置 harbor.yml:决定安装成败的必改项
进入目录后,第一步操作是把配置模板复制成真正的配置文件:cp harbor.yml.tmpl harbor.yml。Harbor 的安装机制是:prepare脚本读取harbor.yml,生成 docker-compose 所需的 env 文件和证书,然后install.sh才真正拉起容器。所以配置文件的错误,会在prepare阶段就暴露。
# harbor.yml 关键配置节选 hostname: 192.168.1.100 # 必改:本机 IP 或域名,不能留 localhost http: port: 80 # HTTP 端口,和已有服务冲突时改 8080 https: port: 443 certificate: /data/cert/harbor.crt # 自签名证书路径 private_key: /data/cert/harbor.key harbor_admin_password: Harbor12345 # 必改:管理员初始密码 data_volume: /data/harbor # 镜像和数据存储位置 log: level: info rotate_count: 20 rotate_size: 100M database: password: root123 # postgres 密码,修改后需和 core 配置一致这里最容易犯的错是把hostname写成localhost或者不写。Harbor 会把hostname拼进镜像仓库地址,比如192.168.1.100/library/nginx。如果写了localhost,你在另一台机器上 push 时会得到一个192.168.1.100无法访问的怪异地址。
参数说明:http.port和https.port是两套独立监听端口,你可以只启用 HTTP、只启用 HTTPS、或者两者都启用。生产环境建议只开 HTTPS,但内网环境很多机器没有证书信任,HTTP 反而更方便——注意把http段打开,https段注释掉即可。log.rotate_count和rotate_size控制日志轮转策略,默认值够用,但高频推拉环境下建议把rotate_size调大到 200M。
提示:
harbor_admin_password如果保持默认为Harbor12345,安装脚本不会强制你改,但所有知道 Harbor 默认密码的人都能进管理后台。内网环境也不能省这一步,至少换成一个 12 位以上的随机串。
3.3 执行安装:prepare 阶段、加载镜像、启动容器
配置改完后,从./install.sh开始,后面的事情就交给脚本了。但脚本的执行过程值得拆开看,因为它分成三个阶段,每个阶段失败的错误都不一样。
# 执行安装脚本 sudo ./install.sh脚本内部会依次做三件事:调用prepare生成配置文件与证书、执行docker load导入镜像包、最后docker-compose up -d启动所有服务。整个流程耗时和机器性能强相关,我在 16 核鲲鹏 + SSD 的机器上跑完约 12 分钟,在 4 核虚拟机上则要半小时以上。
安装完成后,docker-compose ps会看到 9 个容器在运行状态。如果某个容器反复重启,比如harbor-core起来又退出,最可能的原因有两类:一是harbor.yml里数据库密码改了一半,core 连不上 postgres;二是磁盘权限不对,postgres 容器无法写数据目录。
# 查看容器运行状态 docker-compose ps # 查看具体容器日志 docker-compose logs -f harbor-core # 查看全部服务的启动日志 docker-compose logs --tail=200逻辑说明:docker-compose ps比docker ps更适合排查,因为它显示的是 Harbor 编排内的服务名,一眼能看出哪个服务状态异常。logs -f harbor-core是定位 core 起不来的首选命令,日志里如果出现dial tcp ...:5432: connect: connection refused,基本就是数据库容器还没就绪,等几秒再看;如果出现password authentication failed,则一定是数据库密码配置不一致。
3.4 验证安装:从 Web 到 docker login 的全链路检查
安装完成先别急着用,按顺序验证三件事:Web 页面是否可访问、docker login 是否成功、push 一个测试镜像是否正常。前两步验证管理面和认证链路,第三步验证存储链路。
# 浏览器或 curl 验证 Web 服务 curl -I http://192.168.1.100/ # 在另一台机器上测试登录 docker login 192.168.1.100 -u admin -p '你的密码' # 打一个测试镜像并推送 docker tag nginx:latest 192.168.1.100/library/nginx-test docker push 192.168.1.100/library/nginx-test参数说明:登录时如果报Error response from daemon: Get "https://192.168.209.133/v2/": http: server gave HTTP response to HTTPS client,说明 docker 默认用 HTTPS 访问你的 Harbor,但你的 Harbor 只开了 HTTP。解决方法是往 docker daemon 配置里加"insecure-registries": ["192.168.1.100"],重启 docker 后重试。
curl -I返回200 OK是 Web 层面的验证,但不代表容器调度正常。推送成功则证明 registry 容器读写磁盘正常,这一步通过了,Harbor 的安装才算真正完成。
4. aarch64 平台上的关键落地配置:存储、证书与镜像同步
4.1 数据目录选型:不要把镜像存进系统盘
Harbor 默认的数据目录是/data,但实际落地上我见过太多人直接把系统盘塞满,导致后面的镜像 GC 都无法执行。Harbor 的镜像存储是docker-registry的 filesystem 驱动,一个镜像的多个层散落在/data/database/registry/docker/registry/v2/repositories下,占用空间是镜像实际大小的 1.5 到 2 倍。
如果你有独立的数据盘,比如挂载在/mnt/harbor-data,建议安装前就把data_volume指过去。这里有个额外好处:后续如果需要备份或迁移,直接对data_volume目录做快照即可,不需要逐个容器导出。
# harbor.yml 中数据目录配置 data_volume: /mnt/harbor-data配置好之后重启服务生效:docker-compose down后重新./install.sh。注意down不会删除数据卷,重启后原有镜像数据还在,这个操作是可逆的。但如果你把data_volume指向一个全新空目录,重启后仓库里的镜像列表会短暂为空——数据其实还在旧目录里,别急着删。
参数说明:data_volume路径的用户属主会影响容器写入权限,建议统一chown -R 10000:10000,这是 Harbor 容器内运行用户 ID(postgres 和 registry 都用 UID 10000 运行)。权限不对时,registry 容器会报permission denied,但写入错误往往延迟到你 push 镜像时才暴露。
4.2 自签名证书生成与分发:免掉 HTTPS 告警
内网环境没有公共 CA,最常用的做法是生成自签名 CA,再用它签发 Harbor 的服务器证书。这样做的好处是:只要把 CA 证书加到客户端的信任库,所有docker login和docker pull都不需要走insecure-registries,更接近生产环境的使用方式。
# 生成 CA 私钥和证书 openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt -subj "/CN=Harbor-CA" # 生成 Harbor 服务器私钥 openssl genrsa -out harbor.key 2048 # 创建证书签名请求 openssl req -new -key harbor.key -out harbor.csr -subj "/CN=192.168.1.100" # 使用 CA 签发服务器证书 echo "subjectAltName=IP:192.168.1.100" > extfile.cnf openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out harbor.crt -days 825 -extfile extfile.cnf逻辑说明:这里的关键是第三步和第四步的CN必须等于 Harbor 的hostname,同时subjectAltName里必须包含 IP 或域名。docker 校验证书时会检查这二者,缺任何一个都会在docker login时报x509: certificate relies on legacy Common Name field或cannot validate certificate。
生成完成后,把harbor.crt和harbor.key放到harbor.yml中指定的路径,然后重新执行./install.sh。客户端的配置需要手工同步:把ca.crt拷贝到每台客户机的/etc/docker/certs.d/192.168.1.100/ca.crt,重启 docker 后即可免告警访问。
参数说明:证书有效期 825 天是 Chrome 和 docker 都接受的上限,超过这个天数现代客户端会直接拒绝。到期前需要重新签发并替换,替换方式和首次生成一样,但要注意先docker-compose down再替换证书,否则 nginx 容器还持有旧证书的内存副本。
4.3 离线环境下的镜像同步:从上游拖镜像的替代方案
离线环境建好 Harbor 之后,下一步就是往里灌镜像。这里有一个天然的鸡生蛋问题:内网机器没有外网,初始镜像从哪来?常见做法是在一台有外网的机器上docker pull,再docker save成 tar,拷进内网后docker load并 push。
# 在有外网的机器上拉取并保存镜像 docker pull nginx:1.25 docker save nginx:1.25 -o nginx-1.25.tar # 拷贝 tar 到内网机器后加载并推送 docker load -i nginx-1.25.tar docker tag nginx:1.25 192.168.1.100/library/nginx:1.25 docker push 192.168.1.100/library/nginx:1.25这个方案手动操作效率太低,镜像一多就烦。更效率的做法是用 Harbor 自带的harbor-registryctl或直接调用其 API 做项目间复制(Replication)。该功能支持从另一个 Harbor、docker registry、甚至阿里云 ACR 同步镜像,并且支持定时触发——在离线环境下,如果有一条虽然慢但可用的网络链路,这个方法比完全靠人工搬运优雅得多。
逻辑说明:复制策略在 Harbor 的 Web 界面里配,核心选项是「源注册表类型」和「源地址」以及需要同步的项目。首次同步会全量拷贝,之后按标签变化做增量。这个功能对 aarch64 环境尤其重要,因为 ARM 镜像的获取渠道比 x86 少,一旦在一个节点上找到了某镜像的 ARM 版本,尽快复制到其他 Harbor 节点,能省大量重复搜索的时间。
4.4 单机 Docker 配置:insecure-registries 的正确写法
很多内网 Harbor 用的是 HTTP 协议,这就必须在 docker daemon 侧声明insecure-registries。这个配置的坑在于:改完要重启 docker 才生效,而重启 docker 会短暂中断所有运行中容器。
// /etc/docker/daemon.json { "insecure-registries": ["192.168.1.100", "my-harbor.internal:8080"] }修改后重启方式建议用systemctl daemon-reload && systemctl restart docker。重启后docker info能看到Insecure Registries列表里出现了你配置的地址,才算真正生效。
这里有一处容易踩的坑:如果你同时配置了registry-mirrors和insecure-registries,部分版本 docker 在拉取镜像时,会先去 mirror 找,找不到才走 insecure registry。由于 mirror 通常在外网,内网环境里每次docker pull都会因为超时白白多等十几秒,严重时直接导致 login 超时。建议离线环境把registry-mirrors整个删掉,只保留insecure-registries。
参数说明:地址可以带端口,比如192.168.1.100:8080;可以写网段,比如192.168.10.0/24,但网段匹配的优先级低于精确匹配。配置了网段后,该网段内所有地址都会被当作 insecure 处理,安全性上要自己权衡。
5. 避坑指南:aarch64 离线安装的 5 个高频故障与排查思路
5.1 镜像导入时报invalid tar header:文件损坏或校验缺失
现象:执行install.sh时,docker load阶段报错,指出harbor.v2.10.2.tar.gz内某一层archive/tar: invalid tar header,安装进程中断。
原因:tgz 在拷贝过程中发生字节损坏,甚至有些是下载工具提前掐断连接导致文件不完整。另一个常见源头是 U 盘格式不兼容,FAT32 不支持大于 4GB 的单文件,而 Harbor 离线包的内部 tar 常常超过这个限制,拷贝时会静默截断。
解决:第一步永远是用sha256sum核对下载时的校验值。如果源站没有提供,就把包重新拷贝一次,用rsync -c比对文件内容。拷贝目标盘要选 ext4 或 xfs,不要用 FAT32。如果文件确实损坏,只能重新下载——不要尝试用tar --ignore-zeros去抢救,Harbor 的镜像包内部结构复杂,跳过坏块后导入的镜像大概率在启动时报错,这种玄学修复不如重下稳定。
5.2exec format error:拿错架构的离线包
现象:容器启动瞬间退出,docker logs显示exec format error,或者docker inspect里镜像的Architecture字段是amd64。
原因:拿 x86 的离线包装到了 ARM64 机器上。docker load不会校验宿主机架构,镜像能导入成功,但运行时内核无法执行 x86 指令,于是容器直接崩溃。
解决:从文件名即可判断,aarch64后缀的包才能在 ARM64 机器上用。如果你同时管理两种架构的机器,建议在下载后就重命名,把架构写进目录名,比如harbor-offline/arm64/和harbor-offline/amd64/。另外在解压后执行docker load之前,可以先tar -xOf内部某个镜像的 manifest 文件看架构,但这操作太麻烦,不如直接看文件名。
5.3dial tcp 192.168.209.133: ... connect: connection refused:端口没监听或防火墙拦截
现象:docker login时报Get "https://192.168.209.133/v2/": dial tcp 192.168.209.133:443: connect: connection refused,但 Harbor Web 页面却可以正常访问。
原因:Web 页面通过浏览器访问走的是你输入的端口,而 docker login 默认走 443。如果 Harbor 只开了 HTTP 80 端口,但你用docker login 192.168.209.133不带端口,docker 会自己加https://前缀并连 443,连接被拒绝。另一种情况是 80 端口被云安全组或 iptables 挡了,curl 从本机访问正常,但跨机器访问不通。
解决:先确认 Harbor 开了哪些端口:netstat -tlnp | grep -E '80|443'。如果只有 80,那就在 docker 的 daemon.json 里加insecure-registries,并且登录时显式写端口:docker login 192.168.209.133:80。如果端口明确放开还连不上,检查 iptables:iptables -L -n | grep 80,必要时临时放行测试:iptables -I INPUT -p tcp --dport 80 -j ACCEPT。
5.4 磁盘空间不足,推镜像时报no space left on device
现象:docker push到一半失败,registry 容器日志里有no space left on device,检查df -h却发现data_volume所在分区还有几十个 G。
原因:Harbor 的 registry 容器默认使用docker volume或本地目录存储,如果你配置的是data_volume: /data,但/data和/不在同一分区,df -h /data的空间可能不够。更隐蔽的是,如果 docker 的storage-driver是overlay2,docker load导入的镜像层会占用/var/lib/docker所在分区,而这个分区往往和/data不是同一个。
解决:检查两个分区的剩余空间:df -h /data和df -h /var/lib/docker。如果/var/lib/docker紧张,可以迁移 docker 根目录到数据盘(修改 daemon.json 里的>{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }
max-size: 100m让单个容器日志文件超过 100MB 就轮转,max-file: 3保留最近 3 份。这两个参数只对重启后新建的容器生效,所以要systemctl restart docker,再docker-compose down && docker-compose up -d让 Harbor 全部容器应用新配置。
镜像 GC 更值得养成习惯。Harbor 的 Web 界面删除镜像时,实际删除的只是元数据,磁盘上的分层数据还在。只有执行 garbage collection 后才会物理删除。使用方式是进入 Harbor 的 registry 容器内部执行:
docker-compose exec registry registry garbage-collect /etc/registry/config.yml执行时建议先停掉写入:docker-compose stop registry再执行,否则 GC 过程中新 push 的镜像可能被当作未被引用的层误删。GC 完成后docker-compose start registry。
另一个习惯是定期做数据目录快照备份。data_volume目录包含所有镜像数据和数据库文件,直接用tar或rsync备份都比逐容器导出快。我一般用rsync -avz --delete同步到异地,每周一次,配合前端配置的复制策略,基本能保证 Harbor 节点挂了以后半天内重建。
如果你正在规划内网镜像仓库,aarch64 离线包这条路是走得通的,前提是提前想清楚三件事:数据目录放在哪、docker 的 insecure-registries 怎么配、以及日志和 GC 的兜底策略。把这三个问题在安装前定好,后面能少踩很多坑。希望这篇能帮到你。
本文还有配套的精品资源,点击获取