Instalación Harbor
Los requisitos de instalación dependen del tamaño. Lo recomendado es 4 vCPUs y 160GB de disco para repositorios mayores, pero para un propósito menor 2 vCPUs es suficiente y el espacio es bueno usar al menos unos 100GB, pero debe tenerse en consideración la cantidad de tags que se desea mantener por imagen, tamaño de las imágenes y variedad.
Harbor se despliega como contenedor, por lo que es necesario que el host tenga un container runtime disponible. Para instalación en máquinas exclusivas es necesario tener Docker y Docker Compose pues el instalador necesitará de estos recursos.
Los puertos utilizados son los estándar 80 para HTTP y 443 para HTTPS.
Instalación en el Host
Si quieres instalar directamente en el host es necesario descargar los archivos de instalación en release harbor, extraer y ejecutar el install.
# Cambia la versión si es necesario
wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-online-installer-v2.11.1.tgz
tar -xzvf harbor-online-installer-v2.11.1.tgz
# No ejecutes aún, lee antes lo que está abajo
sudo ./harbor/install.sh --with-trivy
Para un entorno en producción será necesario configurar HTTPS y para mejorar la seguridad habilitar el internal TLS entre los componentes internos de Harbor.
El install buscará las preferencias de la instalación en el archivo harbor.yml. Si no existe, seguirá con los parámetros por defecto. Si necesitas cambiar algo, utiliza la plantilla disponible para definir el harbor.yml.
Voy a eliminar algo de configuración y dejar las partes más importantes. Consulta el archivo completo cuando vayas a instalar.
cat harbor.yml.tmpl
# Archivo de configuración de Harbor
hostname: reg.mydomain.com
# configuración relacionada con http
http:
port: 80
https:
port: 443
# La ruta de los archivos cert y key para nginx
certificate: /your/certificate/path
private_key: /your/private/key/path
# habilitar cifrados ssl fuertes (por defecto: false)
# strong_ssl_ciphers: false
###### INTERNAL TLS #####
# internal_tls:
# # establecer enabled en true significa que internal tls está habilitado
# enabled: true
# # coloca tus archivos cert y key en el directorio
# dir: /etc/harbor/tls/internal
##### CONTRASEÑA INICIAL #####
harbor_admin_password: Harbor12345
##### CONFIGURACIÓN DE LA BASE DE DATOS #####
database:
password: root123
max_idle_conns: 100
max_open_conns: 900
conn_max_lifetime: 5m
conn_max_idle_time: 0
##### CONFIGURACIÓN DE ALMACENAMIENTO #####
data_volume: /data
# storage_service:
# ca_bundle:
# filesystem:
# maxthreads: 100
# redirect:
# disable: false
##### CONFIGURACIÓN DE TRIVY #####
# Configuración de Trivy
trivy:
ignore_unfixed: false
skip_update: false
skip_java_db_update: false
offline_scan: false
security_check: vuln
insecure: false
timeout: 5m0s
# github_token: xxx
##### CONFIGURACIÓN DE CONCURRENCIA #####
jobservice:
max_job_workers: 10
job_loggers:
- STD_OUTPUT
- FILE
logger_sweeper_duration: 1 #días
notification:
webhook_job_max_retry: 3
webhook_job_http_client_timeout: 3
##### CONFIGURACIÓN DE LOGS #####
log:
level: info #debug, info, warning, error, fatal
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
# external_endpoint:
# protocol: tcp
# host: localhost
# port: 5140
_version: 2.11.0
#### SI USAS UNA BASE DE DATOS EXTERNA #####
# 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
#### PERSONALIZACIÓN DE REDIS #####
# redis:
# # registry_db_index: 1
# # jobservice_db_index: 2
# # trivy_db_index: 5
# # harbor_db_index: 6
# # cache_layer_db_index: 7
# external_redis:
# host: redis:6379
# # password:
# # username:
# #sentinel_master_set:
# registry_db_index: 1
# jobservice_db_index: 2
# trivy_db_index: 5
# idle_timeout_seconds: 30
# # harbor_db_index: 6
# # cache_layer_db_index: 7
##### CONFIGURACIÓN DE CACHÉ #####
cache:
# no habilitado por defecto
enabled: false
# mantener caché por un día por defecto
expire_hours: 24
Instalación en Kubernetes
En Kubernetes tenemos un Helm chart para auxiliar y hacer todo más fácil.
helm repo add harbor https://helm.goharbor.io
helm repo update
helm fetch harbor/harbor --untar
ls harbor
total 252K
drwxr-xr-x 1 david david 114 oct 24 10:41 .
drwxr-x--- 1 david david 1,4K oct 24 10:41 ..
-rw-r--r-- 1 david david 637 oct 24 10:41 Chart.yaml
-rw-r--r-- 1 david david 57 oct 24 10:41 .helmignore
-rw-r--r-- 1 david david 12K oct 24 10:41 LICENSE
-rw-r--r-- 1 david david 190K oct 24 10:41 README.md
drwxr-xr-x 1 david david 204 oct 24 10:41 templates
-rw-r--r-- 1 david david 38K oct 24 10:41 values.yaml
Todas las configuraciones ahora estarán en values.yaml para ajustes.
Si vas a hacer la instalación en un cluster local para estudio utiliza kind con la siguiente configuración.
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: "study"
networking:
ipFamily: ipv4
# disableDefaultCNI: true
kubeProxyMode: "ipvs"
podSubnet: "10.244.0.0/16"
serviceSubnet: "10.96.0.0/12"
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
- role: worker
- role: worker
- role: worker
Esta configuración es importante pues sin ella, el pod nginx interno de harbor no se levantará.
Aplicando el helm tenemos
helm install harbor harbor/harbor --namespace harbor --create-namespace --set expose.type=clusterIP --set expose.tls.enabled=false
NAME: harbor
LAST DEPLOYED: Thu Oct 24 22:56:08 2024
NAMESPACE: harbor
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://core.harbor.domain
For more details, please visit https://github.com/goharbor/harbor
# Recursos creados
kubectl get all -n harbor
NAME READY STATUS RESTARTS AGE
pod/harbor-core-956b455c5-dvshj 1/1 Running 0 6m37s
pod/harbor-database-0 1/1 Running 0 6m37s
pod/harbor-jobservice-cb67f855c-6dhbc 1/1 Running 3 (6m1s ago) 6m37s
pod/harbor-nginx-6cbd4bc77d-8chh9 1/1 Running 0 6m37s
pod/harbor-portal-5cc9d5cc7-czq55 1/1 Running 0 6m37s
pod/harbor-redis-0 1/1 Running 0 6m37s
pod/harbor-registry-86bd7dd86c-tntsk 2/2 Running 0 6m37s
pod/harbor-trivy-0 1/1 Running 0 6m37s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/harbor ClusterIP 10.98.62.126 <none> 80/TCP 6m37s
service/harbor-core ClusterIP 10.110.208.69 <none> 80/TCP 6m37s
service/harbor-database ClusterIP 10.97.47.50 <none> 5432/TCP 6m37s
service/harbor-jobservice ClusterIP 10.104.191.97 <none> 80/TCP 6m37s
service/harbor-portal ClusterIP 10.96.187.79 <none> 80/TCP 6m37s
service/harbor-redis ClusterIP 10.97.190.109 <none> 6379/TCP 6m37s
service/harbor-registry ClusterIP 10.97.250.10 <none> 5000/TCP,8080/TCP 6m37s
service/harbor-trivy ClusterIP 10.110.193.106 <none> 8080/TCP 6m37s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/harbor-core 1/1 1 1 6m37s
deployment.apps/harbor-jobservice 1/1 1 1 6m37s
deployment.apps/harbor-nginx 1/1 1 1 6m37s
deployment.apps/harbor-portal 1/1 1 1 6m37s
deployment.apps/harbor-registry 1/1 1 1 6m37s
NAME DESIRED CURRENT READY AGE
replicaset.apps/harbor-core-956b455c5 1 1 1 6m37s
replicaset.apps/harbor-jobservice-cb67f855c 1 1 1 6m37s
replicaset.apps/harbor-nginx-6cbd4bc77d 1 1 1 6m37s
replicaset.apps/harbor-portal-5cc9d5cc7 1 1 1 6m37s
replicaset.apps/harbor-registry-86bd7dd86c 1 1 1 6m37s
NAME READY AGE
statefulset.apps/harbor-database 1/1 6m37s
statefulset.apps/harbor-redis 1/1 6m37s
statefulset.apps/harbor-trivy 1/1 6m37s
Tenemos la base de datos, Redis y Trivy como StatefulSet y el conjunto de pods que forman Harbor (core, nginx, portal, registry, jobservice) como Deployments.
El service que necesitamos hacer un port-forward es el service/harbor; el resto de los services son endpoints para comunicación entre los pods.
Como no alteramos nada en el values.yaml, los datos para login son username=admin y password=Harbor12345.

Y tenemos nuestro sistema.

Es claro que el values.yaml necesita ser ajustado para producción, con una externalURL válida, certificados válidos, etc.
Configuraciones Globales
Un proyecto posee varios repositorios. No creo que sea buena práctica permitir que cualquier usuario pueda crear un proyecto, a no ser que la cuota sea muy pequeña. Generalmente lo que veo es el administrador creando los proyectos y definiendo mantenedores.
Es posible transformar todos los proyectos en solo lectura de una única vez marcando en las opciones de configuraciones globales.
Esto puede ser una solución para quien tiene varias instancias de Harbor, siendo una para producción que sufre sincronización con una de staging, por ejemplo.
