You can support us by downloading this article as PDF from the Link below. Download the guide as PDF

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.

OpenShift Courses:

Practical OpenShift for Developers – New Course 2021

Ultimate Openshift (2021) Bootcamp by School of Devops

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 -o /usr/local/bin/helm
sudo chmod +x /usr/local/bin/helm

--- macOS ---
sudo curl -L -o /usr/local/bin/helm
sudo chmod +x /usr/local/bin/helm

Check the installed version:

$ helm version
version.BuildInfo{Version:"v3.1+unreleased", GitCommit:"7ebdbb86fca32c77f2fce166f7f9e58ebf7e9946", GitTreeState:"clean", GoVersion:"go1.13.4"}

Step 2: Install Harbor Helm Chart on Kubernetes / OpenShift Cluster

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
"harbor" has been added to your repositories

Update the repository:

$ helm repo update

Configure the chart

The configuration items can be set via –set flag during installation or configured by editing the values.yaml directly.

See Harbor Helm configuration page

You can download default values.yaml file.

vim values.yaml

Customize the file to set your desired values then install Harbor helm chart with custom configurations once done modifying.

$ helm install harbor harbor/harbor -f values.yaml -n harbor
NAME: harbor
LAST DEPLOYED: Wed Apr  1 19:20:07 2020
STATUS: deployed
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at
For more details, please visit

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 harbor/harbor \
--set persistence.persistentVolumeClaim.registry.accessMode=ReadWriteMany \
--set persistence.persistentVolumeClaim.registry.size=50Gi \
--set persistence.persistentVolumeClaim.chartmuseum.size=5Gi \
--set persistence.persistentVolumeClaim.database.size=5Gi \
--set externalURL= \
--set \
--set \
--set [email protected] \
-n harbor

Check status to confirm it is deployed:

$ helm status harbor

Updating Hem deployment

If you update parameters in values.yml or add new ones, upgrade helm deployment with the command:

$ helm upgrade harbor harbor/harbor -f values.yml -n harbor
Release "harbor" has been upgraded. Happy Helming!
NAME: harbor
LAST DEPLOYED: Thu Apr 30 11:30:06 2020
STATUS: deployed
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at
For more details, please visit

If you ever want to remove deployment, run:

$ helm uninstall  harbor  -n harbor

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 authenticated users access to the anyuid SCC:

$ oc adm policy add-scc-to-group anyuid system:authenticated

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   <none>        80/TCP              26m
harbor-harbor-clair           ClusterIP   <none>        8080/TCP            26m
harbor-harbor-core            ClusterIP    <none>        80/TCP              26m
harbor-harbor-database        ClusterIP   <none>        5432/TCP            26m
harbor-harbor-jobservice      ClusterIP     <none>        80/TCP              26m
harbor-harbor-notary-server   ClusterIP   <none>        4443/TCP            26m
harbor-harbor-notary-signer   ClusterIP     <none>        7899/TCP            26m
harbor-harbor-portal          ClusterIP    <none>        80/TCP              26m
harbor-harbor-redis           ClusterIP   <none>        6379/TCP            26m
harbor-harbor-registry        ClusterIP   <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.

install harbor registry 02

Default logins if you didn’t change password are:

Username: admin
Password: Harbor12345

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.

Add Harbor Image Registry Pull Secret to Kubernetes / OpenShift

Similar guides:

Install Project Quay Registry on OpenShift With Operator

As an appreciation for the content we put out,
we would be thrilled if you support us!

As we continue to grow, we would wish to reach and impact more people who visit and take advantage of the guides we have on our blog. This is a big task for us and we are so far extremely grateful for the kind people who have shown amazing support for our work over the time we have been online.

Thank You for your support as we work to give you the best of guides and articles. Click below to buy us a coffee.


Please enter your comment!
Please enter your name here