Gerrit on Kubernetes

Gerrit is a web-based code review tool, which acts as a Git server. This helm chart provides a Gerrit setup that can be deployed on Kubernetes. In addition, the chart provides a CronJob to perform Git garbage collection.

Gerrit versions before 3.0 are no longer supported, since the support of ReviewDB was removed.

Prerequisites

  • Helm (>= version 3.0)

    (Check out this guide how to install and use helm.)

  • Access to a provisioner for persistent volumes with Read Write Many (RWM)- capability.

    A list of applicaple volume types can be found here. This project was developed using the NFS-server-provisioner helm chart, a NFS-provisioner deployed in the Kubernetes cluster itself. Refer to this guide of how to deploy it in context of this project.

  • A domain name that is configured to point to the IP address of the node running the Ingress controller on the kubernetes cluster (as described here).

  • (Optional: Required, if SSL is configured) A Java keystore to be used by Gerrit.

Installing the Chart

ATTENTION: The value for ingress.host is required for rendering the chart's templates. The nature of the value does not allow defaults. Thus a custom values.yaml-file setting this value is required!

To install the chart with the release name gerrit, execute:

cd $(git rev-parse --show-toplevel)/helm-charts
helm install \
  gerrit \  # release name
  ./gerrit \  # path to chart
  -f <path-to-custom-values>.yaml

The command deploys the Gerrit instance on the current Kubernetes cluster. The configuration section lists the parameters that can be configured during installation.

Configuration

The following sections list the configurable values in values.yaml. To configure a Gerrit setup, make a copy of the values.yaml-file and change the parameters as needed. The configuration can be applied by installing the chart as described above.

In addition, single options can be set without creating a custom values.yaml:

cd $(git rev-parse --show-toplevel)/helm-charts
helm install \
  gerrit \  # release name
  ./gerrit \  # path to chart
  --set=gitRepositoryStorage.size=100Gi

Container images

ParameterDescriptionDefault
images.registry.nameThe image registry to pull the container images from``
images.registry.ImagePullSecret.nameName of the ImagePullSecretimage-pull-secret (if empty no image pull secret will be deployed)
images.registry.ImagePullSecret.createWhether to create an ImagePullSecretfalse
images.registry.ImagePullSecret.usernameThe image registry usernamenil
images.registry.ImagePullSecret.passwordThe image registry passwordnil
images.versionThe image version (image tag) to uselatest
images.imagePullPolicyImage pull policyAlways

Storage classes

For information of how a StorageClass is configured in Kubernetes, read the official Documentation.

ParameterDescriptionDefault
storageClasses.default.nameThe name of the default StorageClass (RWO)default
storageClasses.default.createWhether to create the StorageClassfalse
storageClasses.default.provisionerProvisioner of the StorageClasskubernetes.io/aws-ebs
storageClasses.default.reclaimPolicyWhether to Retain or Delete volumes, when they become unboundDelete
storageClasses.default.parametersParameters for the provisionerparameters.type: gp2, parameters.fsType: ext4
storageClasses.shared.nameThe name of the shared StorageClass (RWM)shared-storage
storageClasses.shared.createWhether to create the StorageClassfalse
storageClasses.shared.provisionerProvisioner of the StorageClassnfs
storageClasses.shared.reclaimPolicyWhether to Retain or Delete volumes, when they become unboundDelete
storageClasses.shared.parametersParameters for the provisionerparameters.mountOptions: vers=4.1

Network policies

ParameterDescriptionDefault
networkPolicies.enabledWhether to enable preconfigured NetworkPoliciesfalse
networkPolicies.dnsPortsList of ports used by DNS-service (e.g. KubeDNS)[53, 8053]

The NetworkPolicies provided here are quite strict and do not account for all possible scenarios. Thus, custom NetworkPolicies have to be added, e.g. for allowing Gerrit to replicate to a Gerrit replica. By default, the egress traffic of the gerrit pod is blocked, except for connections to the DNS-server. Thus, replication which requires Gerrit to perform git pushes to the replica will not work. The chart provides the possibility to define custom rules for egress- traffic of the gerrit pod under gerrit.networkPolicy.egress. Depending on the scenario, there are different ways to allow the required connections. The easiest way is to allow all egress-traffic for the gerrit pods:

gerrit:
  networkPolicy:
    egress:
    - {}

If the remote that is replicated to is running in a pod on the same cluster and the service-DNS is used as the remote's URL (e.g. http://gerrit-replica-git-backend-service:80/git/${name}.git), a podSelector (and namespaceSelector, if the pod is running in a different namespace) can be used to whitelist the traffic:

gerrit:
  networkPolicy:
    egress:
    - to:
      - podSelector:
          matchLabels:
            app: git-backend

If the remote is outside the cluster, the IP of the remote or its load balancer can also be whitelisted, e.g.:

gerrit:
  networkPolicy:
    egress:
    - to:
      - ipBlock:
          cidr: xxx.xxx.0.0/16

The same principle also applies to other use cases, e.g. connecting to a database. For more information about the NetworkPolicy resource refer to the Kubernetes documentation.

Storage for Git repositories

ParameterDescriptionDefault
gitRepositoryStorage.externalPVC.useWhether to use a PVC deployed outside the chartfalse
gitRepositoryStorage.externalPVC.nameName of the external PVCgit-repositories-pvc
gitRepositoryStorage.sizeSize of the volume storing the Git repositories5Gi

If the git repositories should be persisted even if the chart is deleted and in a way that the volume containing them can be mounted by the reinstalled chart, the PVC claiming the volume has to be created independently of the chart. To use the external PVC, set gitRepositoryStorage.externalPVC.enabled to true and give the name of the PVC under gitRepositoryStorage.externalPVC.name.

CA certificate

Some application may require TLS verification. If the default CA built into the containers is not enough a custom CA certificate can be given to the deployment. Note, that Gerrit will require its CA in a JKS keytore, which is described below.

ParameterDescriptionDefault
caCertCA certificate for TLS verification (if not set, the default will be used)None

Ingress

ParameterDescriptionDefault
ingress.enabledWhether to enable the Ingressfalse
ingress.hostREQUIRED: Host name to use for the Ingress (required for Ingress)nil
ingress.additionalAnnotationsAdditional annotations for the Ingressnil
ingress.tls.enabledWhether to enable TLS termination in the Ingressfalse
ingress.tls.secret.createWhether to create a TLS-secrettrue
ingress.tls.secret.nameName of an external secret that will be used as a TLS-secretnil
ingress.tls.certPublic SSL server certificate-----BEGIN CERTIFICATE-----
ingress.tls.keyPrivate SSL server certificate-----BEGIN RSA PRIVATE KEY-----

Git garbage collection

ParameterDescriptionDefault
gitGC.imageImage name of the Git-GC container imagek8s-gerrit/git-gc
gitGC.scheduleCron-formatted schedule with which to run Git garbage collection0 6,18 * * *
gitGC.resourcesConfigure the amount of resources the pod requests/is allowedrequests.cpu: 100m
requests.memory: 256Mi
limits.cpu: 100m
limits.memory: 256Mi
gitGC.logging.persistence.enabledWhether to persist logstrue
gitGC.logging.persistence.sizeStorage size for persisted logs1Gi

Gerrit

The way the Jetty servlet used by Gerrit works, the Gerrit component of the gerrit chart actually requires the URL to be known, when the chart is installed. The suggested way to do that is to use the provided Ingress resource. This requires that a URL is available and that the DNS is configured to point the URL to the IP of the node the Ingress controller is running on!
Setting the canonical web URL in the gerrit.config to the host used for the Ingress is mandatory, if access to Gerrit is required!
While the chart allows to configure multiple replica for the Gerrit StatefulSet, scaling of Gerrit is currently not supported, since no mechanism to guarantee a consistent state is currently in place. This is planned to be implemented in the future.
ParameterDescriptionDefault
gerrit.images.gerritInitImage name of the Gerrit init container imagek8s-gerrit/gerrit-init
gerrit.images.gerritImage name of the Gerrit container imagek8s-gerrit/gerrit
gerrit.replicasNumber of replica pods to deploy1
gerrit.updatePartitionNumber of pods to update simultaneously1
gerrit.resourcesConfigure the amount of resources the pod requests/is allowedrequests.cpu: 1
requests.memory: 5Gi
limits.cpu: 1
limits.memory: 6Gi
gerrit.persistence.enabledWhether to persist the Gerrit sitetrue
gerrit.persistence.sizeStorage size for persisted Gerrit site10Gi
gerrit.livenessProbeConfiguration of the liveness probe timings{initialDelaySeconds: 30, periodSeconds: 5}
gerrit.readinessProbeConfiguration of the readiness probe timings{initialDelaySeconds: 5, periodSeconds: 1}
gerrit.startupProbeConfiguration of the startup probe timings{initialDelaySeconds: 10, periodSeconds: 5}
gerrit.networkPolicy.ingressCustom ingress-network policy for gerrit podsnil
gerrit.networkPolicy.egressCustom egress-network policy for gerrit podsnil
gerrit.service.typeWhich kind of Service to deployNodePort
gerrit.service.http.portPort over which to expose HTTP80
gerrit.service.ssh.enabledWhether to enable SSHfalse
gerrit.service.ssh.portPort over which to expose SSH29418
gerrit.service.ssh.rsaKeyPrivate SSH key in RSA format-----BEGIN RSA PRIVATE KEY-----
gerrit.keystorebase64-encoded Java keystore (`cat keystore.jksbase64`) to be used by Gerrit, when using SSL
gerrit.index.typeIndex type used by Gerrit (either lucene or elasticsearch)lucene
gerrit.plugins.packagedList of Gerrit plugins that are packaged into the Gerrit-war-file to install["commit-message-length-validator", "download-commands", "replication", "reviewnotes"]
gerrit.plugins.downloadedList of Gerrit plugins that will be downloadednil
gerrit.plugins.downloaded[0].nameName of pluginnil
gerrit.plugins.downloaded[0].urlDownload url of pluginnil
gerrit.plugins.downloaded[0].sha1SHA1 sum of plugin jar used to ensure file integrity and version (optional)nil
gerrit.plugins.cache.enabledWhether to cache downloaded pluginsfalse
gerrit.plugins.cache.sizeSize of the volume used to store cached plugins1Gi
gerrit.etc.configMap of config files (e.g. gerrit.config) that will be mounted to $GERRIT_SITE/etcby a ConfigMap{gerrit.config: ..., replication.config: ...}see here
gerrit.etc.secretMap of config files (e.g. secure.config) that will be mounted to $GERRIT_SITE/etcby a Secret{secure.config: ...} see here
gerrit.additionalConfigMapsAllows to mount additional ConfigMaps into a subdirectory of $SITE/data[]
gerrit.additionalConfigMaps[*].nameName of the ConfigMapnil
gerrit.additionalConfigMaps[*].subDirSubdirectory under $SITE/data into which the files should be symlinkednil
gerrit.additionalConfigMaps[*].dataData of the ConfigMap. If not set, secret has to be created manuallynil

Gerrit config files

The gerrit chart provides a ConfigMap containing the configuration files used by Gerrit, e.g. gerrit.config and a Secret containing sensitive configuration like the secure.config to configure the Gerrit installation in the Gerrit component. The content of the config files can be set in the values.yaml under the keys gerrit.etc.config and gerrit.etc.secret respectively. The key has to be the filename (eg. gerrit.config) and the file's contents the value. This way an arbitrary number of configuration files can be loaded into the $GERRIT_SITE/etc-directory, e.g. for plugins. All configuration options for Gerrit are described in detail in the official documentation of Gerrit. Some options however have to be set in a specified way for Gerrit to work as intended with the chart:

  • gerrit.basePath

    Path to the directory containing the repositories. The chart mounts this directory from a persistent volume to /var/gerrit/git in the container. For Gerrit to find the correct directory, this has to be set to git.

  • gerrit.serverId

    In Gerrit-version higher than 2.14 Gerrit needs a server ID, which is used by NoteDB. Gerrit would usually generate a random ID on startup, but since the gerrit.config file is read only, when mounted as a ConfigMap this fails. Thus the server ID has to be set manually!

  • gerrit.canonicalWebUrl

    The canonical web URL has to be set to the Ingress host.

  • index.onlineUpgrade

    Online reindexing is currently NOT supported. An offline reindexing will be enforced upon Gerrit updates. Online reindexing might under some circum- stances interfere with the Gerrit pod startup procedure and thus has to be deactivated.

  • httpd.listenURL

    This has to be set to proxy-http://*:8080/ or proxy-https://*:8080, depending of TLS is enabled in the Ingress or not, otherwise the Jetty servlet will run into an endless redirect loop.

  • container.user

    The technical user in the Gerrit container is called gerrit. Thus, this value is required to be gerrit.

  • container.javaHome

    This has to be set to /usr/lib/jvm/java-8-openjdk-amd64, since this is the path of the Java installation in the container.

  • container.javaOptions

    The maximum heap size has to be set. And its value has to be lower than the memory resource limit set for the container (e.g. -Xmx4g). In your calculation, allow memory for other components running in the container.

To enable liveness- and readiness probes, the healthcheck plugin will be installed by default. Note, that by configuring to use a packaged or downloaded version of the healthcheck plugin, the configured version will take precedence over the default version. The plugin is by default configured to disable the querychanges and auth healthchecks, since these would not work on a new and empty Gerrit server. The default configuration can be overwritten by adding the healthcheck.config file as a key-value pair to gerrit.etc.config as for every other configuration.

Installing Gerrit plugins

There are several different ways to install plugins for Gerrit:

  • RECOMMENDED: Package the plugins to install into the WAR-file containing Gerrit. This method provides the most stable way to install plugins, but requires to use a custom built gerrit-war file and container images, if plugins are required that are not part of the official release.war-file.

  • Download and cache plugins. The chart supports downloading the plugin files and to cache them in a separate volume, that is shared between Gerrit-pods. SHA1- sums are used to validate plugin-files and versions.

  • Download plugins, but do not cache them. This should only be used during development to save resources (the shared volume). Each pod will download the plugin-files on its own. Pods will fail to start up, if the download-URL is not valid anymore at some point in time.

Upgrading the Chart

To upgrade an existing installation of the gerrit chart, e.g. to install a newer chart version or to use an updated custom values.yaml-file, execute the following command:

cd $(git rev-parse --show-toplevel)/helm-charts
helm upgrade \
  <release-name> \
  ./gerrit \ # path to chart
  -f <path-to-custom-values>.yaml

Uninstalling the Chart

To delete the chart from the cluster, use:

helm delete <release-name>