跳转到内容
123xiao | 无名键客

《从零搭建到生产落地:基于开源项目 Harbor 的企业级容器镜像仓库实战指南》

字数: 0 阅读时长: 1 分钟

从零搭建到生产落地:基于开源项目 Harbor 的企业级容器镜像仓库实战指南

企业里一旦开始大规模使用 Docker/Kubernetes,镜像仓库很快就会从“能用就行”的配套设施,变成“必须稳、必须安全、必须可审计”的基础平台。

很多团队一开始直接用 Docker Hub、阿里云/腾讯云镜像服务,或者临时搭个 registry:2。早期确实够用,但当研发团队多起来、环境多起来、合规要求上来之后,问题会很集中地爆发:

  • 镜像来源不统一,谁都能推,谁也说不清哪个版本可上线
  • 拉取速度不稳定,尤其是跨网络、跨地域时
  • 没有扫描、签名、审计、项目级权限控制
  • 生产环境镜像不可追溯,发布链路难以闭环
  • 想做多集群/多机房同步时,原始 Registry 功能明显不够

这时候,Harbor 基本就是开源方案里的“标准答案”之一。

这篇文章我会按“从零到生产”的思路,带你完整做一遍:

  1. Harbor 是怎么工作的
  2. 如何在 Linux 上快速部署
  3. 如何推送/拉取镜像并验证
  4. 如何接入 HTTPS、项目权限、镜像复制、垃圾回收
  5. 生产环境有哪些常见坑,以及怎么排查

文章尽量不讲空话,重点放在能跑起来、能上线、能维护


一、背景与问题

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 时,大致发生这些事:

  1. Docker Client 与 Harbor 建立 HTTPS 连接
  2. Harbor 校验账号、项目权限
  3. 镂空层(layers)和 manifest 被写入 Registry 后端存储
  4. 元数据被写入 PostgreSQL
  5. 异步任务可能触发扫描、复制、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='[email protected]'

部署示例:

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-dev
  • team-a-prod
  • team-b-dev
  • team-b-prod

这样做的好处是:

  • 权限边界清晰
  • 复制策略更容易做
  • 清理策略更可控
  • 审计定位更方便

7.2 标签策略建议

不要把 latest 当发布标准。推荐至少这样做:

  • 开发构建:build-20240201-001
  • 提交关联:git-<commit_sha>
  • 发布版本:v1.3.2

一个镜像可以同时打多个 tag,但上线和回滚最好依赖不可变标识,例如 digest 或严格版本号。

7.3 Robot Account 替代人工账号

CI/CD 推镜像时,不建议直接使用管理员账号。

推荐流程:

  1. 为项目创建 Robot Account
  2. 授予最小权限
  3. 在 CI 平台保存凭据
  4. 使用该账号执行 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

排查思路

  1. 检查证书是否为受信 CA 签发
  2. 自签证书是否已放到 /etc/docker/certs.d/<域名>/ca.crt
  3. 域名是否与证书 CN/SAN 一致
  4. 客户端 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 扫描结果一直不出

排查顺序

  1. trivy-adapter 容器是否正常
  2. Harbor 是否能访问漏洞数据库更新源
  3. 离线环境是否需要内部代理或离线 DB
  4. 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,我建议按这个顺序推进:

  1. 先单机部署跑通 HTTPS + push/pull
  2. 再做好项目划分、权限和 Robot Account
  3. 然后启用扫描、保留策略、垃圾回收
  4. 最后再考虑复制、高可用和外置存储/数据库

最容易踩坑的地方,通常不是安装本身,而是这些细节:

  • 证书不规范
  • 项目和权限没规划
  • 只删 tag 不做 GC
  • CI 直接用管理员账号
  • latest 当发布依据

如果你的团队规模还不大,Harbor 单机版已经足够起步;但只要进入多团队、多环境、持续交付阶段,就应该尽快把它按“生产基础设施”的标准来建设,而不是把它当一个临时上传镜像的地方。

一句落地建议收尾:先把 Harbor 当成容器供应链的入口,再把权限、扫描、复制、清理这些治理能力逐步补齐,你的镜像仓库才真正算“企业级”。


分享到:

上一篇
《从源码到部署:用开源可观测性项目 OpenTelemetry 构建中型微服务链路追踪实践》
下一篇
《安卓逆向实战:中级开发者如何用 Frida 定位并绕过常见 APK 签名校验逻辑》