概述
Harbor 简介
Harbor 是一个开源的企业级容器镜像仓库,由 VMware 开发并贡献给 CNCF。它基于 Docker Registry 进行二次开发,提供了企业级的功能增强,包括安全、身份认证、管理等,是构建私有容器镜像仓库的首选方案。
核心架构
Harbor 采用模块化架构设计,主要组件包括:
┌─────────────────────────────────────────────────────────────┐
│ Harbor UI │
├─────────────────────────────────────────────────────────────┤
│ Core │
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────┐ │
│ │ API 服务 │ │ 认证服务 │ │ Webhook 服务 │ │
│ └─────────────┘ └─────────────┘ └────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────┐ │
│ │ Job Service │ │ Registry │ │ Registry Ctl │ │
│ └─────────────┘ └─────────────┘ └────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────┐ │
│ │ PostgreSQL │ │ Redis │ │ Trivy/Clair │ │
│ └─────────────┘ └─────────────┘ └────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
核心组件说明:
- Proxy: Nginx 反向代理,处理所有 Harbor 的请求
- Core: Harbor 的核心服务,提供 API、认证、项目管理等功能
- Job Service: 异步任务服务,处理镜像复制、垃圾回收、扫描等任务
- Registry: Docker Registry v2,负责镜像存储
- Database: PostgreSQL,存储项目、用户、角色、复制策略等元数据
- Redis: 缓存服务,存储 session 和任务队列
- Trivy/Clair: 镜像安全扫描器
主要特点
-
基于角色的访问控制(RBAC)
- 多租户支持
- 细粒度的权限管理
- 项目级别的访问控制
-
镜像安全扫描
- 集成 Trivy/Clair 扫描器
- 自动扫描推送的镜像
- 漏洞报告和修复建议
-
镜像签名
- 内容信任(Content Trust)
- Notary 集成
- 确保镜像完整性
-
审计日志
- 完整的操作记录
- 合规性支持
- 日志导出和分析
-
镜像复制
- 多数据中心同步
- 支持多种复制模式
- 带宽优化
-
Helm Chart 支持
- Chart 仓库功能
- 版本管理
- 依赖解析
使用场景
-
企业私有镜像仓库
- 统一管理企业内部镜像
- 安全隔离和访问控制
- 合规性要求
-
CI/CD 集成
- 与 Jenkins、GitLab CI 等集成
- 自动化构建和推送
- 镜像版本管理
-
多数据中心部署
- 跨地域镜像同步
- 就近访问优化
- 灾备和高可用
-
开发测试环境
- 快速部署测试环境
- 版本回滚
- 资源隔离
安装部署
系统要求
硬件要求:
| 资源 | 最小配置 | 推荐配置 |
|---|---|---|
| CPU | 2 核 | 4 核 |
| 内存 | 4 GB | 8 GB |
| 磁盘 | 40 GB | 160 GB |
软件要求:
- Docker version 17.06.0-ce+ 或更高版本
- Docker Compose version 1.18.0 或更高版本
- OpenSSL 最新版本(用于生成证书)
端口要求:
| 端口 | 协议 | 描述 |
|---|---|---|
| 443 | HTTPS | Harbor portal 和 core API 使用此端口 |
| 4443 | HTTPS | 仅在启用 Notary 时使用此端口 |
| 80 | HTTP | Harbor portal 和 core API 使用此端口 |
在线安装
在线安装步骤
- 下载在线安装包
# 下载最新版本(推荐)
wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-online-installer-v2.9.1.tgz
# 解压安装包
tar xvf harbor-online-installer-v2.9.1.tgz
cd harbor
- 配置 harbor.yml
# 复制配置模板
cp harbor.yml.tmpl harbor.yml
# 编辑配置文件
vim harbor.yml
- 执行安装脚本
# 安装 Harbor
sudo ./install.sh
# 带组件安装(推荐)
sudo ./install.sh --with-trivy --with-chartmuseum
离线安装
离线安装步骤
- 下载离线安装包
# 下载离线安装包(包含所有镜像)
wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz
# 解压安装包
tar xvf harbor-offline-installer-v2.9.1.tgz
cd harbor
- 加载镜像
# 离线包会自动加载镜像
# 如需手动加载
docker load -i harbor.v2.9.1.tar.gz
- 配置和安装
# 复制配置文件
cp harbor.yml.tmpl harbor.yml
# 编辑配置
vim harbor.yml
# 执行安装
sudo ./install.sh --with-trivy --with-chartmuseum
高可用部署
架构设计
┌────────────────────────────────────────────────┐
│ Load Balancer (HA) │
├────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ Harbor-1 │ │ Harbor-2 │ │ Harbor-3 │
│ └──────────┘ └──────────┘ └──────────┘
├────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ Redis │ │PostgreSQL│ │ NFS │
│ │ Cluster │ │ Cluster │ │ Storage │
│ └──────────┘ └──────────┘ └──────────┘
└────────────────────────────────────────────────┘
高可用部署步骤
- 准备共享存储
# 配置 NFS 服务器
sudo apt-get install nfs-kernel-server
sudo mkdir -p /data/harbor-storage
sudo chmod 777 /data/harbor-storage
# 编辑 /etc/exports
echo "/data/harbor-storage *(rw,sync,no_root_squash)" >> /etc/exports
sudo exportfs -a
- 部署外部数据库
# PostgreSQL 高可用集群(使用 Patroni)
# 创建 patroni 配置
cat > patroni.yml <<EOF
scope: harbor-db
namespace: /service/
name: postgresql-1
restapi:
listen: 0.0.0.0:8008
connect_address: node1:8008
etcd:
hosts: etcd1:2379,etcd2:2379,etcd3:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
initdb:
- encoding: UTF8
- data-checksums
postgresql:
listen: 0.0.0.0:5432
connect_address: node1:5432
data_dir: /data/postgresql
pgpass: /tmp/pgpass
parameters:
max_connections: 200
shared_buffers: 256MB
effective_cache_size: 1GB
EOF
- 配置 Harbor 高可用
# harbor.yml 高可用配置
hostname: harbor.example.com
# 外部数据库配置
external_database:
harbor:
host: postgresql-vip
port: 5432
db_name: harbor
username: harbor
password: harbor_password
ssl_mode: require
max_idle_conns: 50
max_open_conns: 100
# 外部 Redis 配置
external_redis:
host: redis-vip
port: 6379
password: redis_password
registry_db_index: 1
jobservice_db_index: 2
chartmuseum_db_index: 3
trivy_db_index: 5
idle_timeout_seconds: 30
# 存储配置
storage_service:
filesystem:
rootdirectory: /data/harbor-storage
maintenance:
uploadpurging:
enabled: true
age: 168h
interval: 24h
dryrun: false
Docker Compose 部署
使用 Bitnami 镜像部署
- 下载 docker-compose.yml
# 创建目录
mkdir -p harbor-bitnami && cd harbor-bitnami
# 下载配置文件
curl -LO https://raw.githubusercontent.com/bitnami/containers/main/bitnami/harbor-portal/docker-compose.yml
# 下载配置文件
curl -L https://github.com/bitnami/containers/archive/main.tar.gz | tar xz --strip=2 containers-main/bitnami/harbor-portal && cp -RL harbor-portal/config . && rm -rf harbor-portal
- 自定义配置
# docker-compose.yml 自定义配置
version: '3.8'
services:
registry:
image: docker.io/bitnami/harbor-registry:2
environment:
- REGISTRY_HTTP_SECRET=CHANGEME
volumes:
- registry_data:/storage
- ./config/registry/:/etc/registry/:ro
networks:
- harbor-network
registryctl:
image: docker.io/bitnami/harbor-registryctl:2
environment:
- CORE_SECRET=CHANGEME
- JOBSERVICE_SECRET=CHANGEME
- REGISTRY_HTTP_SECRET=CHANGEME
volumes:
- registry_data:/storage
- ./config/registry/:/etc/registry/:ro
- ./config/registryctl/config.yml:/etc/registryctl/config.yml:ro
networks:
- harbor-network
postgresql:
image: docker.io/bitnami/postgresql:13
container_name: harbor-db
environment:
- POSTGRESQL_PASSWORD=bitnami
- POSTGRESQL_DATABASE=registry
volumes:
- postgresql_data:/bitnami/postgresql
networks:
- harbor-network
core:
image: docker.io/bitnami/harbor-core:2
container_name: harbor-core
depends_on:
- registry
- postgresql
environment:
- CORE_KEY=change-this-key
- _REDIS_URL_CORE=redis://redis:6379/0
- SYNC_REGISTRY=false
- CHART_CACHE_DRIVER=redis
- _REDIS_URL_REG=redis://redis:6379/1
- PORT=8080
- LOG_LEVEL=info
- EXT_ENDPOINT=https://harbor.example.com
- DATABASE_TYPE=postgresql
- REGISTRY_CONTROLLER_URL=http://registryctl:8080
- POSTGRESQL_HOST=postgresql
- POSTGRESQL_PORT=5432
- POSTGRESQL_DATABASE=registry
- POSTGRESQL_USERNAME=postgres
- POSTGRESQL_PASSWORD=bitnami
- POSTGRESQL_SSLMODE=disable
- REGISTRY_URL=http://registry:5000
- TOKEN_SERVICE_URL=http://core:8080/service/token
- HARBOR_ADMIN_PASSWORD=Harbor12345
- CORE_SECRET=CHANGEME
- JOBSERVICE_SECRET=CHANGEME
- ADMIRAL_URL=
- CORE_URL=http://core:8080
- JOBSERVICE_URL=http://jobservice:8080
- REGISTRY_STORAGE_PROVIDER_NAME=filesystem
- REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
- REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
- READ_ONLY=false
- RELOAD_KEY=
volumes:
- core_data:/data
- ./config/core/app.conf:/etc/core/app.conf:ro
- ./config/core/private_key.pem:/etc/core/private_key.pem:ro
networks:
- harbor-network
portal:
image: docker.io/bitnami/harbor-portal:2
container_name: harbor-portal
depends_on:
- core
networks:
- harbor-network
jobservice:
image: docker.io/bitnami/harbor-jobservice:2
container_name: harbor-jobservice
depends_on:
- redis
- core
environment:
- CORE_SECRET=CHANGEME
- JOBSERVICE_SECRET=CHANGEME
- CORE_URL=http://core:8080
- REGISTRY_CONTROLLER_URL=http://registryctl:8080
- REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
- REGISTRY_CREDENTIAL_PASSWORD=harbor_registry_password
volumes:
- jobservice_data:/var/log/jobs
- ./config/jobservice/config.yml:/etc/jobservice/config.yml:ro
networks:
- harbor-network
redis:
image: docker.io/bitnami/redis:7.0
environment:
- REDIS_PASSWORD=redis_password
volumes:
- redis_data:/bitnami/redis/data
networks:
- harbor-network
harbor-nginx:
image: docker.io/bitnami/nginx:1.25
container_name: nginx
volumes:
- ./config/proxy/nginx.conf:/opt/bitnami/nginx/conf/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
ports:
- '80:8080'
- '443:8443'
depends_on:
- postgresql
- registry
- core
- portal
networks:
- harbor-network
networks:
harbor-network:
driver: bridge
volumes:
registry_data:
driver: local
core_data:
driver: local
jobservice_data:
driver: local
postgresql_data:
driver: local
redis_data:
driver: local
- 启动服务
# 启动 Harbor
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
配置管理
基础配置
harbor.yml 完整配置示例
# Configuration file of Harbor
# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: harbor.example.com
# http related config
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 80
# https related config
https:
# https port for harbor, default is 443
port: 443
# The path of cert and key files for nginx
certificate: /etc/harbor/certs/server.crt
private_key: /etc/harbor/certs/server.key
# Uncomment external_url if you want to enable external proxy
# external_url: https://harbor.example.com:8433
# The initial password of Harbor admin
# It only works in first time to install harbor
# Remember Change the admin password from UI after launching Harbor.
harbor_admin_password: Harbor12345
# Harbor DB configuration
database:
# The password for the root user of Harbor DB. Change this before any production use.
password: root123
# The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
max_idle_conns: 100
# The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
max_open_conns: 900
# The default data volume
data_volume: /data
# Harbor Storage settings by default is using /data dir on local filesystem
# Uncomment storage_service setting If you want to using external storage
storage_service:
# ca_bundle is the path to the custom root ca certificate, which will be injected into the truststore
# of registry's and chart repository's containers. This is usually needed when the user hosts a internal storage with self signed certificate.
ca_bundle:
# storage backend, default is filesystem, options include filesystem, azure, gcs, s3, swift and oss
# for more info about this configuration please refer https://docs.docker.com/registry/configuration/
filesystem:
maxthreads: 100
# set disable to true when you want to disable registry redirect
redirect:
disabled: false
# Trivy configuration
trivy:
# ignoreUnfixed The flag to display only fixed vulnerabilities
ignore_unfixed: false
# skipUpdate The flag to enable or disable Trivy DB downloads from GitHub
skip_update: false
# insecure The flag to skip verifying registry certificate
insecure: false
# github_token The GitHub access token to download Trivy DB
# github_token: xxx
jobservice:
# Maximum number of job workers in job service
max_job_workers: 10
notification:
# Maximum retry count for webhook job
webhook_job_max_retry: 10
chart:
# Change the value of absolute_url to enabled can enable absolute url in chart
absolute_url: disabled
# Log configurations
log:
# options are debug, info, warning, error, fatal
level: info
# configs for logs in local storage
local:
# Log files are rotated log_rotate_count times before being removed. If count is 0, old versions are removed rather than rotated.
rotate_count: 50
# Log files are rotated only if they grow bigger than log_rotate_size bytes. If size is followed by k, the size is assumed to be in kilobytes.
# If the M is used, the size is in megabytes, and if G is used, the size is in gigabytes. So size 100, size 100k, size 100M and size 100G
# are all valid.
rotate_size: 200M
# The directory on your host that store log
location: /var/log/harbor
# Uncomment following lines to enable external syslog endpoint.
# external_endpoint:
# # protocol used to transmit log to external endpoint, options is tcp or udp
# protocol: tcp
# # The host of external endpoint
# host: localhost
# # Port of external endpoint
# port: 5140
#This attribute is for migrator to detect the version of the .cfg file, DO NOT MODIFY!
_version: 2.9.0
# Uncomment external_redis if using external Redis server
# external_redis:
# # support redis, redis+sentinel
# # host for redis: <host_redis>:<port_redis>
# # host for redis+sentinel:
# # <host_sentinel1>:<port_sentinel1>,<host_sentinel2>:<port_sentinel2>,<host_sentinel3>:<port_sentinel3>
# host: redis:6379
# password:
# # sentinel_master_set must be set to support redis+sentinel
# #sentinel_master_set:
# # db_index 0 is for core, it's unchangeable
# registry_db_index: 1
# jobservice_db_index: 2
# chartmuseum_db_index: 3
# trivy_db_index: 5
# idle_timeout_seconds: 30
# Uncomment uaa for trusting the certificate of uaa instance that is hosted via self-signed cert.
# uaa:
# ca_file: /path/to/ca
# Global proxy
# Config http proxy for components, e.g. http://my.proxy.com:3128
# Components doesn't need to connect to each others via http proxy.
proxy:
http_proxy:
https_proxy:
no_proxy:
components:
- core
- jobservice
- trivy
# metric:
# enabled: false
# port: 9090
# path: /metrics
# Trace related config
# only can enable one trace provider(jaeger or otel) at the same time,
# and when using jaeger as provider, can only enable it with agent mode or collector mode.
# if using jaeger collector mode, uncomment endpoint and uncomment username, password if needed
# if using jaeger agent mode uncomment agent_host and agent_port
# trace:
# enabled: true
# # set sample_rate to 1 if you wanna sampling 100% of trace data; set 0.5 if you wanna sampling 50% of trace data, and so forth
# sample_rate: 1
# # # namespace used to differenciate different harbor services
# # namespace:
# # # attributes is a key value dict contains user defined attributes used to initialize trace provider
# # attributes:
# # application: harbor
# # # jaeger should be 1.26 or newer.
# # jaeger:
# # endpoint: http://hostname:14268/api/traces
# # username:
# # password:
# # agent_host: hostname
# # # export trace data by jaeger.thrift in compact mode
# # agent_port: 6831
# # otel:
# # endpoint: hostname:4318
# # url_path: /v1/traces
# # compression: false
# # insecure: true
# # timeout: 10s
# enable purge _upload directories
upload_purging:
enabled: true
# remove files in _upload directories which exist for a period of time, default is one week.
age: 168h
# the interval of the purge operations
interval: 24h
dryrun: false
HTTPS 配置
生成自签名证书
# 创建证书目录
mkdir -p /data/cert
cd /data/cert
# 生成私钥
openssl genrsa -out ca.key 4096
# 生成 CA 证书
openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.example.com" \
-key ca.key \
-out ca.crt
# 生成服务器私钥
openssl genrsa -out server.key 4096
# 生成证书签名请求
openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.example.com" \
-key server.key \
-out server.csr
# 生成 x509 v3 扩展文件
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=harbor.example.com
DNS.2=*.harbor.example.com
IP.1=192.168.1.100
EOF
# 生成服务器证书
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in server.csr \
-out server.crt
# 转换证书格式供 Docker 使用
openssl x509 -inform PEM -in server.crt -out server.cert
# 复制证书到 Harbor 配置目录
cp server.cert /data/cert/
cp server.key /data/cert/
配置 Docker 信任证书
# 创建 Docker 证书目录
mkdir -p /etc/docker/certs.d/harbor.example.com/
# 复制证书
cp /data/cert/ca.crt /etc/docker/certs.d/harbor.example.com/
cp /data/cert/server.cert /etc/docker/certs.d/harbor.example.com/
cp /data/cert/server.key /etc/docker/certs.d/harbor.example.com/
# 重启 Docker
systemctl restart docker
存储配置
S3 存储配置
# harbor.yml 中的 S3 存储配置
storage_service:
s3:
accesskey: your_access_key
secretkey: your_secret_key
region: us-west-1
bucket: harbor-storage
encrypt: true
secure: true
v4auth: true
chunksize: 5242880
multipartcopychunksize: 33554432
multipartcopymaxconcurrency: 100
multipartcopythresholdsize: 33554432
rootdirectory: /harbor
阿里云 OSS 配置
storage_service:
oss:
accesskeyid: your_access_key_id
accesskeysecret: your_access_key_secret
region: oss-cn-hangzhou
bucket: harbor-storage
endpoint: oss-cn-hangzhou.aliyuncs.com
internal: false
encrypt: false
secure: true
chunksize: 5242880
rootdirectory: /harbor
认证配置
LDAP 配置
# UI 配置或通过 API 配置
{
"ldap_url": "ldap://ldap.example.com",
"ldap_search_dn": "uid=admin,ou=people,dc=example,dc=com",
"ldap_search_password": "admin_password",
"ldap_base_dn": "ou=people,dc=example,dc=com",
"ldap_filter": "(objectClass=person)",
"ldap_uid": "uid",
"ldap_scope": 2,
"ldap_timeout": 5,
"ldap_verify_cert": false,
"ldap_group_base_dn": "ou=groups,dc=example,dc=com",
"ldap_group_search_filter": "(objectClass=groupOfNames)",
"ldap_group_attribute_name": "cn",
"ldap_group_search_scope": 2,
"ldap_group_membership_attribute": "member"
}
OIDC 配置
# 通过 API 配置 OIDC
{
"oidc_name": "keycloak",
"oidc_endpoint": "https://keycloak.example.com/auth/realms/harbor",
"oidc_client_id": "harbor",
"oidc_client_secret": "secret",
"oidc_groups_claim": "groups",
"oidc_admin_group": "harbor-admin",
"oidc_scope": "openid,profile,email",
"oidc_verify_cert": true,
"oidc_auto_onboard": true,
"oidc_user_claim": "preferred_username"
}
扫描器配置
Trivy 配置优化
# harbor.yml 中的 Trivy 配置
trivy:
# 忽略未修复的漏洞
ignore_unfixed: false
# 跳过更新 Trivy DB
skip_update: false
# 不验证注册表证书
insecure: false
# GitHub token 用于下载 Trivy DB
github_token: your_github_token
# 离线模式
offline_scan: false
# 安全检查
security_check: vuln
# 超时设置
timeout: 5m0s
项目和镜像管理
创建项目
项目类型说明
- 公开项目:任何用户都可以拉取镜像
- 私有项目:只有项目成员可以拉取镜像
创建项目示例
# 使用 Harbor API 创建项目
curl -X POST "https://harbor.example.com/api/v2.0/projects" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
-d '{
"project_name": "my-project",
"metadata": {
"public": "false",
"enable_content_trust": "true",
"prevent_vul": "true",
"severity": "medium",
"auto_scan": "true"
},
"storage_limit": 10737418240
}'
推送镜像
Docker 客户端配置
# 配置 Docker daemon
sudo tee /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://registry.docker-cn.com"
],
"insecure-registries": [
"harbor.example.com"
],
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOF
# 重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
推送镜像步骤
# 1. 登录 Harbor
docker login harbor.example.com -u admin -p Harbor12345
# 2. 给镜像打标签
docker tag nginx:latest harbor.example.com/my-project/nginx:v1.0
# 3. 推送镜像
docker push harbor.example.com/my-project/nginx:v1.0
# 4. 批量推送脚本
#!/bin/bash
HARBOR_URL="harbor.example.com"
PROJECT="my-project"
IMAGES=("nginx" "redis" "mysql" "postgres")
for img in "${IMAGES[@]}"; do
docker pull $img:latest
docker tag $img:latest $HARBOR_URL/$PROJECT/$img:latest
docker push $HARBOR_URL/$PROJECT/$img:latest
done
拉取镜像
# 拉取公开项目镜像(无需登录)
docker pull harbor.example.com/public/nginx:v1.0
# 拉取私有项目镜像(需要登录)
docker login harbor.example.com
docker pull harbor.example.com/my-project/nginx:v1.0
镜像标签管理
标签命名规范
# 版本号标签
harbor.example.com/project/app:1.0.0
harbor.example.com/project/app:1.0.1
harbor.example.com/project/app:2.0.0
# 环境标签
harbor.example.com/project/app:dev
harbor.example.com/project/app:staging
harbor.example.com/project/app:prod
# Git 提交标签
harbor.example.com/project/app:git-abc123
harbor.example.com/project/app:branch-feature-x
# 时间戳标签
harbor.example.com/project/app:20231215-1430
镜像删除策略
配置镜像保留策略
{
"rules": [
{
"disabled": false,
"action": "retain",
"scope_selectors": {
"repository": [
{
"kind": "doublestar",
"decoration": "repoMatches",
"pattern": "**"
}
]
},
"tag_selectors": [
{
"kind": "doublestar",
"decoration": "matches",
"pattern": "prod-*"
}
]
},
{
"disabled": false,
"action": "retain",
"scope_selectors": {
"repository": [
{
"kind": "doublestar",
"decoration": "repoMatches",
"pattern": "**"
}
]
},
"tag_selectors": [
{
"kind": "latestPushedK",
"decoration": "latestPushedK",
"pattern": "10"
}
]
}
],
"trigger": {
"kind": "Schedule",
"settings": {
"cron": "0 0 * * *"
}
}
}
用户权限管理
用户管理
创建用户
# API 创建用户
curl -X POST "https://harbor.example.com/api/v2.0/users" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
-d '{
"username": "developer",
"email": "developer@example.com",
"password": "Dev@12345",
"realname": "Developer User",
"comment": "Developer account"
}'
角色和权限
Harbor 内置角色
| 角色 | 权限 | 说明 |
|---|---|---|
| Project Admin | 所有权限 | 项目管理员,拥有项目的所有权限 |
| Developer | 读写权限 | 可以推送和拉取镜像 |
| Guest | 只读权限 | 只能拉取镜像 |
| Maintainer | 签名权限 | 可以签名镜像 |
分配角色
# 添加项目成员
curl -X POST "https://harbor.example.com/api/v2.0/projects/1/members" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
-d '{
"role_id": 2,
"member_user": {
"username": "developer"
}
}'
LDAP/AD 集成
配置步骤
- 登录管理界面
- 配置 -> 认证 -> LDAP
- 填写 LDAP 参数
# LDAP 配置示例
LDAP URL: ldap://ldap.example.com:389
LDAP Search DN: cn=admin,dc=example,dc=com
LDAP Search Password: ******
LDAP Base DN: ou=people,dc=example,dc=com
LDAP Filter: (objectClass=person)
LDAP UID: uid
LDAP Scope: Subtree
LDAP Group Base DN: ou=groups,dc=example,dc=com
LDAP Group Filter: (objectClass=groupOfNames)
LDAP Group GID: cn
LDAP Group Scope: Subtree
OIDC 集成
Keycloak 集成示例
# 1. 在 Keycloak 创建客户端
# 2. 配置 Harbor OIDC
curl -X PUT "https://harbor.example.com/api/v2.0/configurations" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
-d '{
"auth_mode": "oidc_auth",
"oidc_name": "Keycloak",
"oidc_endpoint": "https://keycloak.example.com/auth/realms/master",
"oidc_client_id": "harbor",
"oidc_client_secret": "secret",
"oidc_groups_claim": "groups",
"oidc_admin_group": "harbor-admin",
"oidc_scope": "openid,profile,email,offline_access",
"oidc_verify_cert": true,
"oidc_auto_onboard": true,
"oidc_user_claim": "preferred_username"
}'
镜像安全扫描
扫描策略配置
自动扫描配置
# 项目级别扫描策略
curl -X PUT "https://harbor.example.com/api/v2.0/projects/1" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
-d '{
"metadata": {
"auto_scan": "true",
"severity": "medium",
"prevent_vul": "true"
}
}'
漏洞数据库
Trivy 数据库更新
# 手动更新 Trivy 数据库
docker exec -it harbor-trivy-adapter trivy image --download-db-only
# 配置代理更新
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
trivy image --download-db-only
扫描报告
获取扫描报告
# 获取镜像扫描报告
curl -X GET "https://harbor.example.com/api/v2.0/projects/my-project/repositories/nginx/artifacts/sha256:abc123/vulnerabilities/summary" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)"
安全策略
CVE 白名单配置
{
"items": [
{
"cve_id": "CVE-2021-12345",
"expires_at": 1640995200
},
{
"cve_id": "CVE-2021-67890",
"expires_at": null
}
]
}
镜像复制
复制规则
创建复制规则
# 推送模式复制
curl -X POST "https://harbor.example.com/api/v2.0/replication/policies" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
-d '{
"name": "sync-to-backup",
"description": "Sync images to backup harbor",
"src_registry": {
"id": 0
},
"dest_registry": {
"id": 1
},
"dest_namespace": "backup",
"trigger": {
"type": "scheduled",
"trigger_settings": {
"cron": "0 2 * * *"
}
},
"enabled": true,
"deletion": false,
"override": true,
"filters": [
{
"type": "name",
"value": "production/*"
},
{
"type": "tag",
"value": "v*"
}
]
}'
多数据中心同步
配置示例
# 主数据中心 -> 备份数据中心
复制策略:
- 名称: main-to-backup
源: 本地
目标: backup-harbor
触发器: 事件驱动
过滤器:
- 仓库: production/*
- 标签: latest, v*
# 跨区域同步
复制策略:
- 名称: cn-to-us
源: 本地
目标: us-harbor
触发器: 定时(0 3 * * *)
带宽限制: 10MB/s
复制策略
复制模式对比
| 模式 | 触发方式 | 适用场景 | 优缺点 |
|---|---|---|---|
| Push Mode | 主动推送 | 主备同步 | 实时性好,需要目标端凭证 |
| Pull Mode | 主动拉取 | 聚合多源 | 集中管理,有延迟 |
| Event Based | 事件触发 | 实时同步 | 即时同步,资源消耗大 |
| Scheduled | 定时执行 | 批量同步 | 可控性好,有延迟 |
复制监控
# 查看复制任务执行情况
curl -X GET "https://harbor.example.com/api/v2.0/replication/executions?policy_id=1" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)"
# 查看具体任务日志
curl -X GET "https://harbor.example.com/api/v2.0/replication/executions/1/tasks" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)"
备份恢复
备份策略
备份内容
- 数据库备份:PostgreSQL 数据
- 镜像存储备份:Registry 数据
- 配置文件备份:harbor.yml 等
- 证书备份:SSL 证书和密钥
数据备份
备份脚本
#!/bin/bash
# Harbor 备份脚本
BACKUP_DIR="/backup/harbor"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="$BACKUP_DIR/harbor_backup_$DATE"
# 创建备份目录
mkdir -p $BACKUP_PATH
# 停止 Harbor
cd /opt/harbor
docker-compose down
# 备份数据库
sudo -u postgres pg_dump -U postgres registry > $BACKUP_PATH/harbor_db.sql
# 备份镜像数据
tar -czf $BACKUP_PATH/registry_data.tar.gz /data/registry
# 备份配置文件
cp -r /opt/harbor/common/config $BACKUP_PATH/
cp /opt/harbor/harbor.yml $BACKUP_PATH/
# 备份证书
cp -r /data/cert $BACKUP_PATH/
# 启动 Harbor
docker-compose up -d
# 清理旧备份(保留7天)
find $BACKUP_DIR -name "harbor_backup_*" -mtime +7 -exec rm -rf {} \;
echo "Backup completed: $BACKUP_PATH"
恢复流程
#!/bin/bash
# Harbor 恢复脚本
BACKUP_PATH=$1
if [ -z "$BACKUP_PATH" ]; then
echo "Usage: $0 <backup_path>"
exit 1
fi
# 停止 Harbor
cd /opt/harbor
docker-compose down
# 恢复数据库
sudo -u postgres psql -U postgres -d registry < $BACKUP_PATH/harbor_db.sql
# 恢复镜像数据
tar -xzf $BACKUP_PATH/registry_data.tar.gz -C /
# 恢复配置文件
cp -r $BACKUP_PATH/config/* /opt/harbor/common/config/
cp $BACKUP_PATH/harbor.yml /opt/harbor/
# 恢复证书
cp -r $BACKUP_PATH/cert /data/
# 重新生成配置
./prepare
# 启动 Harbor
docker-compose up -d
echo "Restore completed from: $BACKUP_PATH"
灾难恢复
灾备方案
# 主备架构
主站点 (Active):
- Harbor 主实例
- 实时数据同步
- 自动故障检测
备站点 (Standby):
- Harbor 备实例
- 数据同步接收
- 快速接管能力
同步机制:
- 数据库: PostgreSQL 流复制
- 镜像: Harbor 原生复制
- 配置: rsync 同步
RTO: < 30分钟
RPO: < 5分钟
升级策略
版本升级
升级前准备
# 1. 检查当前版本
docker images | grep harbor
# 2. 查看升级路径
# https://github.com/goharbor/harbor/releases
# 3. 备份当前系统
./backup_harbor.sh
# 4. 下载新版本
wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz
滚动升级
#!/bin/bash
# Harbor 滚动升级脚本
# 停止当前版本
cd /opt/harbor
docker-compose down
# 备份当前安装目录
mv /opt/harbor /opt/harbor_backup
# 解压新版本
tar xvf harbor-offline-installer-v2.9.1.tgz -C /opt/
# 复制配置文件
cp /opt/harbor_backup/harbor.yml /opt/harbor/
# 执行迁移
cd /opt/harbor
./migrate
# 准备新配置
./prepare
# 启动新版本
docker-compose up -d
# 验证升级
docker-compose ps
curl -k https://localhost/api/v2.0/systeminfo
回滚方案
# 快速回滚脚本
#!/bin/bash
# 停止当前版本
cd /opt/harbor
docker-compose down
# 恢复旧版本
rm -rf /opt/harbor
mv /opt/harbor_backup /opt/harbor
# 启动旧版本
cd /opt/harbor
docker-compose up -d
# 验证回滚
docker-compose ps
Kubernetes 集成
Helm Chart 仓库
启用 ChartMuseum
# 安装时启用 ChartMuseum
./install.sh --with-chartmuseum
# 推送 Chart
helm package mychart/
helm plugin install https://github.com/chartmuseum/helm-push
helm repo add harbor https://harbor.example.com/chartrepo/myproject
helm push mychart-0.1.0.tgz harbor
镜像拉取凭证
创建 Pull Secret
# 创建 Harbor 凭证
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.example.com \
--docker-username=admin \
--docker-password=Harbor12345 \
--docker-email=admin@example.com \
-n default
# 在 Pod 中使用
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: app
image: harbor.example.com/myproject/myapp:v1
imagePullSecrets:
- name: harbor-secret
准入控制
配置准入 Webhook
# admission-webhook.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: harbor-webhook
webhooks:
- name: harbor.example.com
clientConfig:
service:
name: harbor-webhook
namespace: harbor-system
path: "/validate"
caBundle: LS0tLS1CRUdJTi...
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
failurePolicy: Fail
namespaceSelector:
matchLabels:
harbor-validation: enabled
Operator 集成
Harbor Operator 部署
# 安装 Harbor Operator
helm repo add harbor https://goharbor.github.io/harbor-operator
helm install harbor-operator harbor/harbor-operator \
--namespace harbor-system \
--create-namespace
# 创建 Harbor 实例
cat <<EOF | kubectl apply -f -
apiVersion: goharbor.io/v1beta1
kind: HarborCluster
metadata:
name: harbor-cluster
namespace: harbor-system
spec:
version: 2.9.1
adminPasswordRef: "harbor-admin-secret"
expose:
type: LoadBalancer
loadBalancer:
hosts:
- harbor.example.com
storage:
kind: S3
s3:
bucket: harbor-storage
region: us-east-1
EOF
监控和日志
监控指标
Prometheus 集成
# harbor.yml 配置
metric:
enabled: true
port: 9090
path: /metrics
# Prometheus 配置
scrape_configs:
- job_name: 'harbor'
scrape_interval: 20s
static_configs:
- targets: ['harbor.example.com:9090']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'harbor_(.*)|registry_(.*)'
action: keep
Grafana Dashboard
{
"dashboard": {
"title": "Harbor Metrics",
"panels": [
{
"title": "项目数量",
"targets": [
{
"expr": "harbor_project_total"
}
]
},
{
"title": "镜像拉取次数",
"targets": [
{
"expr": "rate(registry_http_requests_total{handler="blob"}[5m])"
}
]
},
{
"title": "存储使用量",
"targets": [
{
"expr": "harbor_project_quota_usage_bytes"
}
]
}
]
}
}
日志管理
日志配置
# harbor.yml 日志配置
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
external_endpoint:
protocol: tcp
host: logstash.example.com
port: 5140
ELK 集成
# Logstash 配置
input {
syslog {
port => 5140
type => "harbor"
}
}
filter {
if [type] == "harbor" {
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}"
}
}
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "harbor-%{+YYYY.MM.dd}"
}
}
告警配置
AlertManager 规则
# Prometheus 告警规则
groups:
- name: harbor_alerts
rules:
- alert: HarborDown
expr: up{job="harbor"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Harbor is down"
description: "Harbor instance {{ $labels.instance }} is down"
- alert: HarborHighStorageUsage
expr: (harbor_project_quota_usage_bytes / harbor_project_quota_bytes) > 0.9
for: 10m
labels:
severity: warning
annotations:
summary: "High storage usage"
description: "Project {{ $labels.project }} storage usage is above 90%"
- alert: HarborReplicationFailed
expr: harbor_replication_status{status="failed"} > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Replication failed"
description: "Replication policy {{ $labels.policy }} failed"
审计日志
审计日志查询
# 查询审计日志
curl -X GET "https://harbor.example.com/api/v2.0/audit-logs?page=1&page_size=10" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)"
# 导出审计日志
curl -X GET "https://harbor.example.com/api/v2.0/audit-logs?q=operation=create&resource_type=artifact" \
-H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
> audit_logs_$(date +%Y%m%d).json
最佳实践
性能优化
存储优化
# 1. 启用存储驱动的删除功能
storage_service:
delete:
enabled: true
# 2. 配置垃圾回收
gc:
scheduled:
cron: "0 2 * * 6" # 每周六凌晨2点
workers: 3
# 3. Redis 优化
external_redis:
max_idle_conns: 100
max_open_conns: 900
conn_timeout: 10s
网络优化
# Nginx 优化配置
http {
client_max_body_size 0; # 禁用大小限制
chunked_transfer_encoding on;
# 连接优化
keepalive_timeout 65;
keepalive_requests 100;
# 缓冲区优化
client_body_buffer_size 128k;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
}
安全加固
安全配置清单
# 1. 启用 HTTPS
# 2. 配置强密码策略
# 3. 启用审计日志
# 4. 配置网络隔离
# 5. 定期更新和打补丁
# 6. 启用镜像扫描
# 7. 配置 RBAC
# 8. 启用内容信任
# 9. 配置资源配额
# 10. 定期备份
# 安全扫描策略
防止推送有漏洞的镜像: true
漏洞严重性阈值: Medium
自动扫描: true
CVE 白名单: 配置已知安全的 CVE
容量规划
存储容量估算
镜像数量: 1000
平均镜像大小: 500MB
镜像层重复率: 30%
保留版本数: 5
所需存储 = 1000 * 500MB * (1-0.3) * 5 = 1.75TB
建议预留 = 1.75TB * 2 = 3.5TB
性能容量规划
| 用户规模 | CPU | 内存 | 存储 | 带宽 |
|---|---|---|---|---|
| < 100 | 4核 | 8GB | 500GB | 100Mbps |
| 100-500 | 8核 | 16GB | 2TB | 1Gbps |
| 500-1000 | 16核 | 32GB | 5TB | 10Gbps |
| > 1000 | 32核+ | 64GB+ | 10TB+ | 10Gbps+ |
运维建议
日常运维检查清单
#!/bin/bash
# Harbor 健康检查脚本
# 1. 检查服务状态
echo "=== 检查服务状态 ==="
docker-compose ps
# 2. 检查存储使用
echo "=== 存储使用情况 ==="
df -h /data
# 3. 检查数据库连接
echo "=== 数据库状态 ==="
docker-compose exec postgresql pg_isready
# 4. 检查 API 健康状态
echo "=== API 健康检查 ==="
curl -s https://localhost/api/v2.0/health | jq .
# 5. 检查复制任务
echo "=== 复制任务状态 ==="
curl -s -u admin:Harbor12345 https://localhost/api/v2.0/replication/executions?page_size=5 | jq '.[] | {id, status, start_time}'
# 6. 检查扫描任务
echo "=== 扫描任务队列 ==="
docker-compose exec jobservice redis-cli -h redis llen scan_job
常见问题
安装问题
Q: 安装时提示端口被占用
# 解决方案
# 1. 查找占用端口的进程
sudo lsof -i :80
sudo lsof -i :443
# 2. 修改 harbor.yml 端口配置
http:
port: 8080
https:
port: 8443
Q: 安装时 Docker 版本不兼容
# 升级 Docker
curl -fsSL https://get.docker.com | bash
# 升级 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
推拉镜像问题
Q: 推送镜像时认证失败
# 1. 检查用户名密码
docker logout harbor.example.com
docker login harbor.example.com
# 2. 检查证书配置
mkdir -p /etc/docker/certs.d/harbor.example.com
cp ca.crt /etc/docker/certs.d/harbor.example.com/
# 3. 重启 Docker
systemctl restart docker
Q: 拉取镜像速度慢
# 1. 配置镜像代理
项目设置 -> 镜像代理 -> 添加 Docker Hub 代理
# 2. 使用就近的 Harbor 实例
# 3. 启用 P2P 分发(Dragonfly)
性能问题
Q: Web UI 响应慢
# 1. 检查数据库性能
docker-compose exec postgresql psql -U postgres -c "SELECT pg_database.datname, pg_size_pretty(pg_database_size(pg_database.datname)) AS size FROM pg_database;"
# 2. 优化 Redis
docker-compose exec redis redis-cli INFO memory
# 3. 增加资源限制
services:
core:
deploy:
resources:
limits:
cpus: '2'
memory: 4G
集成问题
Q: Kubernetes 无法拉取私有镜像
# 1. 创建 Secret
kubectl create secret docker-registry regcred \
--docker-server=harbor.example.com \
--docker-username=robot$k8s \
--docker-password=<token>
# 2. 配置 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: harbor-sa
imagePullSecrets:
- name: regcred
# 3. 在 Pod 中使用
spec:
serviceAccountName: harbor-sa
相关文章
- Docker 基本命令
- Docker 环境部署
- Kubernetes 集群部署
- Nginx 配置指南
- PostgreSQL 数据库管理
- Redis 配置与优化
- ELK Stack 日志分析
- Prometheus 监控系统