**Notes:** The master branch is in heavy development, please use the codes on other branch instead. A high available solution for Harbor based on chart can be find [here](docs/High%20Availability.md). And refer to the [guide](docs/Upgrade.md) to upgrade the existing deployment.
## Introduction
This [Helm](https://github.com/kubernetes/helm) chart installs [Harbor](https://github.com/goharbor/harbor) in a Kubernetes cluster. Welcome to [contribute](CONTRIBUTING.md) to Helm Chart for Harbor.
## Prerequisites
- Kubernetes cluster 1.10+
- Helm 2.8.0+
## Installation
### Download the chart
Download Harbor helm chart code.
```bash
git clone https://github.com/goharbor/harbor-helm
```
Checkout the branch.
```bash
cd harbor-helm
git checkout branch_name
```
### Configure the chart
The following items can be configured in `values.yaml` or set via `--set` flag during installation.
#### Configure the way how to expose Harbor service:
-**Ingress**: The ingress controller must be installed in the Kubernetes cluster.
**Notes:** if the TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to issue [#5291](https://github.com/goharbor/harbor/issues/5291) for the detail.
-**ClusterIP**: Exposes the service on a cluster-internal IP. Choosing this value makes the service only reachable from within the cluster.
-**NodePort**: Exposes the service on each Node’s IP at a static port (the NodePort). You’ll be able to contact the NodePort service, from outside the cluster, by requesting `NodeIP:NodePort`.
-**LoadBalancer**: Exposes the service externally using a cloud provider’s load balancer.
#### Configure the external URL
The external URL for Harbor core service is used to:
1. populate the docker/helm commands showed on portal
2. populate the token service URL returned to docker/notary client
Format: `protocol://domain[:port]`. Usually:
- if expose the service via `Ingress`, the `domain` should be the value of `expose.ingress.hosts.core`
- if expose the service via `ClusterIP`, the `domain` should be the value of `expose.clusterIP.name`
- if expose the service via `NodePort`, the `domain` should be the IP address of one Kubernetes node
- if expose the service via `LoadBalancer`, set the `domain` as your own domain name and add a CNAME record to map the domain name to the one you got from the cloud provider
If Harbor is deployed behind the proxy, set it as the URL of proxy.
#### Configure the way how to persistent data:
-**Disable**: The data does not survive the termination of a pod.
-**Persistent Volume Claim(default)**: A default `StorageClass` is needed in the Kubernetes cluster to dynamic provision the volumes. Specify another StorageClass in the `storageClass` or set `existingClaim` if you have already existing persistent volumes to use.
-**External Storage(only for images and charts)**: For images and charts, the external storages are supported: `azure`, `gcs`, `s3``swift` and `oss`.
#### Configure the secrets
-**Secret keys**: Secret keys are used for secure communication between components. Fill `core.secret`, `jobservice.secret` and `registry.secret` to configure.
-**Certificates**:
-*notary*: Used for authentication during communications. Fill `notary.secretName` to configure. Notary server certificate must be issued with notary service name as subject alternative name.
-*core*: Used for token encryption/decryption. Fill `core.secretName` to configure.
Secrets and certificates must be setup to avoid changes on every Helm upgrade (see: [#107](https://github.com/goharbor/harbor-helm/issues/107)).
#### Configure the other items listed in [configuration](#configuration) section.
### Install the chart
Install the Harbor helm chart with a release name `my-release`:
```bash
helm install--name my-release .
```
## Uninstallation
To uninstall/delete the `my-release` deployment:
```bash
helm delete --purge my-release
```
## Configuration
The following table lists the configurable parameters of the Harbor chart and the default values.
| `expose.type` | The way how to expose the service: `ingress`, `clusterIP`, `nodePort` or `loadBalancer` | `ingress` |
| `expose.tls.type` | Choose TLS certificate type : `secretName`, `custom CA`, `rancher` or `self-signed x509 certificate` | `secretName`
| `expose.tls.secretName` | Fill the name of secret if you want to use your own TLS certificate and private key. The secret must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. The certificate and private key will be generated automatically if it is not set | |
| `expose.tls.notarySecretName` | By default, the Notary service will use the same cert and key as described above. Fill the name of secret if you want to use a separated one. Only needed when the `expose.type` is `ingress`. | |
| `expose.tls.commonName` | The common name used to generate the certificate, it's necessary when the `expose.type` is `clusterIP` or `nodePort` and `expose.tls.secretName` is null | |
| `expose.ingress.host` | The host of Harbor core service in ingress rule | `core.harbor.domain` |
| `expose.ingress.annotations` | The annotations used in ingress | |
| `expose.clusterIP.name` | The name of ClusterIP service | `harbor` |
| `expose.clusterIP.ports.httpPort` | The service port Harbor listens on when serving with HTTP | `80` |
| `expose.clusterIP.ports.httpsPort` | The service port Harbor listens on when serving with HTTPS | `443` |
| `expose.clusterIP.ports.notaryPort` | The service port Notary listens on. Only needed when `notary.enabled` is set to `true` | `4443` |
| `expose.nodePort.name` | The name of NodePort service | `harbor` |
| `expose.nodePort.ports.http.port` | The service port Harbor listens on when serving with HTTP | `80` |
| `expose.nodePort.ports.http.nodePort` | The node port Harbor listens on when serving with HTTP | `30002` |
| `expose.nodePort.ports.https.port` | The service port Harbor listens on when serving with HTTPS | `443` |
| `expose.nodePort.ports.https.nodePort` | The node port Harbor listens on when serving with HTTPS | `30003` |
| `expose.nodePort.ports.notary.port` | The service port Notary listens on. Only needed when `notary.enabled` is set to `true` | `4443` |
| `expose.nodePort.ports.notary.nodePort` | The node port Notary listens on. Only needed when `notary.enabled` is set to `true` | `30004` |
| `expose.loadBalancer.name` | The name of service |`harbor`|
| `expose.loadBalancer.ports.httpPort` | The service port Harbor listens on when serving with HTTP |`80`|
| `expose.loadBalancer.ports.httpsPort` | The service port Harbor listens on when serving with HTTP |`30002`|
| `expose.loadBalancer.ports.notaryPort` | The service port Notary listens on. Only needed when `notary.enabled` is set to `true`|
| **Persistence** |
| `persistence.enabled` | Enable the data persistence or not | `true` |
| `persistence.resourcePolicy` | Setting it to `keep` to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted | `keep` |
| `persistence.persistentVolumeClaim.registry.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | |
| `persistence.persistentVolumeClaim.registry.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning | |
| `persistence.persistentVolumeClaim.registry.subPath` | The sub path used in the volume | |
| `persistence.persistentVolumeClaim.registry.accessMode` | The access mode of the volume | `ReadWriteOnce` |
| `persistence.persistentVolumeClaim.registry.size` | The size of the volume | `5Gi` |
| `persistence.persistentVolumeClaim.chartmuseum.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | |
| `persistence.persistentVolumeClaim.chartmuseum.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning | |
| `persistence.persistentVolumeClaim.chartmuseum.subPath` | The sub path used in the volume | |
| `persistence.persistentVolumeClaim.chartmuseum.accessMode` | The access mode of the volume | `ReadWriteOnce` |
| `persistence.persistentVolumeClaim.chartmuseum.size` | The size of the volume | `5Gi` |
| `persistence.persistentVolumeClaim.jobservice.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | |
| `persistence.persistentVolumeClaim.jobservice.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning | |
| `persistence.persistentVolumeClaim.jobservice.subPath` | The sub path used in the volume | |
| `persistence.persistentVolumeClaim.jobservice.accessMode` | The access mode of the volume | `ReadWriteOnce` |
| `persistence.persistentVolumeClaim.jobservice.size` | The size of the volume | `1Gi` |
| `persistence.persistentVolumeClaim.database.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external database is used, the setting will be ignored | |
| `persistence.persistentVolumeClaim.database.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning. If external database is used, the setting will be ignored | |
| `persistence.persistentVolumeClaim.database.subPath` | The sub path used in the volume. If external database is used, the setting will be ignored | |
| `persistence.persistentVolumeClaim.database.accessMode` | The access mode of the volume. If external database is used, the setting will be ignored | `ReadWriteOnce` |
| `persistence.persistentVolumeClaim.database.size` | The size of the volume. If external database is used, the setting will be ignored | `1Gi` |
| `persistence.persistentVolumeClaim.redis.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external Redis is used, the setting will be ignored | |
| `persistence.persistentVolumeClaim.redis.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used(the default). Set it to `-` to disable dynamic provisioning. If external Redis is used, the setting will be ignored | |
| `persistence.persistentVolumeClaim.redis.subPath` | The sub path used in the volume. If external Redis is used, the setting will be ignored | |
| `persistence.persistentVolumeClaim.redis.accessMode` | The access mode of the volume. If external Redis is used, the setting will be ignored | `ReadWriteOnce` |
| `persistence.persistentVolumeClaim.redis.size` | The size of the volume. If external Redis is used, the setting will be ignored | `1Gi` |
| `imageChartStorage.disableredirect` | The configuration for managing redirects from content backends. For backends which not supported it (such as using minio for `s3` storage type), please set it to `true` to disable redirects. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect) for more information about the detail | `false` |
| `imageChartStorage.type` | The type of storage for images and charts: `filesystem`, `azure`, `gcs`, `s3`, `swift` or `oss`. The type must be `filesystem` if you want to use persistent volumes for registry and chartmuseum. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#storage) for more information about the detail | `filesystem` |
| **General** |
| `externalURL` | The external URL for Harbor core service | `https://core.harbor.domain` |
| `imagePullPolicy` | The image pull policy | `IfNotPresent` |
| `logLevel` | The log level | `debug` |
| `harborAdminPassword` | The initial password of Harbor admin. Change it from portal after launching Harbor | `Harbor12345` |
| `secretkey` | The key used for encryption. Must be a string of 16 chars | `not-a-secure-key` |
| **Nginx** (if expose the service via `ingress`, the Nginx will not be used) |
| `core.image.tag` | Tag for Harbor core image | `dev` |
| `core.replicas` | The replica count | `1` |
| `core.resources` | The [resources] to allocate for container | undefined |
| `core.nodeSelector` | Node labels for pod assignment | `{}` |
| `core.tolerations` | Tolerations for pod assignment | `[]` |
| `core.affinity` | Node/Pod affinities | `{}` |
| `core.podAnnotations` | Annotations to add to the core pod | `{}` |
| `core.secret` | Secret is used when core server communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | |
| `core.secret` | Fill the name of a kubernetes secret if you want to use your own TLS certificate and private key for token encryption/decryption. The secret must contain keys named `tls.tokenServiceRootCertBundle` and `tls.tokenServicePrivateKey` that contain the certificate and private key. They will be automatically generated if not set. | |
| **Jobservice** |
| `jobservice.image.repository` | Repository for jobservice image | `goharbor/harbor-jobservice` |
| `jobservice.image.tag` | Tag for jobservice image | `dev` |
| `jobservice.replicas` | The replica count | `1` |
| `jobservice.maxJobWorkers` | The max job workers | `10` |
| `jobservice.jobLogger` | The logger for jobs: `file`, `database` or `stdout` | `database` |
| `jobservice.resources` | The [resources] to allocate for container | undefined |
| `jobservice.nodeSelector` | Node labels for pod assignment | `{}` |
| `jobservice.tolerations` | Tolerations for pod assignment | `[]` |
| `jobservice.podAnnotations` | Annotations to add to the jobservice pod | `{}` |
| `jobservice.secret` | Secret is used when job service communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | |
| **Registry** |
| `registry.registry.image.repository` | Repository for registry image | `goharbor/registry-photon` |
| `registry.registry.image.tag` | Tag for registry image |
| `registry.registry.resources` | The [resources] to allocate for container | undefined | | `dev` |
| `registry.podAnnotations` | Annotations to add to the registry pod | `{}` |
| `registry.secret` | Secret is used to secure the upload state from client and registry storage backend. See: https://github.com/docker/distribution/blob/master/docs/configuration.md#http. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | |
| **Chartmuseum** |
| `chartmuseum.enabled` | Enable chartmusuem to store chart | `true` |
| `chartmuseum.image.repository` | Repository for chartmuseum image | `goharbor/chartmuseum-photon` |
| `chartmuseum.image.tag` | Tag for chartmuseum image | `dev` |
| `chartmuseum.replicas` | The replica count | `1` |
| `chartmuseum.resources` | The [resources] to allocate for container | undefined |
| `chartmuseum.nodeSelector` | Node labels for pod assignment | `{}` |
| `chartmuseum.tolerations` | Tolerations for pod assignment | `[]` |
| `notary.podAnnotations` | Annotations to add to the notary pod | `{}` |
| `notary.secretName` | Fill the name of a kubernetes secret if you want to use your own TLS certificate authority, certificate and private key for notary communications. The secret must contain keys named `tls.ca`, `tls.crt` and `tls.key` that contain the CA, certificate and private key. They will be generated if not set. | |
| **Database** |
| `database.type` | If external database is used, set it to `external` | `internal` |
| `database.internal.image.repository` | Repository for database image | `goharbor/harbor-db` |
| `database.internal.image.tag` | Tag for database image | `dev` |
| `database.internal.password` | The password for database | `changeit` |
| `database.internal.resources` | The [resources] to allocate for container | undefined |
| `database.internal.nodeSelector` | Node labels for pod assignment | `{}` |
| `database.internal.tolerations` | Tolerations for pod assignment | `[]` |