从零搭建到生产落地:基于开源项目 Harbor 的企业级容器镜像仓库实战指南
企业里一旦开始大规模使用 Docker/Kubernetes,镜像仓库很快就会从“能用就行”的配套设施,变成“必须稳、必须安全、必须可审计”的基础平台。
很多团队一开始直接用 Docker Hub、阿里云/腾讯云镜像服务,或者临时搭个 registry:2。早期确实够用,但当研发团队多起来、环境多起来、合规要求上来之后,问题会很集中地爆发:
- 镜像来源不统一,谁都能推,谁也说不清哪个版本可上线
- 拉取速度不稳定,尤其是跨网络、跨地域时
- 没有扫描、签名、审计、项目级权限控制
- 生产环境镜像不可追溯,发布链路难以闭环
- 想做多集群/多机房同步时,原始 Registry 功能明显不够
这时候,Harbor 基本就是开源方案里的“标准答案”之一。
这篇文章我会按“从零到生产”的思路,带你完整做一遍:
- Harbor 是怎么工作的
- 如何在 Linux 上快速部署
- 如何推送/拉取镜像并验证
- 如何接入 HTTPS、项目权限、镜像复制、垃圾回收
- 生产环境有哪些常见坑,以及怎么排查
文章尽量不讲空话,重点放在能跑起来、能上线、能维护。
一、背景与问题
1.1 为什么不用裸 Registry
Docker 官方的 registry:2 很轻量,但企业里通常还缺这些关键能力:
- 角色与权限:项目级访问控制、只读/开发者/维护者角色
- 界面与审计:可视化管理、操作审计日志
- 镜像扫描:接入 Trivy 做漏洞分析
- 复制与同步:多仓库、多站点之间镜像复制
- 制品管理:不仅是 Docker 镜像,也包括 Helm Chart、OCI Artifact
- 垃圾回收:配合删除策略回收存储
- Webhook / Robot Account:自动化集成更方便
Harbor 本质上是在 OCI/Registry 基础上,加了一套企业所需的治理能力。
1.2 Harbor 适合什么场景
如果你符合下面任意几项,Harbor 基本值得上:
- 公司内部自建 Kubernetes / Docker 平台
- 需要私有镜像仓库,避免依赖公网
- 需要漏洞扫描、镜像签名、准入控制
- 多环境:开发、测试、预发、生产
- 多团队协作,需要项目隔离和权限管理
- 有异地容灾、边缘节点同步需求
1.3 这篇文章的部署边界
本文重点覆盖:
- 单机 Harbor 部署
- HTTPS 启用
- 项目、用户、Robot Account 使用
- 镜像推拉验证
- 复制与垃圾回收
- 生产实践建议
不展开:
- Harbor HA 高可用集群的完整搭建
- 外置 PostgreSQL/Redis 对接的超细节参数
- Kubernetes Operator 方式安装 Harbor
如果你是第一次上手,先把单机版跑顺,再谈高可用,效率最高。
二、前置知识与环境准备
2.1 你需要了解的基础
建议至少熟悉:
- Docker 基本命令:
build / tag / push / pull / login - Linux 基本运维:端口、防火墙、systemd、证书
- HTTPS 证书基础
- 容器镜像命名规则:
仓库地址/项目名/镜像名:标签
2.2 实验环境
以下环境足够完成本文演示:
- OS:Ubuntu 20.04 / 22.04 或 CentOS 7+
- CPU:2 Core+
- 内存:4 GB 起步,建议 8 GB
- 磁盘:50 GB+
- Docker:20.x+
- Docker Compose:Harbor 离线安装包已自带 compose 模板
- 域名:例如
harbor.example.com
我个人建议:测试环境可以先用 4C8G,生产别太抠,尤其开启扫描后,资源吃得比想象中快。
2.3 Harbor 关键组件概览
Harbor 不是单容器,它通常包含这些核心组件:
- nginx:入口代理
- core:Harbor API 与控制逻辑
- portal:Web UI
- registry:底层镜像分发服务
- jobservice:复制、扫描等异步任务
- db:PostgreSQL
- redis:缓存/队列
- trivy-adapter:漏洞扫描
下面这张图能帮助你先建立整体认知。
flowchart LR
U[开发者/CI] --> N[Nginx]
N --> P[Portal]
N --> C[Core API]
C --> R[Registry]
C --> J[JobService]
C --> D[(PostgreSQL)]
C --> X[(Redis)]
J --> T[Trivy Scanner]
J --> R
K[Kubernetes/生产节点] --> N
三、核心原理
Harbor 真正有价值的地方,不是“它能存镜像”,而是它把镜像从“文件”变成“可治理资产”。
3.1 镜像上传与拉取流程
当你执行 docker push harbor.example.com/library/nginx:1.25 时,大致发生这些事:
- Docker Client 与 Harbor 建立 HTTPS 连接
- Harbor 校验账号、项目权限
- 镂空层(layers)和 manifest 被写入 Registry 后端存储
- 元数据被写入 PostgreSQL
- 异步任务可能触发扫描、复制、Webhook 等动作
拉取时也类似,只不过方向相反,Harbor 先鉴权,再由 Registry 返回镜像分层内容。
sequenceDiagram
participant D as Docker Client
participant H as Harbor Nginx/Core
participant R as Registry
participant DB as PostgreSQL
participant J as JobService/Scanner
D->>H: docker login / push
H->>DB: 校验用户、项目、权限
H->>R: 写入 manifest 和 layer
R-->>H: 写入成功
H->>DB: 记录镜像元数据
H->>J: 触发扫描/复制任务
H-->>D: push 完成
3.2 Harbor 的企业能力是怎么落地的
项目隔离
Harbor 通过 Project 作为资源边界。不同团队可以拥有不同项目:
base-images:基础镜像app-team-a:A 团队业务镜像prod-release:生产发布镜像
RBAC 权限模型
常见角色包括:
- Project Admin
- Maintainer
- Developer
- Guest
- Limited Guest
这意味着你可以做到:
- 开发者能推测试镜像
- 运维只允许在生产项目中拉取
- CI 用 Robot Account 自动上传,不给人手工账号
元数据与制品治理
Harbor 记录的不只是 blob 文件,还有:
- 标签(tag)
- digest
- push 时间
- 扫描结果
- 复制状态
- 审计记录
这些信息对于“上线版本追溯”非常关键。
3.3 为什么生产一定要用 HTTPS
如果不用 HTTPS,最直接的问题不是“浏览器报不安全”,而是:
- Docker 默认会拒绝或限制不安全仓库
- 密码、token 可能明文传输
- 集群节点拉取镜像时不可控
- 后续接入签名、Webhook、OIDC 都会变麻烦
一句话:生产 Harbor 没有 HTTPS,基本等于没上正轨。
四、环境准备与安装部署
这一节我们直接开始实操。
4.1 安装 Docker
以 Ubuntu 为例:
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable docker
sudo systemctl start docker
docker version
4.2 准备域名与证书
假设 Harbor 域名是:
harbor.example.com
如果你有正式证书,直接使用即可。测试环境也可以自签。
生成自签证书示例
mkdir -p /data/cert
cd /data/cert
openssl req -newkey rsa:4096 -nodes -sha256 -keyout harbor.example.com.key \
-x509 -days 365 -out harbor.example.com.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Example/OU=IT/CN=harbor.example.com"
如果 Docker 客户端也要信任这个自签证书,需要把证书放到客户端:
sudo mkdir -p /etc/docker/certs.d/harbor.example.com
sudo cp harbor.example.com.crt /etc/docker/certs.d/harbor.example.com/ca.crt
sudo systemctl restart docker
我踩过的一个坑:证书 CN 和你实际访问的域名不一致时,浏览器可能还能点过去,但 Docker 会非常坚决地拒绝。
4.3 下载 Harbor 离线安装包
到 Harbor 官方 Release 页面下载对应版本的离线包。这里演示通用步骤:
cd /opt
tar zxvf harbor-offline-installer-v2.x.x.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
4.4 编辑 harbor.yml
这是最关键的配置文件。一个可工作的示例如下:
hostname: harbor.example.com
http:
port: 80
https:
port: 443
certificate: /data/cert/harbor.example.com.crt
private_key: /data/cert/harbor.example.com.key
harbor_admin_password: Harbor12345
database:
password: root123
data_volume: /data/harbor
trivy:
ignore_unfixed: false
skip_update: false
jobservice:
max_job_workers: 10
notification:
webhook_job_max_retry: 3
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
几个重点参数解释一下:
hostname:必须与实际域名一致https.certificate/private_key:证书路径harbor_admin_password:管理员密码data_volume:镜像和数据落盘目录jobservice.max_job_workers:异步任务并发数,别乱开太大
4.5 执行安装
sudo ./install.sh
如果想启用某些扩展功能,也可以带参数,例如:
sudo ./install.sh --with-trivy
安装完成后,查看容器:
docker ps
你应该能看到类似这些容器:
- harbor-core
- harbor-db
- harbor-jobservice
- harbor-portal
- harbor-registry
- nginx
- redis
- trivy-adapter
五、逐步验证清单
安装完不要急着宣布成功。建议按下面顺序验证。
5.1 验证 Web 登录
浏览器访问:
https://harbor.example.com
默认管理员用户:
admin
密码就是 harbor.yml 里配置的 harbor_admin_password。
5.2 创建项目
在 UI 中创建一个项目,例如:
- 项目名:
demo - 访问级别:Private
企业里默认建议 Private,公开项目要非常克制。
5.3 Docker 登录 Harbor
docker login harbor.example.com
输入账号密码后,若返回 Login Succeeded,说明认证链路正常。
5.4 准备一个测试镜像并上传
先拉一个官方镜像:
docker pull nginx:1.25
重新打标签:
docker tag nginx:1.25 harbor.example.com/demo/nginx:1.25
推送:
docker push harbor.example.com/demo/nginx:1.25
预期结果
在 Harbor UI 的 demo 项目里应该能看到该镜像。
5.5 另一台机器拉取验证
在另一台已信任证书的机器上执行:
docker login harbor.example.com
docker pull harbor.example.com/demo/nginx:1.25
如果能拉下来,说明 Harbor 作为私有镜像仓库已经可用。
六、实战代码:可运行的完整示例
这一节我们做一个更接近真实工作流的例子:构建应用镜像,推送到 Harbor,再用脚本自动检查结果。
6.1 示例应用
新建目录:
mkdir -p ~/harbor-demo-app
cd ~/harbor-demo-app
创建 app.py:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello from Harbor demo!\n"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
创建 requirements.txt:
flask==2.3.3
创建 Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8080
CMD ["python", "app.py"]
6.2 构建并推送镜像
cd ~/harbor-demo-app
docker build -t harbor.example.com/demo/flask-app:v1 .
docker push harbor.example.com/demo/flask-app:v1
6.3 本地运行验证
docker run --rm -p 8080:8080 harbor.example.com/demo/flask-app:v1
访问:
http://127.0.0.1:8080
应返回:
Hello from Harbor demo!
6.4 用脚本自动检查镜像是否存在
创建 check_image.sh:
#!/usr/bin/env bash
set -euo pipefail
HARBOR_HOST="https://harbor.example.com"
PROJECT="demo"
REPOSITORY="flask-app"
TAG="v1"
USERNAME="${HARBOR_USERNAME:-admin}"
PASSWORD="${HARBOR_PASSWORD:-Harbor12345}"
echo "[1] 获取 Harbor API Token..."
AUTH=$(printf "%s:%s" "$USERNAME" "$PASSWORD" | base64 | tr -d '\n')
echo "[2] 查询制品信息..."
curl -sS -H "Authorization: Basic ${AUTH}" \
"${HARBOR_HOST}/api/v2.0/projects/${PROJECT}/repositories/${REPOSITORY}/artifacts/${TAG}" \
| python3 -m json.tool
赋权并执行:
chmod +x check_image.sh
./check_image.sh
如果返回 JSON,说明 Harbor API 可正常查询镜像制品信息。
这里用的是最简单的 Basic Auth 演示。真实生产里更推荐用 Robot Account 或更细粒度的自动化凭证。
6.5 在 Kubernetes 中使用 Harbor 镜像
如果你的 K8s 集群要从 Harbor 拉私有镜像,先创建镜像拉取凭据:
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.example.com \
--docker-username=admin \
--docker-password='Harbor12345' \
--docker-email='admin@example.com'
部署示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
spec:
replicas: 1
selector:
matchLabels:
app: flask-app
template:
metadata:
labels:
app: flask-app
spec:
imagePullSecrets:
- name: harbor-secret
containers:
- name: flask-app
image: harbor.example.com/demo/flask-app:v1
ports:
- containerPort: 8080
应用:
kubectl apply -f deployment.yaml
七、Harbor 生产落地建议
很多团队装完 Harbor 就结束了,其实真正麻烦的是“怎么管”。
7.1 项目规划建议
我比较推荐按“团队 + 环境”或者“镜像类型”来划分项目,而不是一锅炖。
例如:
base:基础镜像middleware:公共中间件镜像team-a-devteam-a-prodteam-b-devteam-b-prod
这样做的好处是:
- 权限边界清晰
- 复制策略更容易做
- 清理策略更可控
- 审计定位更方便
7.2 标签策略建议
不要把 latest 当发布标准。推荐至少这样做:
- 开发构建:
build-20240201-001 - 提交关联:
git-<commit_sha> - 发布版本:
v1.3.2
一个镜像可以同时打多个 tag,但上线和回滚最好依赖不可变标识,例如 digest 或严格版本号。
7.3 Robot Account 替代人工账号
CI/CD 推镜像时,不建议直接使用管理员账号。
推荐流程:
- 为项目创建 Robot Account
- 授予最小权限
- 在 CI 平台保存凭据
- 使用该账号执行
docker login
这样即便凭据泄漏,影响范围也较小。
7.4 镜像复制策略
如果你有多机房、多区域,复制功能很有用。
常见场景:
- 总部 Harbor 向边缘 Harbor 同步基础镜像
- 测试仓库审核后复制到生产仓库
- 私有 Harbor 从上游镜像源做代理缓存/同步
flowchart TD
A[开发构建镜像] --> B[Dev Harbor 项目]
B --> C[漏洞扫描]
C --> D{是否通过}
D -- 否 --> E[禁止进入生产]
D -- 是 --> F[复制到 Prod Harbor 项目]
F --> G[Kubernetes 生产集群拉取]
八、常见坑与排查
这一节很重要。Harbor 不是那种“装完永远没问题”的组件,实际运维里经常会遇到下面这些情况。
8.1 Docker 登录失败:x509 证书错误
现象
docker login harbor.example.com
报错类似:
x509: certificate signed by unknown authority
排查思路
- 检查证书是否为受信 CA 签发
- 自签证书是否已放到
/etc/docker/certs.d/<域名>/ca.crt - 域名是否与证书 CN/SAN 一致
- 客户端 Docker 是否已重启
解决方法
sudo mkdir -p /etc/docker/certs.d/harbor.example.com
sudo cp harbor.example.com.crt /etc/docker/certs.d/harbor.example.com/ca.crt
sudo systemctl restart docker
8.2 push 失败:unauthorized
现象
unauthorized: unauthorized to access repository
常见原因
- 推送到不存在的项目
- 用户只有拉取权限,没有推送权限
- tag 路径拼错了
例如,正确格式应该是:
harbor.example.com/项目名/镜像名:标签
不是:
harbor.example.com/镜像名:标签
快速检查
docker image ls
docker logout harbor.example.com
docker login harbor.example.com
再确认 UI 中项目是否存在、角色是否正确。
8.3 磁盘越来越大,删了镜像也不释放
这是 Harbor 的经典坑之一。
原因
Harbor 删除 tag 或 artifact 后,底层 blob 不一定立刻删除,必须执行 垃圾回收(GC)。
处理建议
在 UI 或计划任务中执行垃圾回收。生产上建议:
- 低峰期运行
- 配合镜像保留策略
- 先确认没有运行中任务依赖相关 blob
我第一次遇到这类问题时,以为是“删除不生效”,后来发现其实是对象存储/本地存储里的层文件还没 GC。
8.4 扫描结果一直不出
排查顺序
trivy-adapter容器是否正常- Harbor 是否能访问漏洞数据库更新源
- 离线环境是否需要内部代理或离线 DB
jobservice是否堆积任务
查看日志:
docker logs trivy-adapter
docker logs harbor-jobservice
docker logs harbor-core
8.5 页面能打开,但 push/pull 超时
这类问题很常见,尤其在反向代理、负载均衡或大镜像场景下。
检查项
- nginx / LB 超时时间
- 上传大小限制
- 磁盘 IO 是否打满
- DNS 解析是否漂移
- MTU 问题
- TLS 终止位置是否正确
基础排查命令
curl -vk https://harbor.example.com/v2/
docker info
df -h
free -m
docker logs nginx
九、安全最佳实践
Harbor 属于供应链的关键节点,安全上不能只停留在“改个管理员密码”。
9.1 最小权限原则
- 普通研发不要给管理员权限
- CI 使用 Robot Account
- 生产项目尽量只允许少数人 push
- 用项目角色做边界,不要所有人共享一个账号
9.2 强制 HTTPS
- 禁止明文 HTTP 暴露到生产网络
- 使用可信 CA 证书
- 定期更新证书,避免过期导致节点拉取失败
9.3 开启漏洞扫描,但理解边界
Trivy 很有用,但不要误解为“扫过就安全”:
- 它主要发现已知漏洞
- 对业务逻辑风险无能为力
- 对基础镜像层效果更明显
- 需要结合版本治理、修复策略和准入规则
建议:
- 只允许通过扫描门槛的镜像进入生产
- 对高危漏洞设置阻断
- 定期重扫历史镜像
9.4 审计与留痕
- 开启操作审计
- 发布流程记录镜像 digest
- 保留关键仓库访问日志
- 将 Harbor 审计日志接入集中日志平台
9.5 镜像不可变策略
对于生产项目,建议开启 Tag Immutability,避免有人把 v1.0.0 重新推成别的内容。
这件事看起来小,实际上对回滚和事故复盘非常关键。
十、性能最佳实践
Harbor 在生产里是否好用,性能配置影响很大。
10.1 存储优先级很高
镜像仓库本质上是 I/O 密集型服务,尤其是:
- 大量 push/pull
- 并发构建
- 扫描与复制同时进行
建议:
- 数据目录放 SSD
- 避免系统盘和 Harbor 数据盘混用
- 定期监控磁盘延迟、容量和 inode
10.2 合理设置 jobservice 并发
jobservice.max_job_workers 不是越大越好。
太小:
- 扫描、复制排队严重
太大:
- CPU、内存、数据库连接压力增大
中小团队可先从 10 左右开始,根据任务堆积情况微调。
10.3 生产环境建议外置数据库与 Redis
单机版自带 PostgreSQL 和 Redis,适合快速部署,但如果你进入正式生产,建议逐步考虑:
- 外置 PostgreSQL
- 外置 Redis
- 共享/对象存储后端
- 高可用架构
这样更便于备份、监控和容量扩展。
10.4 做好镜像保留与清理
如果没有保留策略,Harbor 很快会被“历史流水镜像”堆满。
建议:
- Dev 项目只保留最近 N 个 tag
- 按时间自动清理旧镜像
- 生产项目保留正式版本和回滚窗口版本
- 定期 GC
stateDiagram-v2
[*] --> 构建镜像
构建镜像 --> 推送到开发项目
推送到开发项目 --> 漏洞扫描
漏洞扫描 --> 审核通过
漏洞扫描 --> 审核拒绝
审核通过 --> 复制到生产项目
复制到生产项目 --> 部署上线
部署上线 --> 保留策略评估
保留策略评估 --> 垃圾回收
垃圾回收 --> [*]
十一、一个可执行的生产落地清单
如果你准备把 Harbor 从测试环境推进到生产,我建议至少完成下面这份清单。
11.1 基础可用性
- 使用域名访问 Harbor
- HTTPS 证书有效且客户端可信
- push/pull 在多台机器验证通过
- Harbor 服务重启后可自动恢复
- 数据目录独立挂载
11.2 权限治理
- 项目按团队/环境划分
- 管理员账号不参与日常 CI
- CI 使用 Robot Account
- 生产项目设置更严格权限
- 启用标签不可变规则
11.3 安全与合规
- 漏洞扫描已启用
- 审计日志可查询
- 镜像来源有规范
- 发布记录包含 tag 与 digest
- 证书、密码、凭据纳入轮换机制
11.4 运维保障
- 监控 CPU/内存/磁盘/容器状态
- 备份 Harbor 配置和数据库
- 制定 GC 执行窗口
- 复制策略经过验证
- 故障恢复流程有演练
十二、总结
Harbor 之所以在企业里广泛使用,不是因为它“会存镜像”,而是因为它把容器镜像仓库做成了一个可治理、可审计、可自动化接入的平台。
如果你是第一次搭 Harbor,我建议按这个顺序推进:
- 先单机部署跑通 HTTPS + push/pull
- 再做好项目划分、权限和 Robot Account
- 然后启用扫描、保留策略、垃圾回收
- 最后再考虑复制、高可用和外置存储/数据库
最容易踩坑的地方,通常不是安装本身,而是这些细节:
- 证书不规范
- 项目和权限没规划
- 只删 tag 不做 GC
- CI 直接用管理员账号
- 把
latest当发布依据
如果你的团队规模还不大,Harbor 单机版已经足够起步;但只要进入多团队、多环境、持续交付阶段,就应该尽快把它按“生产基础设施”的标准来建设,而不是把它当一个临时上传镜像的地方。
一句落地建议收尾:先把 Harbor 当成容器供应链的入口,再把权限、扫描、复制、清理这些治理能力逐步补齐,你的镜像仓库才真正算“企业级”。