第 16/60 天
引言
在上一篇文章中,我们用 kaniko 在 Tekton 里构建出了容器镜像。但镜像构建出来之后放哪里?这就轮到我们的制品仓库 Harbor 登场了。作为三件套里的”存储中枢”,Harbor 承上启下——上游接收 Tekton 推送的镜像,下游被 Argo CD 拉取部署。
很多团队部署 Harbor 时图省事直接用 HTTP,结果在接入 Tekton 和 Argo CD 时反复踩坑:Docker/containerd 拒绝非 HTTPS 仓库、凭证明文传输、自签名证书没被信任导致 x509: certificate signed by unknown authority 报错满天飞。本文带你从零完成一个生产级、HTTPS、含密码学组件正确配置的 Harbor 部署,为后续第 29、30 天的三件套集成扫清障碍。
本文覆盖范围:Harbor 的组件架构、自签名 CA 与证书签发、harbor.yml 完整配置、在线/离线安装、HTTPS 验证与 Docker 信任配置、以及密码学相关的密钥与凭证管理。
核心概念
1. Harbor 的组件架构
Harbor 不是单体,而是一组容器服务的集合。理解它的组件,才知道 harbor.yml 里每一项配置对应什么:
| 组件 | 作用 | 说明 |
|---|---|---|
| nginx | 反向代理/入口 | 统一对外提供 HTTPS,转发到各组件 |
| core | 核心 API 服务 | 处理镜像/制品元数据、RBAC、复制任务 |
| portal | Web 管理界面 | 提供给运维/开发的可视化控制台 |
| registry | 镜像存储 | 底层就是开源的 Docker Distribution |
| registryctl | 注册表控制器 | 配合垃圾回收、配额管理 |
| jobservice | 异步任务服务 | 复制、扫描、GC 等后台任务的执行器 |
| database | 元数据数据库 | 存储项目、用户、权限等(默认 PostgreSQL) |
| redis | 缓存/队列 | 会话、job 队列、扫描缓存 |
| trivy-adapter | 漏洞扫描 | 对接 Trivy 做镜像安全扫描 |
密码学组件:Harbor 内部依赖一组密钥——
secretkey(用于加密复制任务的推送密钥)、_secret主密钥(用于加密数据库中的敏感字段)、HTTPS 证书密钥。这些在安装时需要正确落盘,否则重启后会出现”凭证解密失败”或”复制到远端仓库时凭据错误”的诡异问题。
2. 为什么必须用 HTTPS
- Docker/containerd 默认拒绝 HTTP 仓库(除非显式配置
insecure-registries,这会关闭 TLS 校验,不安全)。 - 凭证安全:robot account、push 密码在 HTTP 下明文传输,生产环境不可接受。
- Kubernetes/containerd 拉取:Kubelet 拉取镜像时会对 registry 做 TLS 校验,未配置好证书会直接
x509报错。 - 合规:金融/医疗等行业的审计要求传输加密。
3. 自签名证书的三层信任模型
| 层级 | 说明 |
|---|---|
| CA 根证书 | 自建私有 CA 的根证书,是信任链的起点 |
| 服务器证书 | 为 harbor.stellardata.top 签发的证书,由 CA 签发 |
| 客户端信任 | Docker daemon、containerd、浏览器都需要导入 CA 根证书才信任服务器证书 |
生产环境如果有内网 PKI 或公共 CA,直接用即可;没有的话,自建私有 CA 是最常见做法。自签名 ≠ 自建 CA:直接用 openssl req -x509 生成一个”自签名”证书虽快,但每个客户端都要单独信任,且不便签发多张证书;自建 CA 只需信任一次根证书,后续签发任意域名证书都有效。
实战步骤
步骤 1:准备环境与依赖
# 检查 Docker Compose(Harbor 官方安装器依赖 docker-compose)
docker compose version
# 或旧版:docker-compose --version
# 下载 Harbor 离线安装包(以 v2.11 为例,实际以官方最新为准)
cd /opt
wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-offline-installer-v2.11.1.tgz
tar xzvf harbor-offline-installer-v2.11.1.tgz
cd harbor
# 生成默认配置模板
cp harbor.yml.tmpl harbor.yml
步骤 2:自建私有 CA 并签发服务器证书
这一步是密码学组件的基础。先创建 CA 根证书,再用它签发 Harbor 服务器证书:
# 1) 创建私有 CA 根证书
mkdir -p /opt/harbor/certs && cd /opt/harbor/certs
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650
-subj "/CN=Harbor Private CA/O=StellarTop/C=CN"
-out ca.crt
# 2) 生成 Harbor 服务器的私钥
openssl genrsa -out harbor.key 2048
# 3) 创建证书签名请求(CSR)配置文件——这里指定 SAN 域名
cat > harbor.csr.cnf << 'EOF'
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = harbor.stellardata.top
O = StellarTop
C = CN
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = harbor.stellardata.top
DNS.2 = registry.stellardata.top
IP.1 = 192.168.10.10
EOF
# 4) 生成 CSR
openssl req -new -key harbor.key -out harbor.csr -config harbor.csr.cnf
# 5) 用 CA 签发服务器证书(含 SAN,有效期 1 年)
openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial
-out harbor.crt -days 365 -sha256 -extensions v3_req -extfile harbor.csr.cnf
# 6) 校验证书
openssl x509 -in harbor.crt -noout -text | grep -A1 "Subject Alternative Name"
关键点:
harbor.crt是给 Harbor nginx 用的服务器证书,ca.crt是分发给所有客户端的信任锚。二者不能混淆。
步骤 3:编写 harbor.yml 配置
# /opt/harbor/harbor.yml
hostname: harbor.stellardata.top
# HTTPS 配置——生产环境必开
http:
port: 80
https:
port: 443
certificate: /opt/harbor/certs/harbor.crt # 服务器证书
private_key: /opt/harbor/certs/harbor.key # 服务器私钥
# 密码学组件:Harbor 用于加密敏感字段的密钥(持久化在文件系统)
# secretkey 默认在 data/secretkey,_secret 在环境变量 HARBOR_ADMIN_PASSWORD
# 生产建议外部化,见下文"密码学组件"小节
# 管理员初始密码(首次登录后请立即修改)
harbor_admin_password: "ChangeMe_Strong_2026!"
database:
password: "DB_Strong_Password_2026!" # PostgreSQL 的 postgres 用户密码
max_idle_conns: 100
max_open_conns: 900
data_volume: /data/harbor
trivy:
ignore_unfixed: true
skip_update: false
offline_scan: false
severity: "HIGH,CRITICAL"
# 核心 API 与 Portal 的鉴权密钥(密码学组件核心)
# _secret:用于加密 robot account 密码、复制任务远端凭据等
# 首次安装时由 prepare 脚本自动生成到 /data/harbor/secret
secretkey_path: /data/harbor/secret
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
步骤 4:运行 prepare 与安装
# 生成 Docker Compose 配置并初始化密码学密钥
sudo ./prepare
# 安装并启动 Harbor(离线包自带镜像)
sudo ./install.sh --with-trivy
# 验证所有组件健康
docker ps | grep harbor
# 期望看到:nginx、core、portal、registry、registryctl、jobservice、database、redis、trivy-adapter
步骤 5:验证 HTTPS 并让 Docker 信任 CA
# 1) 检查 HTTPS 端口与证书链
curl -k https://harbor.stellardata.top/api/v2.0/health
# {"status":"healthy",...}
# 2) 用完整 CA 校验服务器证书(不加 -k,验证信任链)
curl --cacert /opt/harbor/certs/ca.crt https://harbor.stellardata.top/api/v2.0/health
# 3) 让本机 Docker daemon 信任私有 CA
mkdir -p /etc/docker/certs.d/harbor.stellardata.top
cp /opt/harbor/certs/ca.crt /etc/docker/certs.d/harbor.stellardata.top/ca.crt
systemctl restart docker
# 4) 验证 docker 可登录(不报 x509)
echo "AdminPass123" | docker login harbor.stellardata.top -u admin --password-stdin
# Login Succeeded
步骤 6:让 Kubernetes 节点信任 CA(为 Argo CD/containerd 准备)
Kubelet 用 containerd 拉取镜像,需要把 CA 放到每个节点:
# 在每个 K8s 节点执行
for node in node01 node02 node03; do
ssh $node "mkdir -p /etc/containerd/certs.d/harbor.stellardata.top &&
scp /opt/harbor/certs/ca.crt $node:/etc/containerd/certs.d/harbor.stellardata.top/ca.crt"
done
# 或配置 containerd 全局信任
# /etc/containerd/config.toml
# [plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.stellardata.top".tls]
# ca_file = "/etc/containerd/certs.d/harbor.stellardata.top/ca.crt"
systemctl restart containerd
密码学组件:密钥管理与外部化
Harbor 的密码学体系依赖三个持久化密钥,务必理解并做好备份:
#!/usr/bin/env python3
"""检查 Harbor 密码学组件落盘状态(生产巡检脚本片段)"""
import os, json
data_volume = "/data/harbor"
required = {
"secret": "主密钥 _secret(加密 robot 与复制凭据)",
"secretkey": "复制任务密钥 secretkey",
"database": "数据库数据目录",
}
for name, desc in required.items():
path = os.path.join(data_volume, name)
exists = os.path.exists(path)
size = os.path.getsize(path) if os.path.isfile(path) else None
print(f"[{'OK' if exists else 'MISSING'}] {name:10s} {desc:30s} {size}")
# 生产建议:
# 1. data_volume 使用外部存储(NFS/云盘)并定期备份
# 2. 使用外部 PostgreSQL / Redis 提升可用性(见第 35 天高可用篇)
# 3. 密钥文件权限收紧为 600,仅 harbor 用户可读
# 4. 变更 _secret 后需重新 prepare,否则旧 robot account 凭据解密失败
常见问题
Q1:为什么 docker login 报 x509: certificate signed by unknown authority?
A:Docker daemon 没有信任你的 CA 根证书。把 ca.crt 放到 /etc/docker/certs.d/<hostname>/ca.crt 并重启 docker,或把 CA 加入系统信任库(cp ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates)。
Q2:安装后用 HTTP 也能访问,能不能就先用 HTTP?
A:能,但不推荐。Docker/containerd/Kubernetes 默认都要求 TLS。走 insecure-registries 会关闭校验,且 robot account 凭据明文传输。生产环境请务必配置 HTTPS。
Q3:修改了 harbor.yml 的证书路径,重启后报证书加载失败?
A:改 harbor.yml 后必须重新运行 sudo ./prepare 再 docker compose down && docker compose up -d。prepare 会重新生成 nginx 配置和密码学密钥初始化,只重启容器不会生效。
Q4:重启 Harbor 后 robot account 推送镜像报”凭据无效”?
A:多半是 _secret 主密钥丢失或被覆盖。Harbor 用它加密数据库中的 robot 密码。务必确保 /data/harbor/secret 持久化;若 data_volume 是临时目录或重建了容器卷,旧 robot 凭据将无法解密,需要重建 robot account。
Q5:./install.sh 时报数据库连接失败?
A:检查 database.password 与已存在的数据卷是否一致。若 data_volume 已初始化过,harbor.yml 里的数据库密码必须与初次安装时一致,否则 PostgreSQL 起不来。首次就应把密码记入密码管理器。
总结
本文完成了生产级 Harbor 部署的关键一步,核心要点:
- Harbor 是多组件容器栈:nginx / core / registry / jobservice / database / redis / trivy,
harbor.yml的每一项配置都对应具体组件。 - HTTPS 是生产底线:自建私有 CA → 签发带 SAN 的服务器证书 → 分发 CA 根证书给 Docker、containerd、浏览器,构建完整信任链。
- 密码学组件要持久化:
_secret、secretkey、数据库密码是 Harbor 的安全根基,data_volume 必须持久化并定期备份。 - 改配置必须重跑 prepare:
harbor.yml→./prepare→ 重启容器,顺序不能错。 - 为下游铺路:让 K8s 节点 containerd 信任 CA,是第 30 天 Argo CD 从 Harbor 拉取镜像的前置条件。
下一篇文章我们将深入 Harbor 的项目隔离与权限管理,把项目类型、访问级别、成员角色吃透,为多团队协作打基础。
📖 系列目录
- 第 15 天:使用 kaniko 在 Tekton 中构建容器镜像
- 第 16 天:Harbor 安装与配置——HTTPS、自签名证书、密码学组件 ← 本篇
- 第 17 天:Harbor 项目隔离与权限管理 🔜
下期预告: 第 17 天我们将讲解 Harbor 的项目隔离与权限管理,覆盖项目类型、访问级别、成员角色,帮助你在多团队场景下安全地共享镜像仓库。















暂无评论内容