Harbor生产级部署实战:PostgreSQL+Redis+MinIO全解耦架构详解
环境介绍:
采用解耦架构 :Harbor 不使用自身内置 PostgreSQL、Redis、本地存储,全部依赖外部独立组件,做到元数据、缓存、镜像存储彻底分离,符合生产高可用架构标准。
各组件部署位置:
1.K8s 集群内部
- 部署 PostgreSQL:存放 Harbor 所有元数据(用户、项目、镜像信息、配置等)
- 部署 Redis:负责 Harbor 会话缓存、接口缓存、任务队列缓存
- 访问方式:通过 K8s NodePort 端口对外暴露,供外网 Harbor 连接
2.独立对象存储服务器
- 单独部署 MinIO:专门存放 Harbor 镜像二进制层、Blob 文件
- 端口:9000 为 API 端口、9001 为 Web 管理控制台
- 自建独立桶
harbor专供镜像仓库使用3.独立 Harbor 服务器(Docker 部署)
- 单独一台机器用 Docker安装 Harbor
- 配置 HTTPS 域名
- 完全剥离内置 PG、Redis,全量对接 K8s 集群中间件
- 镜像存储后端对接外置 MinIO,不落地本地磁盘
一、K8s 部署 PostgreSQL
1.创建命名空间
bash
kubectl create ns harbor
2.postgres.yaml
yaml
apiVersion: v1
kind: Service
metadata:
name: pg-harbor # Service 的名称
namespace: harbor # 指定 Service 所在的命名空间
labels:
app: pg-harbor # 为 Service 添加标签
spec:
ports:
- port: 5432 # Service 暴露的端口
name: pg # 端口的名称
clusterIP: None # 设置为 None 使其成为无头 Service
selector:
app: pg-harbor # 选择器,将流量导向带有 app=pg-harbor 标签的 Pod
---
apiVersion: v1
kind: Service
metadata:
name: pg-harbor-nodeport # Service 的名称
namespace: harbor # 指定 Service 所在的命名空间
spec:
type: NodePort # 指定 Service 类型为 NodePort
ports:
- port: 5432 # Service 在集群内部的端口
nodePort: 30532 # 在节点上开放的固定端口,外部通过 节点IP:30532 访问
selector:
app: pg-harbor # 选择器,同样指向 app=pg-harbor 的 Pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: pg-harbor # StatefulSet 的名称
namespace: harbor # 指定 StatefulSet 所在的命名空间
spec:
serviceName: pg-harbor # 关联的无头 Service 名称,用于 Pod 的网络身份
replicas: 1 # 期望运行的 Pod 副本数量
selector:
matchLabels:
app: pg-harbor # 用于查找和管理 Pod 的选择器
template:
metadata:
labels:
app: pg-harbor # Pod 的标签,必须与上面的 selector 匹配
spec:
containers:
- name: postgres # 容器的名称
image: postgres:14-alpine # 使用的容器镜像及版本
ports:
- containerPort: 5432 # 容器内部监听的端口
env: # 定义容器的环境变量
- name: POSTGRES_USER
value: "harbor" # 设置数据库用户名
- name: POSTGRES_PASSWORD
value: "Pg@Harbor123" # 设置数据库密码
- name: POSTGRES_DB
value: "registry" # 设置默认创建的数据库名
- name: TZ
value: Asia/Shanghai # 设置容器的时区
volumeMounts: # 将存储卷挂载到容器内的指定路径
- name: pg-data # 引用的存储卷名称(在 volumeClaimTemplates 中定义)
mountPath: /var/lib/postgresql/data # 挂载路径,即 PostgreSQL 的数据目录
volumeClaimTemplates: # 为每个 Pod 自动创建持久化卷声明 (PVC) 的模板
- metadata:
name: pg-data # PVC 的名称模板
spec:
accessModes: ["ReadWriteOnce"] # 访问模式,表示卷可以被单个节点以读写方式挂载
resources:
requests:
storage: 10Gi # 申请 10Gi 的存储空间
3.应用配置
bash
kubectl apply -f postgres.yaml
4.手动创建PG库
bash
kubectl exec -it -n harbor pg-harbor-0 bash
psql -U harbor -d registry
创建notary_signer和notary_server
bash
CREATE DATABASE notary_signer;
CREATE DATABASE notary_server;
退出
bash
\q
exit
二、K8s 部署 Redis
1.redis.yaml
yaml
apiVersion: v1
kind: Service
metadata:
name: redis-harbor
namespace: harbor
spec:
ports:
- port: 6379
name: redis
clusterIP: None
selector:
app: redis-harbor
---
# 外部访问 Service
apiVersion: v1
kind: Service
metadata:
name: redis-harbor-nodeport
namespace: harbor
spec:
type: NodePort
ports:
- port: 6379
nodePort: 30379
selector:
app: redis-harbor
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-harbor
namespace: harbor
spec:
serviceName: redis-harbor
replicas: 1
selector:
matchLabels:
app: redis-harbor
template:
metadata:
labels:
app: redis-harbor
spec:
containers:
- name: redis
image: redis:7-alpine
command: ["/bin/sh","-c"]
args:
- redis-server --requirepass Redis@Harbor123 --appendonly yes --protected-mode no
volumeMounts:
- name: redis-data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
2.应用配置
bash
kubectl apply -f redis.yaml
三、验证PostgreSQL和Redis外部连接
1.安装 psql 客户端(Harbor 服务器执行)
bash
apt install postgresql-client -y
2.连接命令
bash
psql -h 172.16.0.200 -p 30532 -U harbor -d registry
3.输入密码,出现下面内容表示PostgreSQL连接成功

4.安装 redis-cli(Harbor 服务器执行)
bash
apt install redis-tools -y
5.连接命令
bash
redis-cli -h 172.16.0.200 -p 30379
连接后执行:
bash
AUTH Redis@Harbor123 #Redis密码
6.出现 OK = Redis认证成功
再测试ping ,返回 pong → Redis完全正常

四、独立部署 MinIO(对象存储)
单机部署硬件条件
- 操作系统: Linux x86_64 / ARM64。主流发行版如 Ubuntu、CentOS、Debian 均可。
- CPU: 最低 2 核。
- 内存: 最低2G,建议至少 4GB。
- 磁盘: 至少 20GB 可用空间。为获得更好性能,推荐使用 SSD。
- 网络 : 需要开放 9000 (API) 和 9001 (Web 控制台) 端口。
1.Docker部署指令
bash
docker run -d --restart=always --name minio -p 9000:9000 -p 9001:9001 -v /data/minio:/data -e "MINIO_ROOT_USER=minioadmin" -e "MINIO_ROOT_PASSWORD=minioadmin123" --memory 1.5G quay.io/minio/minio server /data --console-address ":9001"
关键说明
- 宿主机数据目录:
/data/minio(自动创建)- 内存限制:1.5G(适配本演示2H2G 服务器,不爆内存)
- 端口:9000(API)、9001(控制台)
- 账号:
minioadmin/ 密码:minioadmin123
2.验证MinIo功能正常
①浏览器访问测试
浏览器打开 http://服务器IP:9001,能打开登录页面、输入账号密码能登录 → 控制台正常

②在任意机器测试网络联通
bash
curl -v http://云服务器IP:9000
正常会返回一段 XML 内容,不是超时、不是拒绝连接。

3.手动创建Bucket
-
登录 9001 控制台
-
左侧 Buckets → Create Bucket
-
名字填:harbor
-
其他默认,直接创建
4.测试上传/下载文件(核心功能)
-
进 harbor 这个 Bucket
-
点 Upload 随便传一个小文件(txt / 图片都行)
-
上传成功后,点击文件下载
能上传、能下载、不报错 → 存储读写正常
5.用命令行mc测试(模拟调用S3接口)
安装 mc 客户端(随便一台 Linux 机器)
bash
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
mv mc /usr/local/bin/
配置连接你的云服务器 MinIO
bash
mc alias set myminio http://云服务器IP:9000 minioadmin minioadmin123

- 查看 bucket 列表
bash
mc ls myminio
能看到刚才建的 harbor 桶 → S3 接口完全正常

- 测试写入文件
bash
echo "test" > test.txt
mc cp test.txt myminio/harbor/
无报错就是写入成功。

同时,在web控制台也能看到上传的test.txt

五、部署harbor
1.下载harbor安装包
前往 github地址:GitHub - goharbor/harbor: An open source trusted cloud native registry project that stores, signs, and scans content. · GitHub下载offline安装压缩包

2.上传到服务器并解压
上传压缩包到服务器解压后获得 harbor 文件夹
3.修改核心配置
bash
cp harbor.yml.tmpl harbor.yml

按照配置需求,修改harbor.yml内容如下:
yml
hostname: harbor.xxxxx.com #解析到harbor服务器的域名
http:
port: 80
https:
port: 443
certificate: /data/harbor/cert/harbor.pem #https证书
private_key: /data/harbor/cert/harbor.key #https证书
harbor_admin_password: Harbor12345 #harbor管理员密码
data_volume: /data/harbor #默认数据存储路径
# 外部 PostgreSQL(对接 K8s-PG)
external_database:
harbor:
host: 172.16.0.200
port: 30532
db_name: registry
username: harbor
password: Pg@Harbor123
ssl_mode: disable
notary_signer:
host: 172.16.0.200
port: 30532
db_name: notary_signer
username: harbor
password: Pg@Harbor123
ssl_mode: disable
notary_server:
host: 172.16.0.200
port: 30532
db_name: notary_server
username: harbor
password: Pg@Harbor123
ssl_mode: disable
# 外部 Redis(对接 K8s-Redis)
external_redis:
host: 172.16.0.200:30379
password: Redis@Harbor123
registry_db_index: 1
jobservice_db_index: 2
trivy_db_index: 5
idle_timeout_seconds: 30
# 外部MinIO(对接云服务器对象存储)
storage_service:
s3:
accesskey: minioadmin
secretkey: minioadmin123
region: us-east-1
bucket: harbor #必须在minio中先创建harbor桶
secure: false
regionendpoint: http://你的MinIO服务器IP:9000 #minio服务器IP+9000端口
v4auth: true
skipverify: true
trivy:
ignore_unfixed: false
skip_update: false
insecure: false
jobservice:
max_job_workers: 10
max_job_duration_hours: 24
job_loggers:
- STD_OUTPUT
- FILE
logger_sweeper_duration: 1
notification:
webhook_job_max_retry: 3
webhook_job_http_client_timeout: 3
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
_version: 2.15.0
4.执行初始化部署
bash
./prepare
docker compose up -d

六、Docker客户端配置&镜像推拉测试
1.从其他仓库拉取一个镜像
bash
docker pull nginx:alpine
2.Docker登录私有仓库
bash
docker login harbor.xxxxx.com # 替换成你的仓库地址
3.镜像打标签、推送
bash
docker tag nginx:alpine harbor.xxxxx.com/library/nginx:alpine #替换成你的harbor仓库地址
docker push harbor.xxxxx.com/library/nginx:alpine #替换成你的harbor仓库地址
4.测试拉取 + 运行
bash
docker pull harbor.xxxxx.com/library/nginx:alpine # 替换成你的harbor仓库地址
docker run -d harbor.xxxxx.com/library/nginx:alpine # 替换成你的harbor仓库地址

5.成功在harbor和minio控制台查看上传的镜像文件


七、Harbor + MinIO 进阶用法
1.MinIO 为 Harbor 配置最小权限子账号
①创建 MinIO 专用业务用户
bash
mc admin user add myminio harbor-svc HarborPass123!
②编写生产级最小权限策略 policy.json
允许:列出桶内内容、上传 / 下载 / 删除镜像对象,仅限定 harbor 桶
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::harbor",
"arn:aws:s3:::harbor/*"
]
}
]
}
③创建策略并绑定到专用用户
bash
# 创建策略,取名harbor-rw
mc admin policy create myminio harbor-rw policy.json
# 绑定harbor-rw策略给用户harbor-svc
mc admin policy attach myminio harbor-rw --user harbor-svc
④给 Harbor 生成专用 AccessKey
bash
mc admin accesskey create myminio --user harbor-svc
保存生成的 AccessKey / SecretKey,用于修改 Harbor 存储配置。

⑤修改 harbor.yml 接入 MinIO 子账号
yaml
# MinIO
storage_service:
s3:
accesskey: RNJVCGM6PA2UM2KH8WWS #替换成你的accesskey
secretkey: uQsH8+i7VcbOPrNUWrgjgghzJ8HL2BptDWshTIVt #替换成你的secretkey
region: us-east-1
bucket: harbor
secure: false
regionendpoint: http://你的minio服务器IP:9000
v4auth: true
skipverify: true
重启生效 Harbor:
bash
docker compose down
./prepare
docker compose up -d
⑥权限验证步骤
用子账号新建 mc 别名做测试
bash
mc alias set test-harbor-svc http://你的MinIO服务器IP:9000 harbor-svc HarborPass123!
验证结果:
-
mc ls test-harbor-svc:只能看到 harbor 一个桶,看不到其他桶,无全局浏览权限 -
mc ls test-harbor-svc/harbor:正常列出桶内 docker 目录,读写列表权限正常 -
Docker 推拉镜像:harbor 推拉、运行完全正常

2.MinIO 生命周期规则(自动清理 Harbor 旧镜像,释放存储)
这里我们给 harbor 桶配置生命周期规则,让 30 天未被访问的镜像分层 / 旧版本自动删除,释放磁盘空间,同时不影响正在使用的镜像。
bash
# 创建规则
cat > lifecycle.json << EOF
{
"Rules": [
{
"ID": "harbor-30days-expire",
"Status": "Enabled",
"Prefix": "",
"Expiration": { "Days": 30 }
}
]
}
EOF
# 应用规则
mc ilm rule import myminio/harbor < lifecycle.json
# 查看规则
mc ilm rule list myminio/harbor

3.Harbor 内置垃圾回收 GC
MinIO 生命周期是删过期文件 ;Harbor 垃圾回收是清理镜像废弃分层、冗余垃圾,两个配合,磁盘空间彻底释放。
Harbor 删掉镜像后,镜像层文件还留在 MinIO 里 ,占空间不自动删;执行垃圾回收,清理没被任何镜像引用的冗余层,释放存储空间。

点击【模拟运行】会列出即将清理的文件

点击【立即清理垃圾】

从日志可以看到真实删掉了:9 个镜像层 blob、1 个镜像清单 manifest,实际真正从 MinIO 后端 释放了 24MB

配置定时清理

cron格式参考:
| 执行时间 | Cron 表达式 |
|---|---|
| 每天凌晨 3 点 | 0 3 * * * |
| 每周六凌晨 3 点 | 0 3 * * 6 |
| 每月 1 号 凌晨 3 点执行 | 0 3 1 * * |
4.K8s 配置 Harbor 私有镜像拉取
K8s 默认不能直接拉取 Harbor 私有镜像 ,会报ErrImagePull / ImagePullBackOff,接下来我们进行拉取配置
①操作所有 K8s 节点登录 Harbor
bash
docker login harbor.xxxxx.com #替换成你的harbor地址
②创建私有镜像拉取secret
bash
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.xxxxx.com \ #改成你的harbor仓库地址
--docker-username=hyz \
--docker-password='Hyz123!@#' \
--docker-email=test@example.com
③配置拉取方式(2种)
- 方式A:单个 YAML 手动指定(繁琐)
在 Pod/Deployment 模板里加:
yaml
spec:
imagePullSecrets:
- name: harbor-secret
- 方式B:设为命名空间默认密钥**(推荐)**
给 default 命名空间默认服务账号绑定拉取密钥:
bash
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-secret"}]}'
创建测试test.yaml 不配置 imagePullSecrets
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-harbor2
spec:
replicas: 1
selector:
matchLabels:
app: test-harbor2
template:
metadata:
labels:
app: test-harbor2
spec:
containers:
- name: nginx
image: harbor.xxxx.com/library/nginx:alpine #填仓库镜像名称
ports:
- containerPort: 80
应用
bash
kubectl appply -f test.yaml
应用后 Pod 状态直接变为 1/1 Running,代表配置全部生效
八、Harbor+LDAP统一认证
Harbor 接入 LDAP,实现统一身份认证,一套账号管理仓库、服务器等多系统,集中管控权限,符合企业运维规范。
LDAP服务器:OpenLDAP + phpLDAPadmin 可视化管理,部署在独立服务器
172.16.3.207
1.LDAP 服务部署(docker)
yml
#核心配置(docker-compose.yml)
services:
openldap:
image: osixia/openldap:latest
container_name: openldap
restart: always
ports:
- "389:389"
environment:
LDAP_ORGANISATION: "HarborCorp"
LDAP_DOMAIN: "harbor.local"
LDAP_ADMIN_PASSWORD: "Admin@123"
volumes:
- /data/openldap:/var/lib/ldap
- /data/openldap-config:/etc/ldap/slapd.d
phpldapadmin:
image: osixia/phpldapadmin:latest
container_name: phpldapadmin
restart: always
ports:
- "8088:80"
environment:
PHPLDAPADMIN_LDAP_HOSTS: openldap
PHPLDAPADMIN_HTTPS: "false"
2.启动服务
bash
docker compose up -d
3.访问管理页面
- 地址:
http://172.16.3.207:8088 - 登录 DN:
cn=admin,dc=harbor,dc=local - 密码:
Admin@123
4.Harbor切换LDAP认证
①修改harbor.yml
新增以下内容,开启LDAP
bash
auth_mode: ldap_auth
ldap:
url: ldap://172.16.3.207:389
search_dn: cn=admin,dc=harbor,dc=local
search_password: Admin@123
base_dn: dc=harbor,dc=local
uid: cn
scope: subtree
verify_cert: false
②修改修改 PostgreSQL 认证模式(外部库必须执行)
bash
# 进入PG Pod
kubectl exec -it -n harbor pg-harbor-0 -- bash
# 登录数据库
psql -U harbor -d registry
# 插入认证模式(无则插入,有则更新)
INSERT INTO properties (k, v) VALUES ('auth_mode', 'ldap_auth');
# 验证
SELECT * FROM properties WHERE k = 'auth_mode';
#预计返回以下内容
id | k | v
----+-----------+-----------
3 | auth_mode | ldap_auth
(1 row)
#退出
\q
exit
③重启Harbor生效
bash
./prepare
docker compose down
docker compose up -d
5.Harbor web界面配置LDAP参数
①进入 【配置管理】→ 【配置】→【认证模式】

②填写参数
| 配置项 | 值 | 注释 |
|---|---|---|
| LDAP URL | ldap://172.16.3.207:389 | LDAP 服务器地址及端口(非加密连接) |
| LDAP 搜索 DN | cn=admin,dc=harbor,dc=local | 用于绑定并搜索 LDAP 目录的管理员账户 DN |
| 搜索密码 | Admin@123 | 上述管理员账户的密码 |
| 基础 DN | dc=harbor,dc=local | LDAP 搜索的起始点,所有用户在此路径下查找 |
| 过滤器 | (objectClass=inetOrgPerson) | 只筛选出对象类为 inetOrgPerson 的条目(通常代表人员账号) |
| 用户 UID | cn | 使用 cn(通用名称)作为用户登录 ID 的属性映射 |
| 搜索范围 | 子树 | 从基础 DN 开始,递归搜索所有子目录 |
| LDAP 检查证书 | 否(已取消勾选) | 跳过 LDAP 服务端证书校验(仅用于测试或内网信任环境) |
③测试连接
点击 【测试连接】 → 连通正常 → 保存

6.创建LDAP管理员用户(用于登录 Harbor)
登录LDAP管理后台 http://172.16.3.207:8088
①登录
DN: cn=admin,dc=harbor,dc=local
密码:Admin@123

②创建用于登录Harbor用户
- 创建 Generic: Posix Group
左侧点击 dc=harbor,dc=local,点击 Create new entry here ,模板选择:Generic: Posix Group
填写信息:
| 配置项 | 值 | 注释 |
|---|---|---|
| Group name | users | LDAP 中的用户组名称 |
| GID Number | 500 | 用户组的 GID 编号 |
点击 Create Object,组创建完成
- 创建Generic: User Account
左侧点击 dc=harbor,dc=local,点击 Create new entry here ,模板选择:Generic: User Account
填写信息:
| 配置项 | 值 | 注释 |
|---|---|---|
| First name | harbor-admin | 名 |
| Last name | harbor-admin | 姓 |
| Common Name (cn) | harbor-admin | 登录用户名,不能包含空格 |
| User ID | harbor-admin | 用户 ID,通常与 Common Name 保持一致 |
| UID Number | 1000 | 用户 UID 编号 |
| GID Number | users(500) | 下拉选择,对应 users 组,GID 为 500 |
| Home directory | /home/users/harbor-admin |
用户主目录路径 |
| 密码 | admin123!@# | 用户登录密码 |
点击 Create Object,用户创建完成
7.给 LDAP 用户授予 Harbor 系统管理员权限
LDAP 仅负责身份认证,权限由 Harbor 数据库控制
前往harbor web界面授权------【系统管理】------【用户管理】------找到【harbor-admin】------设置为管理员
