news 2026/10/22 10:58:28

Docker Compose部署Harbor私有镜像仓库全流程实操与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker Compose部署Harbor私有镜像仓库全流程实操与避坑指南

部署一个私有镜像仓库这种事,我印象里每次都有人卡在同一批坑上。这次我用 docker-compose 在云主机上完整部署了最新版 Harbor v2.3.4,从离线安装包下载、自签名证书生成、harbor.yml 配置,到 prepare 脚本、docker-compose up -d 全流程走完,中间还解锁了不少网上好多人懒得写清楚的细节。这篇就是把这次实操经历完整记录下来,尤其是官方文档语焉不详、但实际部署又绕不开的部分,我尽量用大白话讲透。你手头有 Linux 服务器、会基础 docker 命令就能跟上;要是完全没接触过 Harbor,第二节的配置拆解也能帮你少搜半天资料。

1. 部署前先理清的问题

1.1 为什么用 docker-compose 而不是 Helm 或其他方式

Harbor 官方给出的安装方式其实有好几种:在线安装包、离线安装包、Helm Chart,还有基于 Operator 的方式。标题既然说 docker-compose,那重点就落在官方前两种安装包上,因为这两类安装包底层就是靠 docker-compose 编排的。

有同学可能会问,现在 K8s 都普及成这样了,为什么还要用 docker-compose 装 Harbor?我的看法是:对于中小团队、单机或少量节点这种最常出现的使用场景,docker-compose 方案是代价最小的。它不需要维护一整套 K8s 集群,故障排查链路也短——容器起没起,docker-compose ps 一眼就能看出来;哪个服务挂了,docker-compose logs 直接追日志。Helm 方案虽然更适合已经被 K8s 托管的场景,但引入的 values 配置、存储卷、网络策略这些复杂度,对只想快速落地一个镜像仓库的团队来说完全没必要。

这里要特别注意一个细节:docker-compose 这个命令本身分两个时代。老一代是独立安装的 python 写的 docker-compose 二进制,新一代是 docker 官方插件 docker compose(中间没有横杠)。Harbor 官方安装脚本在 v2.3.4 这个版本里依旧用的是带横杠的 docker-compose 命令。如果你装的是新版插件,要么补一个软链接别名,要么直接用老版本二进制。这一步没搞对,后面 install.sh 一执行就报 command not found,很多人在这里就卡住了。

1.2 v2.3.4 这个版本有什么值得注意的

很多人一看到“最新版”三个字,会默认选市场上数字最大的版本号。但实际在企业环境里,版本选择更看重的是稳定性和团队熟悉程度。v2.3.4 属于 2.x 系列里比较扎实的一个小版本,它的底层架构和之后 2.4、2.5 没有颠覆性差异,而 2.3 这个系列有几个标志性能力:

  • 默认漏洞扫描组件从 Clair 切换成了 Trivy,扫描速度比之前快不少
  • 支持 Proxy Cache 功能,拉公共镜像的时候可以先经过 Harbor 缓存一下,内网重复拉取就不走外网了
  • 机器人账号可以做项目级和系统级两种维度,CI/CD 场景下权限隔离更灵活
  • API 全面走 v2.0,脚本自动化对接没障碍

对于标题这个任务来说,只要是 2.3.4 这个版本,后续涉及到的配置文件字段、环境变量和目录结构基本是同一套,照着这篇文章操作即可。

我个人的建议是:不需要为了追新版本而追新版本。把 v2.3.4 跑稳,理解清楚它的配置逻辑,将来再升级到更高版本,迁移路径也是顺的。真正等你需要新版本功能的时候,再花半小时看 release notes 升级也不晚。

1.3 服务器资源、端口和数据目录的规划

Harbor 这套东西看着就是几个容器,但实际跑起来比你想象中要“肥”。官方给的最低要求是 2GB 内存、10GB 磁盘空间,我用下来的真实体感是:2GB 内存只能算是能启动,一旦有镜像推送、漏洞扫描任务同时跑,内存很容易顶到 90% 以上。我的建议是 4GB 起步,8GB 会比较舒服,这还没算上数据库连接数和 Trivy 扫描器的临时占用。

磁盘方面,镜像数据增长速度完全取决于你的使用频率,开发环境可能一个月几个 GB,生产环境一天几十 GB 也不稀奇。所以数据盘至少 50GB 起步,并且强烈建议把 data_volume 单独挂到非系统盘上。系统盘和数据盘放在一起,迟早会出现“镜像把系统盘塞满,docker daemon 直接罢工”的事故。

端口规划主要是三块:

端口用途说明
80HTTP 访问默认提供,可改
443HTTPS 访问默认提供,可改
4443Notary 签名组件云服务器安全组默认不放开,需要手动加规则

这三个端口如果已经被宿主机上的 Nginx、Apache 或其他容器占用,就会出大问题,具体排错我在第四节展开。另外提醒一句,Harbor 各组件之间依赖时间和令牌校验,服务器 NTP 时钟同步一定要配好,否则你会发现登录时好时坏、拉取镜像偶尔 401,排查半天最后发现是时钟漂移。

2. 安装包获取与配置文件逐项拆解

2.1 在线包和离线包怎么选

Harbor 官方发布包分两种:在线安装包 harbor-online-installer 和离线安装包 harbor-offline-installer。相同版本下,离线包体积要大得多,因为里面预先打包好了所有组件的镜像,比如 harbor-core、harbor-registry、harbor-jobservice、trivy-adapter、nginx 等等全都在 harbor.v2.3.4.tar.gz 这个文件里。

选哪个?我这次用的是离线包。原因很简单:在线包安装的时候 install.sh 里要现场从网络拉取镜像,一旦网络波动或者超时,安装过程就断在半路上。离线包下载下来之后,内网环境也能装,整个过程不依赖外网连通性。下载完记得校验一下压缩包完整性,常见做法是对一下官方发布的 sha256 校验值,别嫌这一步麻烦,压缩包损坏导致的玄学报错比想象中多。

解压之后会得到一个 harbor 目录,里面的东西大致是:

harbor/ ├── harbor.yml.tmpl # 配置模板,必须复制成 harbor.yml 才能用 ├── install.sh # 一键安装脚本 ├── prepare # 配置生成脚本,核心 ├── common.sh # 公共函数库 ├── docker-compose.yml # compose 编排文件 └── harbor.v2.3.4.tar.gz # 离线镜像包

install.sh 本质上就是先 load 离线镜像,然后调用 prepare 生成配置,最后 docker-compose up -d。理解这个执行链条以后,你以后手排问题会轻松很多。

2.2 harbor.yml 关键配置逐行讲

第一次部署,先把模板复制成正式配置:

cd harbor cp harbor.yml.tmpl harbor.yml vi harbor.yml

配置文件里几个必须关注的项我拆开讲:

  • hostname:这个值写你的域名或 IP,客户端访问 Harbor 的地址就是它。生产环境强烈建议用域名,比如 registry.example.com,而不是裸 IP。后面证书、客户端配置、复制目标配置全都以这个 hostname 为基准,这会带来 ip 直连想象不到的便利。
  • http.port 和 https.port:默认 80 和 443。如果宿主机上已经有进程占用,可以改成 18080 和 18443,但改完后意味着客户端访问、docker login 都要带上对应端口,尽量保持默认。
  • https.certificate 和 https.private_key:指向证书和私钥的绝对路径,证书生成过程在下小节讲。
  • data_volume:默认是 /data,这个就是所有容器的挂载卷根目录。我建议改成 /data/harbor,避免和其他应用共用目录造成混乱。镜像数据、数据库文件、redis 数据全在这里,备份时重点关注这个目录。
  • harbor_admin_password:初始化 admin 用户的密码。v2.3 开始对密码复杂度有要求,太短会在启动阶段直接报错,别图省事设个 123456 就完了。
  • database.password:PostgreSQL 的密码,生产环境必改,别用默认值。
  • trivy 相关配置有两个值值得留意:ignore_unfixed 表示是否只显示已修复漏洞,skip_update 表示是否跳过漏洞库更新。离线环境建议把 skip_update 设为 true,否则 Trivy 容器会尝试从网络下载漏洞数据库,失败后扫描任务会一直 Pending。

配置文件里还有 chart、jobservice、notification 等段落,正常部署保持默认即可,不需要过度配置。把上面几个关键项填对,这个文件就算过了 80%。

2.3 证书生成这一步别偷懒

HTTPS 证书有两种路线:正规 CA 签发的证书,以及内网自签名证书。公网开放使用,我建议直接买或者申请可信 CA 证书。纯内网、测试环境,自签名足够。这次我就用自签名走一遍。

自签名有一个标准操作流程,先用 CA 私钥造一个 CA 根证书,再用 CA 给服务器签一张证书。很多教程只给一个命令生成证书,但那种不带 Subject Alternative Name 的证书在现在的浏览器里直接被标记为不安全。OpenSSL 命令如下:

# 1. 生成 CA 私钥和根证书 openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -sha512 -days 3650 \ -subj "/CN=registry.example.com" \ -key ca.key -out ca.crt # 2. 生成服务器私钥和证书签名请求 openssl genrsa -out server.key 4096 openssl req -new -sha256 -key server.key -out server.csr \ -subj "/CN=registry.example.com" # 3. 用 CA 签发服务器证书 openssl x509 -req -sha512 -days 3650 \ -extfile v3.ext \ -CA ca.crt -CAkey ca.key -CAcreateserial \ -in server.csr -out server.crt

v3.ext 文件内容如下,IP 字段按需保留,域名建议放 DNS 里:

subjectAltName = @alt_names [alt_names] DNS.1 = registry.example.com IP.1 = 192.168.1.10

签发完成之后,把 ca.crt、server.crt、server.key 放到一个固定目录,比如 /data/harbor/cert,然后在 harbor.yml 里对应指向。证书文件权限也要注意,server.key 权限建议 400,server.crt 权限 644,权限不对会导致 nginx 容器启动失败。自签名方案下,ca.crt 必须永久保留,因为之后每个要访问 Harbor 的客户端都得信任它。

3. 完整部署流程实录

3.1 prepare 阶段容易踩的三个报错

很多教程上来就让你跑 install.sh,但对于排错来说,手动拆开执行反而更清楚。先把离线镜像导进去:

docker load -i harbor.v2.3.4.tar.gz

然后执行 prepare 脚本:

./prepare

prepare 这个脚本是 Python 写的,它读取 harbor.yml,生成各组件运行所需的配置目录和 docker-compose.yml 最终版本。这个环节最常见的三个报错:

第一,Python 环境不对。prepare 脚本需要 Python 3 和 PyYAML 模块。很多 CentOS 7 默认 Python 版本还是 2,运行时报语法错误或者 ModuleNotFoundError。处理办法是装好 Python 3,再用 pip 安装 pyyaml,之后重新执行 prepare。注意 prepare 不会自动检测 Python 版本,报错信息有时候非常隐晦,看到类似 ModuleNotFoundError: No module named 'yaml' 的提示,基本就是它了。

第二,配置校验不通过。harbor.yml 里 hostname 留成了 localhost 或者填了带下划线的域名,prepare 会直接报 invalid config,启动流程中断。趁早把所有配置项填规范,免得来回试。

第三,端口被占用。这时候 prepare 一般能过,但在后面 docker-compose up 时才会暴露,我会在下节一起说。

3.2 docker-compose up -d 执行与启动验证

配置生成完毕,正式启动:

docker-compose up -d

第一次启动会创建并拉起十几个容器,主要包括 harbor-core、harbor-portal、harbor-registry、harbor-db、harbor-jobservice、harbor-log、harbor-redis、nginx、trivy-adapter 等。启动时间取决于机器性能,一般一到三分钟。

启动完先别急着访问,确认所有容器状态是 Up:

docker-compose ps

如果某个容器一直是 Restarting,大概率是下面几个原因:

端口占用是最常见的。harbor 的 nginx 容器要监听宿主机 80/443,如果这台机器已经装了 Nginx、Apache,或者某容器占用着端口,docker 会报 driver failed programming external connectivity on endpoint,底层错误写着 bind: address already in use。处理办法:先把占用端口的进程停掉,或者改 harbor.yml 端口后重新执行 prepare,注意改完之后必须重新 prepare 一次,直接 docker-compose up 不会生效。

第二种情况是目录权限。data_volume 目录如果不允许容器内用户写入,容器会反复启动失败。把数据目录属主改成当前用户,或者用 chmod / chown 调整权限后再 up。

容器都稳定 Up 之后,浏览器访问 https://registry.example.com,首次访问会出现自签名证书告警,点“继续前往”即可。如果连页面都打不开,检查云安全组和防火墙规则,放行 443(还有 80)入方向。

登录页面出来后,用 harbor.yml 里配置的 admin 密码登录。登录成功不代表部署完全没问题,真正的验证还要看镜像 push / pull 能不能跑通,这是第四节的重点。

3.3 把自签名证书分发到客户端

部署完成后第一件让人头疼的事就是 docker login 直接失败,报错信息一般是:

x509: certificate signed by unknown authority

原因很简单:docker 客户端不认识你这套自签名 CA。正确做法是把 CA 证书分发到每个需要访问 Harbor 的机器上,并放到 docker 的证书目录里。

Linux 客户端做法:

sudo mkdir -p /etc/docker/certs.d/registry.example.com sudo cp ca.crt /etc/docker/certs.d/registry.example.com/ca.crt sudo systemctl restart docker

路径里的 registry.example.com 必须和 harbor.yml 的 hostname 完全一致,否则不生效。然后执行:

docker login registry.example.com

如果公司内网没有 DNS 解析,还要在客户机 /etc/hosts 里加一行记录:

192.168.1.10 registry.example.com

macOS 和 Windows 的 Docker Desktop 处理方式略有不同:可以直接把 ca.crt 导入系统钥匙串或受信任根证书颁发机构,也可以在 Docker Desktop 设置里把 registry.example.com 加进 insecure-registries 列表。但 insecure-registries 本质是关闭证书校验,有中间人风险,不建议多团队生产环境用。还有一个容易被忽略的点:配置文件里的 hostname、证书里的 CN/SAN、客户端访问的域名、docker 证书目录的文件夹名,这四个必须完全一致,否则即使你信任了证书,docker 也会报证书与主机名不匹配。

4. 部署完成后的功能校验

4.1 先跑通 push / pull 全流程再谈别的

容器仓库如果不能 push / pull,就算 UI 登录成功也是白搭。完整验证流程如下:

先在 Harbor 网页上创建一个项目,比如叫 test,访问级别先选私有。然后在本机给镜像打个标签:

docker tag nginx:alpine registry.example.com/test/nginx:alpine docker push registry.example.com/test/nginx:alpine

第一次 push 需要先 docker login。登录成功后 push 应该正常完成。到 UI 的 test 项目仓库页面里,能看到 nginx 这个镜像和对应标签,就说明核心链路通了。

接着验证拉取:

docker rmi registry.example.com/test/nginx:alpine docker pull registry.example.com/test/nginx:alpine

如果手头有一台全新客户端,建议在另一台机器上重复一次 login、pull 流程,这样才能确认证书分发的完整性,而不是恰好本地运气好。

我建议在这个阶段顺带验证一下 Trivy 漏洞扫描:在项目里给刚才推送的镜像发起扫描,如果一直处于 Pending 状态,多半就是漏洞库更新失败。离线环境把 harbor.yml 里 trivy 的 skip_update 改成 true 再重新 prepare,能暂时绕过去。联网环境则可以等它自动下载,首次下载漏洞数据库耗时比较长,不用慌。

4.2 用户体系、项目隔离和机器人账号配置

部署完第一件事,不要急着把 admin 密码发给所有人。多个人共享一个 admin 账号,后面查操作记录、权限回收都是灾难。正确定级是:创建几个真实用户,给不同人分配项目维度角色。Harbor 项目角色分为项目管理员、开发者、访客等,开发者角色能 push / pull 私有项目镜像,访客只能 pull。

对 CI/CD 这种机器身份,正确的做法是创建机器人账号。v2.3.4 的机器人账号可以精细控制权限到项目级别,比如给测试流水线创建一个只能推送到 test 项目、不能删除镜像的机器人账号。这样就算 Jenkins 机器被攻破,波及范围也只有一个项目,而不是整个仓库。这个习惯越早养成越好,因为后期镜像多了之后再回头补权限,工作量大到你根本不想动。

如果团队里多个项目都依赖同一个公共基础镜像,v2.3.4 的 Proxy Cache 功能很好用。在目标项目里配置一个代理缓存指向 Docker Hub,拉取 nginx 这种公共镜像时先走 Harbor,缓存到本地,后面再有机器拉取就直接内网命中,省外网流量,速度也快很多。

4.3 日常巡检和日志查看

Harbor 跑起来之后,日常巡检不用太复杂,我固定就做四件事。

第一,看容器状态。docker-compose ps 一眼扫过去,确认没有 Restarting 容器。第二,看磁盘水位。镜像仓库这玩意别的毛病没有,就是吃磁盘,用 df -h 盯住 data_volume 所在分区。第三,看关键容器日志,主要看 core、registry 和 nginx 这几个:

docker-compose logs -f harbor-core docker-compose logs -f nginx

日志里有大量 401 / 403 就要警惕,可能是凭证泄露或者配置错误。第四,定期执行垃圾回收。Harbor UI 里删除镜像后,底层存储不会立刻释放,需要在“垃圾回收”功能里执行清收。这个操作会暂时锁住仓库,建议放在低峰期,别在团队正忙着发版的时候点。

5. 备份、升级与回滚的实操经验

5.1 备份策略的侧重点

很多人的备份策略是拷贝一下 data_volume 目录就完事,这个做法不算错,但不够严谨。Harbor 持久化数据分两类:一类是镜像数据,即 registry 存储里的 blob;另一类是元数据,包括用户、项目、标签、复制规则等,这些都在 PostgreSQL 里。稳妥的备份建议分两层:

第一层,对数据卷做快照或者 rsync 同步,保证镜像数据有副本。第二层,单独对数据库做逻辑备份:

docker exec harbor-db pg_dump -U postgres -F c -b -f /tmp/registry_backup.dump harbor docker exec harbor-db pg_dump -U postgres -F c -b -f /tmp/postgres_backup.dump postgres

把生成的 dump 文件拷贝出服务器保存。数据库备份频率至少一天一次,镜像数据不用每天全量备份,用快照或 rsync 增量即可。

恢复流程一定要演练过才叫备份,很多人备份了三年从没恢复过,真出事时才发现备份文件已经损坏。恢复的大致路线是:部署一个同版本的新 Harbor,停掉容器,把数据卷和 dump 文件放回原位,再启动服务。别嫌麻烦,至少完整演练一次。

5.2 小版本升级要做什么

Harbor 从 2.3.3 升到 2.3.4 这种小版本,操作相对轻量,但两条铁律不能破:先备份数据库,再看官方 release notes 确认升级路径。升级前把整个服务停掉:

docker-compose down

然后备份 /data/harbor 下数据库相关目录,再把新版本安装包解压覆盖,重新执行 prepare 和 docker-compose up -d。数据卷保持不变,配置沿用原来的 harbor.yml,一般就能顺利起来。

大版本升级则要谨慎得多,比如从 2.2 升到 2.3。官方提供了 upgrade.sh 脚本,会自动做数据库迁移。跨版本升级不支持跳过,有些路径要求逐步升级。升完级之后进 UI 重点检查几个地方:项目列表是否完整、复制规则是否正常执行、镜像标签是否还在。一旦发现异常,立即回滚,回滚就是恢复备份的流程,所以备份永远放在升级第一步。

5.3 常见问题速查表

我把这次部署过程中实际遇到的高频问题整理一下:

现象原因处理
docker login 报 x509 unknown authority客户端未信任自签名 CA,或四个名称不一致分发 ca.crt 到 /etc/docker/certs.d/,检查 hostname 一致性
UI 无法访问,页面超时云安全组/防火墙未放行端口放行 443、80、4443
容器一直 Restarting端口占用或数据目录权限错误检查端口占用,修复目录属主
docker-compose 命令不存在只装了新插件未做兼容别名安装 docker-compose 二进制或创建 alias
Trivy 扫描总是 Pending离线环境漏洞库下载失败配置 trivy skip_update,或手动导入漏洞库
登录时好时坏,随机 401服务器时间漂移配置 NTP 时间同步
push 大镜像速度极慢磁盘 IO 瓶颈数据目录换 SSD,检查磁盘负载

表格整理完,我自己这次部署最大的体会是:Harbor 本身是个很稳的项目,绝大多数问题不是软件缺陷,而是部署环境和对概念的理解没到位。你把这套流程完整走一遍之后再看官方文档,会发现很多之前觉得模糊的段落突然就能读懂了。

最后分享一个小技巧:证书和域名映射最好在第一次部署前就固化下来,以后再添加客户端时,只需要把 ca.crt 和 hosts 记录分发过去就行。如果中途换域名、换证书,所有配置了旧地址的客户端都得跟着改,这个成本比你想的高得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 10:55:24

OpenCode 终端 AI 编码助手:从安装到自定义 Agent 实战指南

我刚开始接触 OpenCode 的时候,其实并没有抱太高期待。AI 编程助手我前前后后试过不少,编辑器的、独立客户端的、各种插件拼装出来的“全家桶”方案都有,但用下来的感觉就是,真正干活的时候,总得在好几个窗口之间来回切…

作者头像 李华
网站建设 2026/10/22 10:53:02

异构固定翼无人机集群协同搜索与自适应避障的Matlab实现

前阵子把一套异构固定翼无人机集群协同搜索方法在Matlab里完整跑通了。简单说,这套方法解决的是这么一个问题:有多架气动参数和传感器配置都不一样的固定翼无人机,在部分已知、部分未知的复杂环境里,要在某个区域内搜索目标&#…

作者头像 李华
网站建设 2026/10/22 10:53:01

以太网底层原理与真实排障实战指南

1. 这不是“背题库”,而是重建以太网认知的起点很多人看到“思科答案参考”四个字,第一反应是找标准答案、划重点、突击刷题——这恰恰踩进了最危险的认知陷阱。我带过十几期网络基础实训班,几乎每期都有学员考前狂背“以太网帧结构各字段长度…

作者头像 李华
网站建设 2026/10/22 10:52:59

白盒漏洞AI运营实战:从扫描报告到修复工单的自动化闭环

如果你所在的安全团队也背着“白盒漏洞”的KPI,那你大概率经历过这种场景:周三早上,静态扫描任务刚跑完,工单列表里一下子多出两三百条待处置的漏洞记录。每一条都要打开看代码上下文、判断触发路径、确认是否误报、想修复方案、再…

作者头像 李华
网站建设 2026/10/22 10:52:58

Muse设计复盘:AI时代的产品设计契约与任务熵值

1. 项目概述:这不是一次常规的产品复盘,而是一次设计思维的现场解剖“Meta 在 Muse 项目中做对了什么:一位产品设计师的复盘分析”——这个标题里藏着三个关键信号:Muse 是一个真实落地的内部孵化项目,它不是概念稿或P…

作者头像 李华
网站建设 2026/10/22 10:52:58

AI过度成功的经济系统性风险:传导路径与预警信号

一段时间以来,我反复在琢磨一个问题:人工智能的“成功”到底有没有边界?过去两年,我们习惯了各类AI能力刷榜式的突破,习惯了“AI又在某领域超过人类”的新闻头条,也习惯了资本疯狂涌入算力赛道。但作为一名…

作者头像 李华