ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ARM服务器离线部署Harbor:离线包安装与常见问题排查

ARM服务器离线部署Harbor:离线包安装与常见问题排查 简介面向ARM架构服务器如鲲鹏、飞腾的Harbor 2.13.1私有镜像仓库离线部署包专为解决内网或信创环境下依赖下载困难、镜像拉取超时等问题而设计适合需要快速搭建镜像仓库的运维人员和系统架构师。压缩包共6个文件以shell安装脚本、离线镜像压缩包、配置模板及证书许可文件为主安装脚本实现自动化部署离线镜像包内含完整Harbor组件配置模板支持按业务调整参数整体约513MB。目前已有413人学习下载。读者只需将离线包上传至目标ARM服务器即可摆脱外网依赖完成安装与初始化通过prepare工具自动预检环境减少手工配置和排错成本压缩包结构精简核心组件一次齐备很适合在生产或交付环境中直接复用。1. Arm 服务器上离线部署 Harbor一个 tgz 解决“镜像仓库进不去内网”的难题一台 aarch64 服务器网络隔离开发机上几千个镜像没法推过去DevOps 流水线卡在最后一步——这是我在 ARM 设备上做交付时最常遇到的卡点。harbor-offline-installer-v2.13.1-arm64.tgz 就是为这种场景准备的它把 Harbor 2.13.1 的整套组件镜像和安装脚本打成一个离线包拿到内网解压、改配置、跑脚本就能起一套带 Web 界面的镜像仓库全程不依赖外部镜像源。适合正在维护 ARM 服务器、边缘节点或者需要把开发环境整体迁到内网的一线工程师。这个包有个反直觉的地方真正花时间的往往不是安装过程而是环境适配。docker compose 版本、数据卷权限、hostname 解析、内存水位这四个问题承包了绝大多数安装失败现场。这篇笔记先拆包看结构再把环境准备和安装步骤走一遍最后把亲测过的坑按现象、原因、解决排出来。从解压到 Web 页面能登录大概 1 小时把坑踩熟之后可以压到 20 分钟。2. 离线包拆解arm64 版 Harbor 2.13.1 的组件构成与选型逻辑2.1 为什么 arm 架构必须用 arm64 专用离线包Harbor 官方 release 资产里同时提供 amd64 和 arm64 两种形态的离线包命名规则很直白arm64 包的文件名里会带arm64字样。这个区分不是多此一举而是因为 Harbor 由十几个组件镜像组成这些镜像各自打上了linux/amd64或linux/arm64的架构标签。docker load阶段如果发现镜像架构和宿主机不匹配会直接报image with reference ... was found but does not match the specified platform装到一半停下来。我见过有人图省事拿 x86 的离线包往 ARM 服务器上硬灌结果 registry、core 这些容器起来之后行为异常日志里全是exec format error。这不是 Harbor 本身的问题是镜像里的二进制是 x86 指令集ARM 处理器跑不了。反过来也一样在 x86 机器上 load arm64 包同样会翻车。所以第一原则很朴素目标机是aarch64就用arm64离线包目标机是x86_64就用不带架构后缀的通用包。别混用。2.2 离线包里装了哪些组件解压离线包以后镜像都封装在几个 tar 包里。一次完整的 Harbor 2.13.1 部署核心组件大概是下面这套具体小版本号以你解压后docker images的输出为准组件镜像名在 Harbor 里的职责coregoharbor/harbor-core提供 API、认证、配额管理、项目逻辑registrygoharbor/harbor-registry镜像存储与分发基于 Docker Distributionregistryctlgoharbor/harbor-registryctlRegistry 的配置与管理辅助进程jobservicegoharbor/harbor-jobservice处理复制、GC、扫描等异步任务portalgoharbor/harbor-portalWeb 控制台前端dbgoharbor/harbor-dbPostgreSQL保存项目、用户、复制规则等元数据redisgoharbor/harbor-redis缓存与任务队列loggoharbor/harbor-log日志采集基于 rsyslognginxgoharbor/nginx-photon统一入口按路径分发到各组件trivygoharbor/trivy-adapter漏洞扫描默认不启用带--with-trivy装上的是 trivy-adapter带--with-notary会多出 notary-server 和 notary-signer。我需要提醒一句默认安装不包含这两个因为它们的资源开销不小在小内存 ARM 机器上开启后postgres 和 trivy 抢内存容器容易被 OOM 杀掉。这个话题在第 5 章展开。2.3 解压后先确认这几样东西拿到harbor-offline-installer-v2.13.1-arm64.tgz以后先不要急着找install.sh双击执行。我一般先解压然后对比几个关键文件在不在文件作用注意点harbor.yml.tmpl配置文件模板必须复制成 harbor.yml 再改不能直接改模板install.sh安装入口会调用 prepare然后 docker compose upprepare配置预处理脚本负责生成各组件需要的配置文件common.sh公共函数库缺失时 install.sh 直接退出harbor.v2.13.1.tar.gz组件镜像包可能按组件拆成多个 tgzinstall 时自动 loadinstall.sh在执行时自动加载这些镜像包不需要手动docker load。曾经有同事觉得“既然有 tar 包我手动 load 一下更稳妥”结果中途顺序乱了prepare 阶段找不到镜像反而把环境搞脏了。我的习惯是解压完以后只改配置文件剩下交给脚本。系统会提示Harbor has been installed and started successfully看到这行字才算真正跑起来。2.4 离线包和在线安装包怎么选在线安装包体积小解压后边装边从 Docker Hub 拉镜像适合安装机有稳定公网访问的场景。离线包则把所有镜像固化在 tgz 里适合生产内网、隔离网、以及公网拉取不稳定的环境。绝大多数 ARM 服务器部署场景是离线内网所以直接选-arm64.tgz结尾的离线包。这里有一个容易被忽略的点离线包只解决安装阶段的镜像来源不解决后续运行时的外部依赖。比如你配了远程复制、镜像缓存这类功能运行期还是需要网络通道。换句话说离线包保证的是“装得上”不保证“所有功能都离线可用”。选型时要把这个边界跟团队讲清楚避免后面功能启用了才发现网络不通。3. 安装前环境准备Compose 版本、数据卷与端口是三大命门3.1 先确认你是不是真的在 arm64 上离线包的名字写着arm64不等于目标机器就一定能装。ARM 服务器之间有代差aarch64是 64 位 ARM 指令集armv7l是 32 位 ARM两者镜像完全不通用。我接手过的机器里有鲲鹏、飞腾也有开发板和小型 NAS你很难从外观判断位数最稳妥的办法是在 shell 里直接问系统uname -m # 期望输出aarch64如果输出是armv7l或者armv6l说明这是 32 位 ARM 环境这个离线包装不了。还可以再补一条确认架构信息的命令grep -i architecture /proc/cpuinfo | head -1 cat /etc/os-release第一条看 CPU 架构第二条看发行版信息。确认是aarch64之后再往下走。之前在论坛看到有人在树莓派 3B 上想装 Harbor那是 armv7l折腾一晚上才醒悟过来。这个检查只要十秒值得养成习惯。3.2 Docker 与 Docker Compose 版本基线Harbor 2.13.1 的安装过程在很大程度上依赖 Docker Compose。这里有个常见认知误区机器上有docker-compose命令不代表版本够用。老版本的docker-compose1.x 是 Python 实现的新版本用 Go 重写成了 Docker 插件调用方式是docker compose中间有个空格。Harbor 的install.sh会对 Compose 版本做校验1.x大概率直接报Compose version is not sufficient。先看当前环境docker --version docker compose versiondocker compose version这条命令能跑通输出类似Docker Compose version v2.24.2说明 Compose v2 插件已就位。如果命令报错或者只能找到docker-compose就需要补装插件。以 Debian/Ubuntu 系为例常见做法是sudo apt install docker-compose-plugin docker compose versionCentOS 系的包名通常是docker-compose-plugin或docker-compose-v2具体以发行版仓库为准。我不推荐用pip install docker-compose的方式补那个方案停在 1.x装完照样过不了 Harbor 的校验。这个版本检查是整个安装过程里最值得先做的一项因为失败得最早也最容易修。3.3 数据卷、内存、端口规划Harbor 的二进制包不大但跑起来之后数据卷会持续膨胀。镜像仓库的数据全在data_volume目录下默认是/data。我见过最惨的一次翻车是把 Harbor 装在系统根分区上跑了三个月磁盘满了postgres 直接拒绝写入。所以安装前先看磁盘df -h /data规划时可以参考下面这张表条目建议说明data_volume单独挂载的磁盘SSD 更稳镜像 blob 有大文件也有碎文件机械盘 GC 时性能很差文件系统ext4 或 xfs注意个别发行版默认 zfs/btrfs先确认内核模块内存2GB 起步4GB 舒适关掉 trivy 可压到 1.5GB低于 1GB 不建议HTTP 端口80被占用时可在 harbor.yml 改比如 8080HTTPS 端口443不启用就保持注释状态Registry 端口5000容器内部端口映射关系在 docker-compose 里Notary 端口4443仅当启用 notary 时占用端口这块有个经验80 端口在生产服务器上经常被 nginx 或其他服务占用。如果你决定把 Harbor 的 HTTP 端口改成 8080那么后续所有docker login、docker tag、docker push里的地址都要带端口号例如harbor.internal:8080。这个改动会影响全团队的使用习惯改之前先确认值得。3.4 主机名解析与时间同步Harbor 的配置里有一项hostname它决定后续镜像地址的前缀。安装完后开发机上docker push harbor.internal/library/app:v1能不能成功取决于这条地址能不能解析到 Harbor 服务器。内网没有 DNS 的情况下我一般在客户端机器的/etc/hosts里写死192.168.10.20 harbor.internal同时把 Harbor 服务器自己的/etc/hosts也配上这条映射。Harbor 启动时会用hostname生成内部 URL如果这台机器解析不到自己健康检查会出现诡异的失败。时间同步是另一个容易被忽略的点。如果启用了 Harbor 的复制功能源仓库和目标仓库之间的 token 校验依赖时间窗口两边时间偏差超过几分钟复制任务会报认证失败。我在生产环境里会用 chrony 或 systemd-timesyncd 保证所有节点的时钟一致这个操作在 ARM 服务器上尤其重要因为很多小板子没有 RTC 电池断电重启后时间会跳到 1970 年。4. 离线安装实操解压、改配置、跑脚本从零到 Web 登录4.1 校验下载文件并解压从文件服务器把harbor-offline-installer-v2.13.1-arm64.tgz传到目标机器以后第一件事是校验完整性。大文件在传输过程中损坏的概率不低尤其是跨内网传输或通过 USB 拷盘时。我一般先把官方提供的 sha256 校验值存下来然后执行sha256sum harbor-offline-installer-v2.13.1-arm64.tgz对比输出和官方给出的校验值一致再解压。这一步花不了多少时间但能拦住后面大量莫名其妙的问题。校验通过后解压tar zxf harbor-offline-installer-v2.13.1-arm64.tgz cd harbor-offline-installer-v2.13.1-arm64 ls -lh解压后你会看到harbor.yml.tmpl、install.sh、prepare、common.sh以及一个或多个.tar.gz镜像包。文件列表和第 2 章表格里的对应得上就算就绪了。接下来所有操作都在这个目录里进行。4.2 把模板配置改到能跑Harbor 安装的核心是harbor.yml。官方给的是模板harbor.yml.tmpl本质上是一个带注释的完整配置。先复制成正式配置cp harbor.yml.tmpl harbor.yml然后编辑harbor.yml。我习惯用vim你也可以用任何趁手的编辑器。需要重点关注的字段如下这些字段直接决定安装结果和团队日常使用体验字段建议值说明hostnameharbor.internal必须改成内网可达的域名或 IPhttp.port80默认 HTTP 端口https注释状态只在确认有证书时启用harbor_admin_password强密码管理员初始密码长度至少 8 位database.password强密码PostgreSQL 内部账号密码data_volume/data镜像数据、数据库文件的根目录jobservice.max_job_workers3小内存机器调低减少并发任务抢占trivy.enabledfalse内存紧张时保持关闭下面是一个精简但可运行的配置片段注意字段名以你解压出来的模板为准hostname: harbor.internal http: port: 80 https: port: 443 certificate: /data/cert/harbor.crt private_key: /data/cert/harbor.key harbor_admin_password: ChangeMe_2024 database: password: DbChangeMe2024 max_idle_conns: 50 max_open_conns: 100 data_volume: /data jobservice: max_job_workers: 3 trivy: enabled: falsehostname是镜像仓库的对外地址写127.0.0.1会害死后续所有 push 操作。harbor_admin_password和database.password都必须改掉默认值尤其是database.passwordHarbor 默认是root123内网里被扫到就是裸奔。如果不需要 HTTPS把整个https:段保持注释状态不要留一个空配置。我自己习惯内网环境直接用 HTTP省去客户端 CA 分发的麻烦这个方案在第 5 章会展开。4.3 执行安装脚本配置改完以后直接执行安装脚本./install.sh脚本内部会先跑prepare生成各组件配置再docker load镜像包最后docker compose up -d启动所有容器。整个过程大概需要 3 到 10 分钟取决于磁盘速度和镜像包大小。如果后续需要启用漏洞扫描执行./install.sh --with-trivy参数含义很直接--with-trivy附带漏洞扫描组件--with-notary附带镜像签名组件--with-chartmuseum附带 Helm Chart 仓库。ARM 小内存机器上我强烈建议一个都不要带先把核心功能跑起来再说。不要在第一次安装时就追求功能齐全组件越多内存和磁盘的余量要求越高。安装过程中如果看到报错不用急着重跑先看日志。安装日志一般落在/var/log/harbor/目录下也可以直接重跑并用tee记录./install.sh 21 | tee /tmp/harbor-install.log成功结束的标志是✔ ----Harbor has been installed and started successfully----。没看到这行字说明某一步出了问题顺着报错排查再决定是否重跑。4.4 启动后的自检安装完成之后立刻做一轮自检别等团队来反馈“登录不上”。最直接的是看容器状态docker compose ps所有服务都应该显示Up关键服务还应当带(healthy)标记。harbor-core的(healthy)是 Harbor 是否自检通过的重要信号。如果某个容器反复Restarting多半是配置或资源问题下一步就去看这个容器的日志docker compose logs harbor-core然后通过 API 验证健康状态curl -i http://harbor.internal/api/v2.0/health正常返回{status:healthy}HTTP 状态码 200。这里注意替换成你实际配置的hostname。最后在浏览器里访问http://harbor.internal用admin和你设置的密码登录看到项目列表页面整套安装才算真正落地。5. Arm 环境部署 Harbor 高频踩坑排查五个我翻过车的现场5.1 Compose 版本过低install.sh 直接拒绝执行现象执行./install.sh后脚本输出类似Compose version is not sufficient的错误还没开始 load 镜像就退出了。原因系统里只有docker-compose1.x。Harbor 2.13.1 的安装脚本要求 Compose v2 版本1.x 的某些参数行为和 v2 差异较大脚本无法兼容。解决安装 Compose v2 插件。Debian/Ubuntu 系统执行sudo apt install docker-compose-plugin装完验证docker compose version看到Docker Compose version v2.x.x就对了。血泪教训不要用pip install docker-compose来补装的还是 1.x白折腾。5.2 数据卷权限导致数据库容器循环重启现象harbor-db容器一启动就退出docker compose ps里显示Restarting日志里能看到Permission denied或者could not change permissions。原因data_volume指向的目录属于 root或者启用了 SELinux 导致容器内进程无法写入。Harbor 容器内的 postgres 进程以非 root 用户运行对数据目录必须有完整读写权限。解决先把数据目录属主调整到位mkdir -p /data chown -R 10000:10000 /data如果系统开了 SELinux还需要给容器数据目录打上正确的上下文标签或者临时setenforce 0验证是不是 SELinux 的问题。从那以后我每次安装前都会强制检查一遍ls -ld /data避免把问题带到安装阶段。5.3 内存不足多个组件被 OOM 干掉现象安装过程中容器逐个起来但registry或harbor-core起来一会就退出docker compose ps里反复出现Restarting。查系统日志能看到dmesg | grep -i oom | tail -20原因1GB 内存的 ARM 设备上跑了 postgres、redis、registry 等一堆常驻服务内存水位耗尽内核直接 kill 掉一些容器进程。解决小内存机器不要追求功能齐全。用./install.sh不带任何--with-*参数关闭 trivy、notary同时把jobservice.max_job_workers调小到 3再给 Docker 配置 swap 作为兜底。实测 2GB 内存的 ARM 设备能稳定跑起来1GB 设备尽量只做开发验证不要当生产仓库用。5.4 hostname 写 127.0.0.1push 镜像时客户端连不上现象Web 页面能登录但在开发机上执行docker push harbor.internal/library/app:v1报错提示无法解析主机名或连接超时而浏览器访问却一切正常。原因harbor.yml里hostname写的是127.0.0.1Harbor 对外暴露的地址变成了本机回环地址。浏览器在 Harbor 服务器本机上访问没问题但其他开发机根本不知道127.0.0.1指向哪里。解决把hostname改成内网实际 IP 或域名比如192.168.10.20或harbor.internal然后在开发机的/etc/hosts里绑定。改动后需要重新执行./install.sh让配置生效。这个问题的特征很有迷惑性Web 能开就以为服务没问题实际数据面完全不通。5.5 自签证书在客户端不被信任现象启用 HTTPS 后开发机执行docker login harbor.internal报错x509: certificate signed by unknown authority浏览器打开也会出现红色警告页。原因内网自签 CA 的根证书没有被客户端的系统证书库信任。Docker 客户端严格校验 HTTPS 证书链不信任就直接拒绝。解决把自签 CA 分发到每一台需要访问 Harbor 的机器上sudo cp harbor-ca.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates sudo systemctl restart docker注意systemctl restart docker会中断节点上正在运行的容器生产环境要选低峰期操作。如果你和我一样不想维护这么多客户端的证书内网场景可以直接用 HTTP 方案在每台客户机的/etc/docker/daemon.json里配置白名单。{ insecure-registries: [harbor.internal:80] }改完同样要重启 docker。这个方案省掉了证书分发环节代价是传输不加密适合完全隔离的内网。两种方案取舍很清晰规范团队用 HTTPS图省事用 HTTP 加白名单。6. 验证与维护习惯让这套 Arm Harbor 长期不闹心6.1 跑一遍完整的 push/pull 闭环环境验收时我会用一台干净的开发机走完整闭环确认数据面真正可用。先在客户端登录docker login harbor.internal -u admin然后随便拉一个本地已有的镜像改成 Harbor 仓库地址推上去docker tag nginx:1.27 harbor.internal/library/nginx-arm:v1 docker push harbor.internal/library/nginx-arm:v1 docker pull harbor.internal/library/nginx-arm:v1docker pull能成功拉回来说明存储、分发、认证整体链路是通的。再回到 Web 界面确认library/nginx-arm项目里出现了v1这个镜像整个生命周期就闭环了。6.2 arm 环境该养成的备份与远端缓存习惯数据安全上Harbor 的备份核心是两块PostgreSQL 里存的元数据以及data_volume里的镜像 blob。升级前我会先给数据库做一次逻辑备份docker exec harbor-db pg_dump -U postgres -c harbor harbor-db-$(date %F).sql执行前先用docker exec -it harbor-db psql -U postgres -l确认实际库名不同小版本可能略有差异。不要改数据卷目录里的内容直接复制整个/data目录做物理备份更稳妥。arm 环境还有一个很推荐的玩法利用 Harbor 的 Proxy Cache 功能把远端公共仓库的 arm64 镜像缓存到内网。开发机上反复拉同一个基础镜像时命中缓存就走内网流量既快又稳定。配置方法不复杂在 Web 界面新建一个项目类型选 Proxy Cache填远端仓库地址就行。从那以后我每次在 arm 环境交付 Harbor都会强制走一遍完整检查清单架构确认、compose 版本、数据卷权限、push/pull 闭环、证书分发五分钟做完再也没有半夜被拉起来处理“装不上”的问题。希望这些经验能帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进