ARM64离线部署Harbor 2.13.1:避坑指南与API运维实践
简介本资源为面向 ARM 架构服务器环境的 Harbor 2.13.1 离线安装包适合在国产化平台、ARM 服务器或内网隔离场景下部署私有镜像仓库的运维与 DevOps 人员使用。压缩包共包含 6 个文件以 sh 安装脚本、gz 镜像归档、prepare 预检脚本、tmpl 配置模板及 license 许可文件为主覆盖从环境准备、参数配置到服务启动的完整离线部署链路整体约 513.28MB无需联网拉取镜像即可完成安装。目前已有 414 人学习下载说明该版本在 ARM 场景下具备一定实用参考价值。借助包内脚本与模板读者可快速搭建 Harbor 私有仓库理解离线安装的目录组织与配置项含义并在此基础上完成镜像推送、权限管理与日常运维排错适合需要在内网 ARM 环境落地容器镜像仓库的工程师参考使用。1. ARM 服务器上装 Harbor 2.13.1为什么离线包比在线脚本更靠谱在 ARM 架构的服务器上部署 Harbor很多人第一反应是直接跑官方在线安装脚本结果卡在拉镜像这一步——docker pull超时、manifest 找不到、镜像层下载到一半断流。这不是网络配置的问题而是 Harbor 官方在线安装脚本默认拉取的是 x86_64 架构镜像在 ARM 机器上根本跑不起来。harbor-offline-installer-v2.13.1-arm64.tgz这个包解决的就是这个问题它把 Harbor 全部组件镜像预先打包成 ARM64 版本解压后直接docker load不依赖外网拉取也不存在架构不匹配。适合在鲲鹏、飞腾、麒麟 V10 ARM64 等国产化平台上搭建私有镜像仓库的运维和开发人员。如果你手里正好有一台 ARM 服务器又不想在镜像拉取上反复折腾这个离线包是目前最省事的路径。2. 拆开离线包目录结构、镜像清单与版本对齐2.1 解压后到底有什么拿到harbor-offline-installer-v2.13.1-arm64.tgz之后先别急着执行install.sh。我一般会先解压到/opt下然后花两分钟把目录结构看清楚这一步能省掉后面很多返工。# 解压到 /opt 目录 tar -zxvf harbor-offline-installer-v2.13.1-arm64.tgz -C /opt # 进入解压后的目录 cd /opt/harbor # 查看目录内容 ls -lh执行完ls -lh你会看到几个关键文件harbor.v2.13.1.tar.gz是镜像包体积通常在 1.5GB 到 2GB 之间harbor.yml.tmpl是配置模板install.sh是安装入口脚本prepare是环境预检脚本。harbor.v2.13.1.tar.gz里面包含了 Harbor 核心组件、数据库、Redis、Nginx 等全部镜像全部是 ARM64 架构。# 查看镜像包内包含哪些镜像 tar -tzf harbor.v2.13.1.tar.gz | head -30 # 或者先解压镜像包再查看 tar -xzf harbor.v2.13.1.tar.gz ls -lh harbor/镜像包解压后是一个harbor目录里面按组件分门别类存放了*.tar镜像文件。常见的有harbor-core.tar、harbor-db.tar、harbor-jobservice.tar、harbor-portal.tar、harbor-registry.tar、harbor-redis.tar、nginx-photon.tar等。每个 tar 文件对应一个 Docker 镜像架构标签都是arm64。注意不要跳过解压镜像包这一步直接跑install.sh因为install.sh内部会调用docker load加载这些镜像如果镜像包不完整或解压失败安装脚本会在加载阶段报错而且错误信息不一定直观。2.2 版本对齐Docker、Docker Compose 与 Harbor 2.13.1 的兼容边界Harbor 2.13.1 对 Docker 和 Docker Compose 的版本有明确要求。在 ARM64 平台上Docker Engine 建议使用 20.10.x 及以上版本Docker Compose 需要 v2 版本注意不是 python 版的 docker-compose 1.x。很多 ARM 服务器出厂自带的 Docker 版本偏低或者装的是 podman-docker 兼容层这些都会导致install.sh执行失败。# 检查 Docker 版本 docker version --format {{.Server.Version}} # 检查 Docker Compose 版本 docker compose version # 如果 compose 是独立二进制检查路径 which docker-compose docker-compose version如果docker compose version报错说找不到子命令说明你装的是旧版 docker-compose 1.x需要升级到 v2。在 ARM64 上安装 Docker Compose v2 的常见做法是直接从 GitHub Releases 下载对应架构的二进制文件放到/usr/local/bin/下然后赋予执行权限。# 下载 Docker Compose v2 ARM64 二进制示例版本按需替换 curl -SL https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-linux-aarch64 \ -o /usr/local/bin/docker-compose # 赋予执行权限 chmod x /usr/local/bin/docker-compose # 验证 docker-compose version参数说明-SL中-S表示显示错误-L表示跟随重定向-o指定输出文件路径。下载的二进制文件名docker-compose-linux-aarch64中的aarch64就是 ARM64 架构标识不要下成x86_64版本。2.3 配置模板里必须改的三处harbor.yml.tmpl是配置模板直接复制成harbor.yml再改。有三处必须改否则安装会失败或者装完访问不了。# 复制配置模板 cp harbor.yml.tmpl harbor.yml # 编辑配置文件 vi harbor.yml第一处是hostname改成你服务器的实际 IP 或域名。如果写localhost或127.0.0.1其他机器访问不了。第二处是harbor_admin_password默认是Harbor12345生产环境必须改掉。第三处是data_volume默认是/data如果服务器上/data分区空间不够改成大分区的路径。# harbor.yml 关键配置片段 hostname: 192.168.1.100 # 改成实际 IP 或域名 harbor_admin_password: YourStrongPassword # 改掉默认密码 data_volume: /data # 确保该路径所在分区有足够空间如果不需要 HTTPS把https相关配置整段注释掉即可。Harbor 2.13.1 默认启用 HTTPS但离线环境下没有证书注释掉 HTTPS 配置后 Harbor 会以 HTTP 模式运行适合内网测试环境。3. 从零到跑起来ARM64 离线安装全流程与参数调优3.1 环境预检与依赖确认在跑install.sh之前先手动跑一遍prepare脚本它会检查 Docker 版本、Docker Compose 版本、端口占用等。这一步相当于提前排雷比装到一半报错再回头查要省时间。# 执行环境预检 ./prepare # 如果报错根据提示逐项修复 # 常见报错Docker version is too low # 解决升级 Docker Engine 到 20.10prepare脚本还会检查 80 和 443 端口是否被占用。如果服务器上已经有 Nginx 或 Apache 在跑需要先停掉或者改 Harbor 的监听端口。改端口在harbor.yml的http.port和https.port字段。# 修改 Harbor 监听端口 http: port: 8080 # 默认 80改成 8080 避免冲突注意改端口后hostname字段不要带端口号端口号只在http.port里配置。访问时用http://hostname:8080。3.2 执行安装脚本与镜像加载过程配置改好、预检通过之后执行安装脚本。这个过程会依次加载镜像、生成配置、启动容器耗时取决于磁盘 IO 速度通常在 2 到 5 分钟。# 执行安装 ./install.sh # 安装完成后查看容器状态 docker compose ps # 查看 Harbor 核心服务日志 docker compose logs -f harbor-coreinstall.sh内部做的事情按顺序是调用docker load加载harbor.v2.13.1.tar.gz里的所有镜像根据harbor.yml生成docker-compose.yml调用docker compose up -d启动所有容器。如果卡在docker load阶段通常是镜像包损坏或磁盘空间不足。# 检查磁盘空间 df -h /var/lib/docker # 如果空间不足清理无用镜像和容器 docker system prune -a安装完成后docker compose ps应该显示 9 个左右的容器处于running状态包括harbor-core、harbor-db、harbor-jobservice、harbor-portal、harbor-registry、harbor-redis、nginx、registryctl等。如果某个容器反复重启用docker compose logs 服务名看日志。3.3 登录、推拉镜像与项目创建Harbor 跑起来之后第一件事是登录 Web 界面创建项目然后在命令行登录并推拉镜像验证。# 命令行登录 Harbor docker login 192.168.1.100 -u admin -p YourStrongPassword # 给本地镜像打标签 docker tag nginx:latest 192.168.1.100/library/nginx:latest # 推送镜像 docker push 192.168.1.100/library/nginx:latest # 从 Harbor 拉取镜像 docker pull 192.168.1.100/library/nginx:latest参数说明docker login的-u是用户名-p是密码docker tag的格式是Harbor地址/项目名/镜像名:标签。项目名需要在 Web 界面提前创建或者用 API 创建。如果推送时报denied: requested access to the resource is denied通常是项目不存在或者用户没有该项目的推送权限。# 用 API 创建项目需要先获取 token 或用 basic auth curl -u admin:YourStrongPassword -X POST \ http://192.168.1.100/api/v2.0/projects \ -H Content-Type: application/json \ -d {project_name: library, public: true}这个 API 调用创建了一个名为library的公开项目。public: true表示该项目下的镜像可以被匿名拉取适合内网共享场景。如果设为false拉取镜像也需要登录。3.4 数据持久化与备份策略Harbor 的数据分两部分数据库数据PostgreSQL和镜像文件Registry 存储。默认情况下数据库数据存在/data/database镜像文件存在/data/registry。这两个目录必须做持久化否则容器重建后数据丢失。# 查看数据目录 ls -lh /data/ # 备份数据库 docker exec harbor-db pg_dump -U postgres registry /backup/harbor_db_$(date %Y%m%d).sql # 备份镜像存储直接打包 registry 目录 tar -czf /backup/harbor_registry_$(date %Y%m%d).tar.gz /data/registry常见做法是把/data挂载到独立的数据盘上然后对数据盘做定期快照。如果服务器没有独立数据盘至少要把/data目录纳入日常备份范围。数据库备份用pg_dump导出 SQL 文件镜像存储直接打包目录恢复时先恢复数据库再恢复 registry 目录。4. 避坑与排查ARM64 离线安装 Harbor 的五个血泪教训4.1 现象install.sh 执行到 docker load 报错 “no space left on device”原因/var/lib/docker所在分区空间不足。Harbor 离线包的镜像解压后占用空间在 3GB 到 5GB 之间加上 Docker 自身的存储开销至少需要 10GB 可用空间。解决先df -h确认分区剩余空间如果不足清理无用镜像和容器docker system prune -a或者把 Docker 数据目录迁移到大分区。迁移方法是修改/etc/docker/daemon.json中的># 修改 Docker 数据目录 cat /etc/docker/daemon.json # 添加或修改 data-root: /new/path/docker # 重启 Docker systemctl restart docker4.2 现象容器启动后 Harbor Web 界面打不开nginx 容器反复重启原因harbor.yml中hostname配置成了localhost或127.0.0.1导致 nginx 配置生成异常或者 80 端口被其他服务占用。解决把hostname改成服务器实际 IP确认 80 端口没有被占用。如果必须用其他端口改http.port字段。改完配置后需要重新执行./install.sh或者docker compose down docker compose up -d。# 检查端口占用 ss -tlnp | grep :80 # 如果被占用改 Harbor 端口 vi harbor.yml # 修改 http.port: 8080 # 重新生成配置并启动 docker compose down ./install.sh4.3 现象docker push 报 “manifest unknown” 或 “architecture mismatch”原因推送的镜像架构与 Harbor 期望的不一致。在 ARM64 服务器上如果推送的是 x86_64 镜像Harbor 不会拒绝存储但拉取到 ARM64 机器上运行时会出现exec format error。解决确保推送的镜像本身就是 ARM64 架构。用docker inspect查看镜像架构。# 查看镜像架构 docker inspect nginx:latest --format {{.Architecture}} # 输出应为 arm64 # 如果是 amd64需要重新构建或拉取 ARM64 版本4.4 现象Harbor 数据库容器启动失败日志显示 “initdb: cannot be run as root”原因PostgreSQL 容器默认不允许以 root 用户运行 initdb。在 ARM64 平台上某些基础镜像的默认用户配置与 x86_64 不同导致权限问题。解决检查docker-compose.yml中harbor-db服务的user字段。如果被显式设置为root改成postgres或者删掉该字段让镜像使用默认用户。# docker-compose.yml 中 harbor-db 服务片段 harbor-db: image: goharbor/harbor-db:v2.13.1 user: postgres # 不要设为 root4.5 现象安装完成后能登录但推送大镜像时超时原因Harbor 的 nginx 默认client_max_body_size可能不够大或者 registry 的存储后端性能不足。ARM64 服务器如果用的是机械硬盘大镜像写入速度慢容易触发超时。解决修改 nginx 配置中的client_max_body_size在harbor.yml中没有直接暴露这个参数需要改common/config/nginx/nginx.conf文件然后重启 nginx 容器。# 编辑 nginx 配置 vi common/config/nginx/nginx.conf # 找到 client_max_body_size改成 0 表示不限制 client_max_body_size 0; # 重启 nginx 容器 docker compose restart nginx注意改common/config/nginx/nginx.conf后重新执行./install.sh会覆盖这个文件。如果经常需要改建议在harbor.yml中通过nginx扩展字段配置或者把修改固化到安装脚本里。5. 进阶技巧用 Harbor API 做镜像清理与项目配额管理Harbor 跑起来之后真正费时间的是日常维护——镜像越堆越多磁盘很快被占满。Harbor 2.13.1 提供了 API 和 Web 界面的垃圾回收功能但很多人不知道 API 可以批量操作。我一般会写一个定时脚本每周清理一次无标签镜像和过期标签。import requests from requests.auth import HTTPBasicAuth HARBOR_URL http://192.168.1.100 AUTH HTTPBasicAuth(admin, YourStrongPassword) # 获取所有项目 projects requests.get(f{HARBOR_URL}/api/v2.0/projects, authAUTH).json() for proj in projects: proj_name proj[name] # 获取每个项目下的仓库 repos requests.get( f{HARBOR_URL}/api/v2.0/projects/{proj_name}/repositories, authAUTH ).json() for repo in repos: repo_name repo[name].split(/, 1)[1] # 获取仓库下的所有 artifact artifacts requests.get( f{HARBOR_URL}/api/v2.0/projects/{proj_name}/repositories/{repo_name}/artifacts, authAUTH ).json() for art in artifacts: tags art.get(tags) or [] # 删除无标签的 artifact if not tags: digest art[digest] requests.delete( f{HARBOR_URL}/api/v2.0/projects/{proj_name}/repositories/{repo_name}/artifacts/{digest}, authAUTH ) print(fDeleted untagged artifact: {proj_name}/{repo_name}{digest})这段脚本的逻辑是遍历所有项目再遍历每个项目下的仓库最后遍历每个仓库下的 artifact。如果 artifact 没有标签tags为空就调用删除接口。参数说明HARBOR_URL是 Harbor 地址AUTH用 basic auth 传用户名密码。删除接口的路径是/api/v2.0/projects/{project_name}/repositories/{repository_name}/artifacts/{digest}其中digest是 artifact 的摘要值。除了清理项目配额管理也很重要。Harbor 支持为每个项目设置存储配额超过配额后推送会被拒绝。用 API 设置配额的代码如下# 设置项目配额为 50GB quota { hard: { storage: 53687091200 # 50GB in bytes } } requests.put( f{HARBOR_URL}/api/v2.0/quotas/{proj_name}, authAUTH, jsonquota )配额的单位是字节50GB 等于50 * 1024 * 1024 * 1024 53687091200。设置之后该项目下的镜像总大小超过 50GB 时新的推送会被拒绝但已有镜像不受影响。还有一个容易被忽略的点Harbor 的垃圾回收GC不会自动删除 registry 存储中的物理文件需要手动触发。Web 界面在「系统管理」→「垃圾回收」里可以手动执行也可以用 API 触发。# 触发垃圾回收 curl -u admin:YourStrongPassword -X POST \ http://192.168.1.100/api/v2.0/system/gc/schedule \ -H Content-Type: application/json \ -d {schedule: {type: Manual}}执行 GC 时 Harbor 会进入只读模式期间不能推送镜像。建议在业务低峰期执行并且 GC 之前先做数据库备份。GC 完成后registry 存储中的无引用 blob 会被清理磁盘空间才会真正释放。从那以后我每次部署完 Harbor都会先把 GC 定时任务和项目配额配上再写一个每周执行的清理脚本。不然等到磁盘告警再处理往往已经来不及了。希望帮到你。本文还有配套的精品资源点击获取