Harbor is an open-source cloud native registry that stores, signs, and scans container images for vulnerabilities. This guide will walk you through the installation of Harbor Image Registry on Kubernetes / OpenShift with Helm Chart. Some of the cool features of Harbor image registry are:
Features of Harbor Registry
- Multi-tenant support
- Security and vulnerability analysis support
- Extensible API and web UI
- Content signing and validation
- Image replication across multiple Harbor instances
- Identity integration and role-based access control
Helm is a command-line interface (CLI) tool that was created to simplify deployment of applications and services to Kubernetes / OpenShift Container Platform clusters. Helm uses a packaging format called charts. A Helm chart is a collection of files that describes Kubernetes resources.
In this tutorial we look at how you can install, and configure Harbor Registry on a Kubernetes cluster.
Step 1: Install Helm 3 on Linux / macOS
Helm is distributed a binary application which means no dependency is required to install it on your Linux / macOS machine:
### Linux ###
sudo curl -L https://mirror.openshift.com/pub/openshift-v4/clients/helm/latest/helm-linux-amd64 -o /usr/local/bin/helm
sudo chmod +x /usr/local/bin/helm
### macOS ###
sudo curl -L https://mirror.openshift.com/pub/openshift-v4/clients/helm/latest/helm-darwin-amd64 -o /usr/local/bin/helm
sudo chmod +x /usr/local/bin/helm
Check the installed version:
$ helm version
version.BuildInfo{Version:"v3.10.2", GitCommit:"50f003e5ee8704ec937a756c646870227d7c8b58", GitTreeState:"clean", GoVersion:"go1.19.3"}
Step 2: Install Harbor using Helm Chart
We’ll need persistent storage on Kubernetes for storing Harbor data. If you don’t have anything configured, check our articles below:
- Configure NFS as Kubernetes Persistent Volume Storage
- How To Deploy Rook Ceph Storage on Kubernetes Cluster
- Deploy and Use OpenEBS Container Storage on Kubernetes
To list storage classes run the commands:
$ kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-01 (default) nfs-provisioner-01 Delete Immediate true 242d
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate true 9d
rook-cephfs rook-ceph.cephfs.csi.ceph.com Delete Immediate true 9d
You can change default class as desired.
Storage_Class=rook-cephfs
kubectl patch storageclass $Storage_Class -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Validate the change using:
$ kubectl get storageclasses
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-01 (default) nfs-provisioner-01 Delete Immediate true 242d
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate true 9d
rook-cephfs (default) rook-ceph.cephfs.csi.ceph.com Delete Immediate true 9d
Then we can remove default flag from initial default storage class.
kubectl patch storageclass nfs-01 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster.
Add Harbor Helm repository:
$ helm repo add harbor https://helm.goharbor.io
"harbor" has been added to your repositories
Update the repository:
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "harbor" chart repository
Update Complete. ⎈Happy Helming!⎈
Configure the chart
The configuration items can be set via –set flag during installation or configured by editing the values.yaml directly.
Extract chart to get values file.
helm fetch harbor/harbor --untar
cd harbor
You can modify the values in the file to suit your installation:
vim values.yaml
See Harbor Helm configuration page for accepted values in different blocks.
Once you’ve customize the file then install Harbor helm chart with custom configurations once done modifying.
$ helm install harbor . -n harbor
NAME: harbor
LAST DEPLOYED: Sat Aug 19 02:27:28 2023
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://harbor.apps.k8s.cloudlabske.io
For more details, please visit https://github.com/goharbor/harbor
You can as well --set
to pass values during Helm installation. See Harbor Helm configuration page
Here is an example with few parameters passed with –set flag.
helm install harbor . \
--set persistence.persistentVolumeClaim.registry.accessMode=ReadWriteMany \
--set persistence.persistentVolumeClaim.jobservice.accessMode=ReadWriteMany \
--set persistence.persistentVolumeClaim.registry.size=50Gi \
--set persistence.persistentVolumeClaim.chartmuseum.size=5Gi \
--set persistence.persistentVolumeClaim.database.size=5Gi \
--set persistence.persistentVolumeClaim.trivy.size=5Gi \
--set externalURL=https://ocr.example.com \
--set expose.ingress.hosts.core=ocr.example.com \
--set expose.ingress.hosts.notary=notary.example.com \
--set harborAdminPassword=H@rb0rAdm \
-n harbor
If you have Nginx Ingress controller, specify its className:
--set expose.ingress.className=nginx
Harbor Admin Password:
--set harborAdminPassword='YourAdminPassword'
Check status to confirm it is deployed:
$ helm status harbor
NAME: harbor
LAST DEPLOYED: Sat Aug 19 02:27:28 2023
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://harbor.apps.k8s.cloudlabske.io
For more details, please visit https://github.com/goharbor/harbor
Updating Hem deployment
If you update parameters in values.yml or add new ones, upgrade helm deployment with the command:
$ helm upgrade harbor . -n harbor
Release "harbor" has been upgraded. Happy Helming!
NAME: harbor
LAST DEPLOYED: Thu Apr 30 11:30:06 2021
NAMESPACE: harbor
STATUS: deployed
REVISION: 2
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://ocr.example.com
For more details, please visit https://github.com/goharbor/harbor.
If you ever want to remove deployment, run:
helm uninstall <name> -n harbor
Using your own SSL certificate
If you sign your certificates you can create secret from the certs and key for use when installing Harbor.
kubectl -n harbor create secret tls harbor-tls-certs --key ./harbor.key --cert ./harbor.crt
Then customized ingress secret name.
expose.certSource=secret
expose.secret.secretName=harbor-tls-certs
expose.secret.notarySecretName=harbor-tls-certs
Fixing Init:CrashLoopBackOff on harbor-harbor-database-0 on OpenShift
Some container images such as postgres and redis require root access and have certain expectations about how volumes are owned. We need relax the security in the cluster so that images are not forced to run as a pre-allocated UID, without granting everyone access to the privileged SCC:
Grant all harbor authenticated user access to the anyuid SCC:
oc adm policy add-scc-to-user anyuid system:serviceaccount:harbor:default
Check your deployments status:
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
harbor-harbor-chartmuseum 1/1 1 1 24m
harbor-harbor-clair 1/1 1 1 24m
harbor-harbor-core 1/1 1 1 24m
harbor-harbor-jobservice 1/1 1 1 24m
harbor-harbor-notary-server 1/1 1 1 24m
harbor-harbor-notary-signer 1/1 1 1 24m
harbor-harbor-portal 1/1 1 1 24m
harbor-harbor-registry 1/1 1 1 24m
Check pod status:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
harbor-harbor-chartmuseum-58f8647f95-mtmmf 1/1 Running 0 5m16s
harbor-harbor-clair-654dcfd8bf-77qs6 2/2 Running 0 5m16s
harbor-harbor-core-5cb85989d6-r7s84 1/1 Running 0 5m16s
harbor-harbor-database-0 1/1 Running 0 5m33s
harbor-harbor-jobservice-fc54cf784-lv864 1/1 Running 0 5m16s
harbor-harbor-notary-server-65d8fb7c77-xgxvg 1/1 Running 0 5m16s
harbor-harbor-notary-signer-66c9db4cf4-5bwvh 1/1 Running 0 5m16s
harbor-harbor-portal-5cbc6d5897-r5wzh 1/1 Running 0 25m
harbor-harbor-redis-0 1/1 Running 0 5m16s
harbor-harbor-registry-7ff65976f4-sgnnd 2/2 Running 0 5m16s
Lastly confirm Services and ingress are created.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
harbor-harbor-chartmuseum ClusterIP 172.30.161.108 <none> 80/TCP 26m
harbor-harbor-clair ClusterIP 172.30.133.154 <none> 8080/TCP 26m
harbor-harbor-core ClusterIP 172.30.29.180 <none> 80/TCP 26m
harbor-harbor-database ClusterIP 172.30.199.219 <none> 5432/TCP 26m
harbor-harbor-jobservice ClusterIP 172.30.86.18 <none> 80/TCP 26m
harbor-harbor-notary-server ClusterIP 172.30.188.135 <none> 4443/TCP 26m
harbor-harbor-notary-signer ClusterIP 172.30.165.7 <none> 7899/TCP 26m
harbor-harbor-portal ClusterIP 172.30.41.233 <none> 80/TCP 26m
harbor-harbor-redis ClusterIP 172.30.101.107 <none> 6379/TCP 26m
harbor-harbor-registry ClusterIP 172.30.112.213 <none> 5000/TCP,8080/TCP 26m
$ kubectl get ing
NAME HOSTS ADDRESS PORTS AGE
harbor-harbor-ingress core.harbor.domain,notary.harbor.domain 80, 443 26m
Since I’m actually doing this deployment on OpenShift, I’ll have routes created.
$ kubectl get route
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
harbor-harbor-ingress-7f9vg notary.harbor.domain / harbor-harbor-notary-server 4443 edge/Redirect None
harbor-harbor-ingress-9pvvz core.harbor.domain / harbor-harbor-portal 8080 edge/Redirect None
harbor-harbor-ingress-d7mcn core.harbor.domain /c/ harbor-harbor-core 8080 edge/Redirect None
harbor-harbor-ingress-gn5w6 core.harbor.domain /chartrepo/ harbor-harbor-core 8080 edge/Redirect None
harbor-harbor-ingress-jf48l core.harbor.domain /service/ harbor-harbor-core 8080 edge/Redirect None
harbor-harbor-ingress-lhbx4 core.harbor.domain /api/ harbor-harbor-core 8080 edge/Redirect None
harbor-harbor-ingress-vtt8v core.harbor.domain /v2/ harbor-harbor-core 8080 edge/Redirect None
A number of persistent volume claims are created as well. Matching the values of size you specified.
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-harbor-harbor-redis-0 Bound pvc-1de4a5b2-d55a-48cc-b8b6-1b258214260c 1Gi RWO ocs-storagecluster-cephfs 29m
database-data-harbor-harbor-database-0 Bound pvc-9754adde-e2bd-40ee-b18b-d72eacfdfc12 1Gi RWO ocs-storagecluster-cephfs 29m
harbor-harbor-chartmuseum Bound pvc-3944fce8-ecee-4bec-b0f6-cc5da3b30572 5Gi RWO ocs-storagecluster-cephfs 29m
harbor-harbor-jobservice Bound pvc-5ecf0be4-002c-4628-8dcc-283e996175bc 1Gi RWO ocs-storagecluster-cephfs 29m
harbor-harbor-registry Bound pvc-072358e9-06f2-4384-b7d6-88e97eb29499 5Gi RWO ocs-storagecluster-cephfs 29m
Step 3: Access Harbor Administration dashboard
Use the external Domain configured during installation to access the Harbor container registry dashboard.
Default logins if you didn’t change password are:
Username: admin
Password: Harbor12345 # If you did set manually use the password
Don’t forget to change your password after first login.
Step 4: Add Pull Secret to Kubernetes / OpenShift
Follow the steps in the guide below to add pull secret to Kubernetes / OpenShift.
Similar guides: