Skip to content

Install Harbor with DevStream

1 Prerequisites

  • An existing Kubernetes cluster, version > 1.10
  • StorageClass

If you are sure you already have a StorageClass configured for your K8s cluster, you can skip this section and move on to the next.

If you are uncertain about StorageClass, here's a bit more explanation:

Depending on the installation method, your Kubernetes cluster may be deployed with an existing StorageClass marked as default. This default StorageClass is then used to dynamically provision storage for PersistentVolumeClaims that do not require any specific storage class. See PersistentVolumeClaim documentation for details.


  • For local clusters created by minikube, there is already a default standard StorageClass using hostpath.
  • For local clusters created by kind, there is a default standard StorageClass using
  • For K8s-as-a-Service in public cloud providers, it's highly likely that a default StorageClass is created. For example, for AWS EKS, the default is gp2, using AWS EBS. Note that the pre-installed default StorageClass may not fit well with your expected workload; for example, it might provision storage that is too expensive. If this is the case, you can either change the default StorageClass or disable it thoroughly to avoid the dynamic provisioning of storage. For more information on this topic, see the official doc here.

2 Harbor Architecture

Harbor Architecture

3 Using the Harbor Plugin with DevStream

3.1 Quickstart

For a local testing and developing purpose, we can deploy Harbor quickly using the minimal config as follows:

- name: helm-installer
  instanceID: harbor-001
  dependsOn: [ ]
    valuesYaml: |
        type: nodePort
          enabled: false
        enabled: false
        enabled: false
        enabled: false

After running dtm apply, we can see the following resources in the "harbor" namespace:

  • Deployment (kubectl get deployment -n harbor)

Most Harbor-related services run as Deployments:

harbor-core         1/1     1            1           2m56s
harbor-jobservice   1/1     1            1           2m56s
harbor-nginx        1/1     1            1           2m56s
harbor-portal       1/1     1            1           2m56s
harbor-registry     1/1     1            1           2m56s
  • StatefulSet (kubectl get statefulset -n harbor)

Harbor depends on Postgres and Redis, which are deployed as StatefulSets. Notice that these dependencies are not deployed to a production-ready level with highly-availability and redundancy.

NAME              READY   AGE
harbor-database   1/1     3m40s
harbor-redis      1/1     3m40s
  • Service (kubectl get service -n harbor)

By default, Harbor is exposed on port 30002 as type NodePort:

NAME                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
harbor              NodePort      <none>        80:30002/TCP        4m17s
harbor-core         ClusterIP   <none>        80/TCP              4m17s
harbor-database     ClusterIP    <none>        5432/TCP            4m17s
harbor-jobservice   ClusterIP       <none>        80/TCP              4m17s
harbor-portal       ClusterIP     <none>        80/TCP              4m17s
harbor-redis        ClusterIP   <none>        6379/TCP            4m17s
harbor-registry     ClusterIP   <none>        5000/TCP,8080/TCP   4m17s
  • PersistentVolumeClaim (kubectl get pvc -n harbor)

Harbor requires a few volumes, including volumes for Postgres and Redis:

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-harbor-redis-0               Bound    pvc-5b6b5eb4-c40d-4f46-8f19-ff3a8869e56f   1Gi        RWO            standard       5m12s
database-data-harbor-database-0   Bound    pvc-d7ccaf1f-c450-4a16-937a-f55ad0c7c18d   1Gi        RWO            standard       5m12s
harbor-jobservice                 Bound    pvc-9407ef73-eb65-4a56-8720-a9ddbcb76fef   1Gi        RWO            standard       5m13s
harbor-registry                   Bound    pvc-34a2b88d-9ff2-4af4-9faf-2b33e97b971f   5Gi        RWO            standard       5m13s
  • PersistentVolume (kubectl get pv)

For a quick start (for example, with a local kind/minikube cluster,) we don't have to configure the StorageClass; so the resources are created with the default StorageClass:

pvc-34a2b88d-9ff2-4af4-9faf-2b33e97b971f   5Gi        RWO            Delete           Bound         harbor/harbor-registry                    standard                5m22s
pvc-5b6b5eb4-c40d-4f46-8f19-ff3a8869e56f   1Gi        RWO            Delete           Bound         harbor/data-harbor-redis-0                standard                5m22s
pvc-9407ef73-eb65-4a56-8720-a9ddbcb76fef   1Gi        RWO            Delete           Bound         harbor/harbor-jobservice                  standard                5m22s
pvc-d7ccaf1f-c450-4a16-937a-f55ad0c7c18d   1Gi        RWO            Delete           Bound         harbor/database-data-harbor-database-0    standard                5m22s

In this example, our default StorageClass is(kubectl get storageclass):

standard (default)   Delete          Immediate           false                  20h

3.2 Using Harbor

We can forward the port of the Harbor service and log in:

kubectl port-forward -n harbor service/harbor 8080:80

Harbor Login

And the default login user/pwd is: admin/Harbor12345. You will see the dashboard after a successful login:

Harbor Dashboard

3.3 Default Config

The harbor plugin provides default values for many options:

key default value description
chart.chartPath "" local chart path
chart.chartName harbor/harbor helm chart name
chart.version "" chart version
chart.timeout 10m timeout for helm install
chart.upgradeCRDs true update CRDs or not (if any)
chart.releaseName harbor helm release name
chart.namespace harbor namespace
chart.wait true wait till deployment finishes
repo.url helm repo URL harbor helm repo name