说明
harbor是当前主流的私有容器镜像仓库方案,开源。功能丰富,能满足大多数业务需求。可在离线环境为其他用户提供容器镜像。
本文以离线部署为例。
设计规划
应对以下资源做设计规划
计算。最低配置2C4G,推荐4C8G及更高版本。
存储。根据业务使用的容量预估,可动态扩容,满足未来业务需求。大多大于200GB。
操作系统。能承载容器均可,可以选择Ubuntu24LTS及更高版本。
网络。访问者能与harbor所在主机网络直达即可。
部署环境。Docker和k8s环境均可。在k8s环境支持集群高可用架构。本文采用Docker环境。
域名。应准备一个专用于harbor的域名用于地址解析,例如主域名a.com,容器仓库域名是harbor.a.com,推荐配置https。若已有TLS证书,可参考https://goharbor.io/docs/
主机名。推荐配置为harbor,不改也可以。
部署Docker
参考https://docs.docker.com/engine/install/
需配置数据存放在可动态扩展的大容量磁盘。选择最新版Docker,并部署完整组件。可参考离线部署部分,下载文件,复制到部署环境。
下载harbor
浏览器访问https://github.com/goharbor/harbor/releases,下载最新版本,推荐使用离线部署文件,带有offline字样。复制到部署环境。
准备云主机
Ubuntu24 LTS,amd64 架构CPU,硬盘500GB可动态扩容,离线环境,无互联网。
配置主机名-可选
不影响harbor的使用。
bash
hostnamectl set-hostname harbor
配置磁盘和目录
配置专用磁盘和目录。vdc是本次专用磁盘。
bash
# 查询磁盘
root@harbor:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda 253:0 0 200G 0 disk
├─vda1 253:1 0 512M 0 part /boot/efi
└─vda2 253:2 0 199.5G 0 part /
vdb 253:16 0 8G 0 disk [SWAP]
vdc 253:32 0 500G 0 disk
配置LVM
bash
# 配置PV
pvcreate /dev/vdc
# 配置VG
vgcreate vg_data /dev/vdc
# 配置LV
lvcreate -l 100%FREE -n lv_data vg_data
# xfs和ext4均可。以业务需求为准。
mkfs.ext4 /dev/vg_data/lv_data
挂载专用目录
bash
mkdir /data
vim /etc/fstab
# 追加以下配置
# add data
/dev/vg_data/lv_data /data ext4 defaults 0 0
查询目录
bash
df -hT
lsblk
上传文件
将下载的docker部署文件,harbor部署文件,都上传至目录/data
部署Docker最新完整组件
可创建目录/data/docker,在目录中安装所有上传的软件包
bash
dpkg -i *.deb
优化基础配置,配置指定的数据存储目录,配置日志存储优化,避免日志过多导致磁盘爆满。
bash
vim /etc/docker/daemon.json
# 追加以下配置
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3",
"compress": "true"
},
"data-root": "/data/docker"
}
使配置生效
bash
systemctl daemon-reload
systemctl restart docker
systemctl status docker
配置harbor
在目录/data中解压harbor压缩包,
bash
tar -zxf harbor-offline-installer-$版本号.tgz
可见目录harbor,后续在该目录操作,
启用HTTPS
推荐启用。
若不启用,默认使用http,可单独配置nginx加TLS进行管理。
配置后,可在拉取镜像阶段减少对用户环境的配置。
已有TLS证书的参考官网文档https://goharbor.io/docs/2.14.0/install-config/configure-https/
证书到期之前应主动续期。
配置证书
注意,此处主域名是a.com,harbor域名是harbor.a.com
对证书有定制要求的,可参考https://goharbor.io/docs/2.14.0/install-config/customize-token-service/
创建专用证书目录
bash
mkdir /data/harbor/cert
cd /data/harbor/cert
生成CA私钥
bash
openssl genrsa -out a.ca.key 4096
生成CA证书
bash
openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=MyPersonal Root CA" \
-key a.ca.key \
-out a.ca.crt
配置说明:
O=example是组织名称,例如baidu,一般填写公司名,可默认example。
OU=Personal是部门名称,例如dev,一般填写部门名称,可默认Personal。
CN=MyPersonal Root CA是通用名称,一般填写完整主机名,可默认MyPersonal Root CA。可通过命令hostname -f 查询确认。
-days 3650表示证书有效期10年。
生成服务器证书私钥
bash
openssl genrsa -out harbor.a.com.key 4096
生成服务器证书CSR
bash
openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=a.com" \
-key harbor.a.com.key \
-out harbor.a.com.csr
配置说明
O=example是组织名称,例如baidu,一般填写公司名,可默认example。
OU=Personal是部门名称,例如dev,一般填写部门名称,可默认Personal。
CN=yourdomain.com是通用名称,填写域名。
生成 x509 v3 扩展文件
bash
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.a.com
DNS.2=harbor.a
DNS.3=harbor
EOF
生成服务器证书
bash
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA a.ca.crt -CAkey a.ca.key -CAcreateserial \
-in harbor.a.com.csr \
-out harbor.a.com.crt
生成docker可用证书
bash
openssl x509 -inform PEM -in harbor.a.com.crt -out harbor.a.com.cert
配置docker专用证书目录
若自定义harbor的默认端口是111,需改目录harbor.a.com为harbor.a.com:111
bash
mkdir -p /etc/docker/certs.d/harbor.a.com/
复制文件
bash
cp harbor.a.com.cert harbor.a.com.key a.ca.crt /etc/docker/certs.d/harbor.a.com/
重启使配置生效
bash
systemctl restart docker
若配置异常,需参考https://goharbor.io/docs/2.14.0/install-config/troubleshoot-installation/#https
修改harbor配置文件
bash
# 在目录harbor中
cp harbor.yml.tmpl harbor.yml
vim harbor.yml
配置说明如下所示,仅参考,不可直接复制使用,
bash
# 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.
# harbor的完整域名
hostname: harbor.a.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: /data/harbor/cert/harbor.a.com.crt
private_key: /data/harbor/cert/harbor.a.com.key
# enable strong ssl ciphers (default: false)
# strong_ssl_ciphers: false
# # Harbor will set ipv4 enabled only by default if this block is not configured
# # Otherwise, please uncomment this block to configure your own ip_family stacks
# ip_family:
# # ipv6Enabled set to true if ipv6 is enabled in docker network, currently it affected the nginx related component
# ipv6:
# enabled: false
# # ipv4Enabled set to true by default, currently it affected the nginx related component
# ipv4:
# enabled: true
# # Uncomment following will enable tls communication between all harbor components
# internal_tls:
# # set enabled to true means internal tls is enabled
# enabled: true
# # put your cert and key files on dir
# dir: /etc/harbor/tls/internal
# Uncomment external_url if you want to enable external proxy
# And when it enabled the hostname will no longer used
# external_url: https://reg.mydomain.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 user('postgres' by default) 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.
# Note: the default number of connections is 1024 for postgres of harbor.
max_open_conns: 900
# The maximum amount of time a connection may be reused. Expired connections may be closed lazily before reuse. If it <= 0, connections are not closed due to a connection's age.
# The value is a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
conn_max_lifetime: 5m
# The maximum amount of time a connection may be idle. Expired connections may be closed lazily before reuse. If it <= 0, connections are not closed due to a connection's idle time.
# The value is a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
conn_max_idle_time: 0
# The default data volume
# harbor存储数据的专用目录,务必填写空目录。
data_volume: /data1/harbor
# 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 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://distribution.github.io/distribution/about/configuration/
# # and https://distribution.github.io/distribution/storage-drivers/
# filesystem:
# maxthreads: 100
# # set disable to true when you want to disable registry redirect
# redirect:
# disable: false
# Trivy configuration
#
# Trivy DB contains vulnerability information from NVD, Red Hat, and many other upstream vulnerability databases.
# It is downloaded by Trivy from the GitHub release page https://github.com/aquasecurity/trivy-db/releases and cached
# in the local file system. In addition, the database contains the update timestamp so Trivy can detect whether it
# should download a newer version from the Internet or use the cached one. Currently, the database is updated every
# 12 hours and published as a new release to GitHub.
trivy:
# ignoreUnfixed The flag to display only fixed vulnerabilities
ignore_unfixed: false
# skipUpdate The flag to enable or disable Trivy DB downloads from GitHub
#
# You might want to enable this flag in test or CI/CD environments to avoid GitHub rate limiting issues.
# If the flag is enabled you have to download the `trivy-offline.tar.gz` archive manually, extract `trivy.db` and
# `metadata.json` files and mount them in the `/home/scanner/.cache/trivy/db` path.
skip_update: false
#
# skipJavaDBUpdate If the flag is enabled you have to manually download the `trivy-java.db` file and mount it in the
# `/home/scanner/.cache/trivy/java-db/trivy-java.db` path
skip_java_db_update: false
#
# The offline_scan option prevents Trivy from sending API requests to identify dependencies.
# Scanning JAR files and pom.xml may require Internet access for better detection, but this option tries to avoid it.
# For example, the offline mode will not try to resolve transitive dependencies in pom.xml when the dependency doesn't
# exist in the local repositories. It means a number of detected vulnerabilities might be fewer in offline mode.
# It would work if all the dependencies are in local.
# This option doesn't affect DB download. You need to specify "skip-update" as well as "offline-scan" in an air-gapped environment.
offline_scan: false
#
# Comma-separated list of what security issues to detect. Possible values are `vuln`, `config` and `secret`. Defaults to `vuln`.
security_check: vuln
#
# insecure The flag to skip verifying registry certificate
insecure: false
#
# timeout The duration to wait for scan completion.
# There is upper bound of 30 minutes defined in scan job. So if this `timeout` is larger than 30m0s, it will also timeout at 30m0s.
timeout: 5m0s
#
# github_token The GitHub access token to download Trivy DB
#
# Anonymous downloads from GitHub are subject to the limit of 60 requests per hour. Normally such rate limit is enough
# for production operations. If, for any reason, it's not enough, you could increase the rate limit to 5000
# requests per hour by specifying the GitHub access token. For more details on GitHub rate limiting please consult
# https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting
#
# You can create a GitHub token by following the instructions in
# https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line
#
# github_token: xxx
jobservice:
# Maximum number of job workers in job service
max_job_workers: 10
# Maximum hours of task duration in job service, default 24
max_job_duration_hours: 24
# The jobLoggers backend name, only support "STD_OUTPUT", "FILE" and/or "DB"
job_loggers:
- STD_OUTPUT
- FILE
# - DB
# The jobLogger sweeper duration (ignored if `jobLogger` is `stdout`)
logger_sweeper_duration: 1 #days
notification:
# Maximum retry count for webhook job
webhook_job_max_retry: 3
# HTTP client timeout for webhook job
webhook_job_http_client_timeout: 3 #seconds
# 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
# 建议和harbor数据存放一起,便于管理
location: /data1/harbor/logs
# 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.14.0
# Uncomment external_database if using external database.
# external_database:
# harbor:
# host: harbor_db_host
# port: harbor_db_port
# db_name: harbor_db_name
# username: harbor_db_username
# password: harbor_db_password
# ssl_mode: disable
# max_idle_conns: 2
# max_open_conns: 0
# Uncomment redis if need to customize redis db
# redis:
# # db_index 0 is for core, it's unchangeable
# # registry_db_index: 1
# # jobservice_db_index: 2
# # trivy_db_index: 5
# # it's optional, the db for harbor business misc, by default is 0, uncomment it if you want to change it.
# # harbor_db_index: 6
# # it's optional, the db for harbor cache layer, by default is 0, uncomment it if you want to change it.
# # cache_layer_db_index: 7
# 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:
# # Redis AUTH command was extended in Redis 6, it is possible to use it in the two-arguments AUTH <username> <password> form.
# # there's a known issue when using external redis username ref:https://github.com/goharbor/harbor/issues/18892
# # if you care about the image pull/push performance, please refer to this https://github.com/goharbor/harbor/wiki/Harbor-FAQs#external-redis-username-password-usage
# # username:
# # sentinel_master_set must be set to support redis+sentinel
# #sentinel_master_set:
# # tls configuration for redis connection
# # only server-authentication is supported
# # mtls for redis connection is not supported
# # tls connection will be disable by default
# tlsOptions:
# enable: false
# # if it is a self-signed ca, please set the ca path specifically.
# rootCA:
# # db_index 0 is for core, it's unchangeable
# registry_db_index: 1
# jobservice_db_index: 2
# trivy_db_index: 5
# idle_timeout_seconds: 30
# # it's optional, the db for harbor business misc, by default is 0, uncomment it if you want to change it.
# # harbor_db_index: 6
# # it's optional, the db for harbor cache layer, by default is 0, uncomment it if you want to change it.
# # cache_layer_db_index: 7
# 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.
# Remove component from `components` array if want disable proxy
# for it. If you want use proxy for replication, MUST enable proxy
# for core and jobservice, and set `http_proxy` and `https_proxy`.
# Add domain to the `no_proxy` field, when you want disable proxy
# for some special registry.
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 agetn 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 differentiate 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 is in seconds
# # timeout: 10
# 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
# Cache layer configurations
# If this feature enabled, harbor will cache the resource
# `project/project_metadata/repository/artifact/manifest` in the redis
# which can especially help to improve the performance of high concurrent
# manifest pulling.
# NOTICE
# If you are deploying Harbor in HA mode, make sure that all the harbor
# instances have the same behaviour, all with caching enabled or disabled,
# otherwise it can lead to potential data inconsistency.
cache:
# not enabled by default
enabled: false
# keep cache for one day by default
expire_hours: 24
# Harbor core configurations
# Uncomment to enable the following harbor core related configuration items.
# core:
# # The provider for updating project quota(usage), there are 2 options, redis or db,
# # by default is implemented by db but you can switch the updation via redis which
# # can improve the performance of high concurrent pushing to the same project,
# # and reduce the database connections spike and occupies.
# # By redis will bring up some delay for quota usage updation for display, so only
# # suggest switch provider to redis if you were ran into the db connections spike around
# # the scenario of high concurrent pushing to same project, no improvement for other scenes.
# quota_update_provider: redis # Or db
启用http
若不启用https,参考本步骤。若已启用,忽略本步骤。
配置说明如下,仅展示差异配置,其他部分与https的配置相同,
bash
...
# https related config
# 注释掉https的配置
# https:
# https port for harbor, default is 443
# port: 443
# The path of cert and key files for nginx
# certificate: /data/cert/a.com.crt
# private_key: /data/cert/a.com.key
# enable strong ssl ciphers (default: false)
# strong_ssl_ciphers: false
...
启用Harbor内部组件间TLS
可选。
有助于增强harbor内部组件通信安全。必须在部署前决定是否启用。
生成证书
bash
docker run -v /:/hostfs goharbor/prepare:v2.14.1 gencert -p /data/harbor/cert/internal
配置说明
goharbor/prepare:v2.14.1是当前环境真实存在的镜像,tag版本务必确认是当前环境在用的。
/data/harbor/cert/internal用于存放证书。
修改harbor配置文件harbor.yml
仅展示差异配置,其他内容不变。
bash
# # Uncomment following will enable tls communication between all harbor components
# 开启功能
internal_tls:
# # set enabled to true means internal tls is enabled
enabled: true
# # put your cert and key files on dir
dir: /data/harbor/cert/internal
部署harbor
bash
./install.sh --with-trivy
等待容器全部启动。
访问测试
部署后,应使用浏览器和终端测试访问harbor。
配置基础环境
访问测试之前,必须配置基础环境。
windows修改文件C:\Windows\System32\drivers\etc\hosts
Linux修改文件/etc/hosts
配置harbor的IP域名映射,IP必须是harbor所在机器的系统IP,
bash
# 私有harbor
192.168.1.10 harbor.a.com
默认账户admin,默认密码Harbor12345
浏览器访问
访问harbor.a.com,登录正常即可。
Docker环境访问
Docker环境必须配置证书,才能正常访问.
若未启用https,需单独配置docker的/etc/docker/daemon.json信任陌生仓库,例如"insecure-registries" : ["harbor.a.com:80", "0.0.0.0"]。
配置证书
Ubuntu环境
将文件harbor.a.com.crt上传到访问者机器的/usr/local/share/ca-certificates/
bash
update-ca-certificates
systemctl restart docker
centos环境
将文件harbor.a.com.crt上传到访问者机器的/etc/pki/ca-trust/source/anchors/
bash
update-ca-trust
systemctl restart docker
访问测试
登录仓库
bash
docker login harbor.a.com
提醒:
退出环境前,必须手动退出登录,避免账户被别人使用推送容器镜像
bash
docker logout harbor.a.com
登录成功后,可以推送一个容器镜像测试,
bash
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.31.4
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.31.4 harbor.a.com/libarary/nginx:1.31.4
docker push harbor.a.com/libarary/nginx:1.31.4
特殊情况
若配置无效,可参考以下方法应急,在访问者机器配置,
bash
mkdir -p /etc/docker/certs.d/habor.a.com
复制harbor机器的a.ca.crt文件到访问者机器的/etc/docker/certs.d/harbor.a.com,重启docker使配置生效,
bash
systemctl restart docker
k8s环境访问
目前k8s常见runtime是containerd,此处以它为例,其他runtime需自行测试。
配置证书
注意,是k8s所有的需要拉取镜像的节点都做配置。
Ubuntu环境
将文件harbor.a.com.crt上传到访问者机器的/usr/local/share/ca-certificates/
bash
update-ca-certificates
systemctl restart containerd
centos环境
将文件harbor.a.com.crt上传到访问者机器的/etc/pki/ca-trust/source/anchors/
bash
update-ca-trust
systemctl restart containerd
bash
mkdir -p /etc/containerd/certs.d/harbor.a.com/
cat > /etc/containerd/certs.d/harbor.a.com/hosts.toml << 'EOF'
server = "https://harbor.a.com"
EOF
访问测试
可以使用nerdctl拉取镜像测试,也可以在k8s部署临时的pod测试镜像拉取。
使用与管理
容器镜像管理
一个项目就是一个仓库,一个项目可以容纳多个容器镜像,一个容器镜像可以存档多个tag。
常用的容器镜像完整名字格式harbor域名/项目名/组件名:版本号,例如harbor.a.com/p1/app1:v1.1.1
将容器镜像直接推送到仓库,不在本地存留,例如
bash
docker buildx imagetools create \
-t harbor.a.com/library/elasticsearch:8.19.20 \
swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/elasticsearch:8.19.20
账户管理
只读账户可用于所有人查询容器镜像,需分配账户给指定的容器仓库,并配置为受限的访问者。
创建用户。管理具体的项目,配置用户权限。