全部笔记All notes

Harbor 企业级容器镜像仓库部署与管理指南

阅读 17m 29s17m 29s read

概述

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: 镜像安全扫描器

主要特点

  1. 基于角色的访问控制(RBAC)

    • 多租户支持
    • 细粒度的权限管理
    • 项目级别的访问控制
  2. 镜像安全扫描

    • 集成 Trivy/Clair 扫描器
    • 自动扫描推送的镜像
    • 漏洞报告和修复建议
  3. 镜像签名

    • 内容信任(Content Trust)
    • Notary 集成
    • 确保镜像完整性
  4. 审计日志

    • 完整的操作记录
    • 合规性支持
    • 日志导出和分析
  5. 镜像复制

    • 多数据中心同步
    • 支持多种复制模式
    • 带宽优化
  6. Helm Chart 支持

    • Chart 仓库功能
    • 版本管理
    • 依赖解析

使用场景

  1. 企业私有镜像仓库

    • 统一管理企业内部镜像
    • 安全隔离和访问控制
    • 合规性要求
  2. CI/CD 集成

    • 与 Jenkins、GitLab CI 等集成
    • 自动化构建和推送
    • 镜像版本管理
  3. 多数据中心部署

    • 跨地域镜像同步
    • 就近访问优化
    • 灾备和高可用
  4. 开发测试环境

    • 快速部署测试环境
    • 版本回滚
    • 资源隔离

安装部署

系统要求

硬件要求:

资源最小配置推荐配置
CPU2 核4 核
内存4 GB8 GB
磁盘40 GB160 GB

软件要求:

  • Docker version 17.06.0-ce+ 或更高版本
  • Docker Compose version 1.18.0 或更高版本
  • OpenSSL 最新版本(用于生成证书)

端口要求:

端口协议描述
443HTTPSHarbor portal 和 core API 使用此端口
4443HTTPS仅在启用 Notary 时使用此端口
80HTTPHarbor portal 和 core API 使用此端口

在线安装

在线安装步骤

  1. 下载在线安装包
# 下载最新版本(推荐)
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
  1. 配置 harbor.yml
# 复制配置模板
cp harbor.yml.tmpl harbor.yml

# 编辑配置文件
vim harbor.yml
  1. 执行安装脚本
# 安装 Harbor
sudo ./install.sh

# 带组件安装(推荐)
sudo ./install.sh --with-trivy --with-chartmuseum

离线安装

离线安装步骤

  1. 下载离线安装包
# 下载离线安装包(包含所有镜像)
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
  1. 加载镜像
# 离线包会自动加载镜像
# 如需手动加载
docker load -i harbor.v2.9.1.tar.gz
  1. 配置和安装
# 复制配置文件
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  │
│     └──────────┘    └──────────┘    └──────────┘
└────────────────────────────────────────────────┘

高可用部署步骤

  1. 准备共享存储
# 配置 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
  1. 部署外部数据库
# 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
  1. 配置 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 镜像部署

  1. 下载 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
  1. 自定义配置
# 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
  1. 启动服务
# 启动 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

项目和镜像管理

创建项目

项目类型说明

  1. 公开项目:任何用户都可以拉取镜像
  2. 私有项目:只有项目成员可以拉取镜像

创建项目示例

# 使用 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 集成

配置步骤

  1. 登录管理界面
  2. 配置 -> 认证 -> LDAP
  3. 填写 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)"

备份恢复

备份策略

备份内容

  1. 数据库备份:PostgreSQL 数据
  2. 镜像存储备份:Registry 数据
  3. 配置文件备份:harbor.yml 等
  4. 证书备份: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内存存储带宽
< 1004核8GB500GB100Mbps
100-5008核16GB2TB1Gbps
500-100016核32GB5TB10Gbps
> 100032核+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

相关文章