gerrit: charts and app configuration

Change-Id: If4f05f749719d6ba0e2ced8da563699bc6fbc4c0
diff --git a/charts/gerrit-replica/.helmignore b/charts/gerrit-replica/.helmignore
new file mode 100644
index 0000000..4f4562f
--- /dev/null
+++ b/charts/gerrit-replica/.helmignore
@@ -0,0 +1,24 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+
+docs/
+supplements/
diff --git a/charts/gerrit-replica/Chart.yaml b/charts/gerrit-replica/Chart.yaml
new file mode 100644
index 0000000..0fc9a45
--- /dev/null
+++ b/charts/gerrit-replica/Chart.yaml
@@ -0,0 +1,24 @@
+apiVersion: v2
+appVersion: 3.9.1
+description: |-
+    The Gerrit replica serves as a read-only Gerrit instance to serve repositories
+    that it receives from a Gerrit instance via replication. It can be used to
+    reduce the load on Gerrit instances.
+name: gerrit-replica
+version: 0.2.0
+maintainers:
+- name: Thomas Draebing
+  email: thomas.draebing@sap.com
+- name: Matthias Sohn
+  email: matthias.sohn@sap.com
+- name: Sasa Zivkov
+  email: sasa.zivkov@sap.com
+- name: Christian Halstrick
+  email: christian.halstrick@sap.com
+home: https://gerrit.googlesource.com/k8s-gerrit/+/master/helm-charts/gerrit-replica
+icon: http://commondatastorage.googleapis.com/gerrit-static/diffy-w200.png
+sources:
+- https://gerrit.googlesource.com/k8s-gerrit/+/master
+keywords:
+- gerrit
+- git
diff --git a/charts/gerrit-replica/LICENSE b/charts/gerrit-replica/LICENSE
new file mode 100644
index 0000000..028fc9f
--- /dev/null
+++ b/charts/gerrit-replica/LICENSE
@@ -0,0 +1,201 @@
+   Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/charts/gerrit-replica/README.md b/charts/gerrit-replica/README.md
new file mode 100644
index 0000000..8b68b43
--- /dev/null
+++ b/charts/gerrit-replica/README.md
@@ -0,0 +1,547 @@
+# Gerrit replica on Kubernetes
+
+Gerrit is a web-based code review tool, which acts as a Git server. On large setups
+Gerrit servers can see a sizable amount of traffic from git operations performed by
+developers and build servers. The major part of requests are read-only requests
+(e.g. by `git fetch` operations). To take some load of the Gerrit server,
+Gerrit replicas can be deployed to serve read-only requests.
+
+This helm chart provides a Gerrit replica setup that can be deployed on Kubernetes.
+The Gerrit replica is capable of receiving replicated git repositories from a
+Gerrit. The Gerrit replica can then serve authenticated read-only requests.
+
+***note
+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](https://docs.helm.sh/using_helm/#quickstart-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](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes).
+    This project was developed using the
+    [NFS-server-provisioner helm chart](https://github.com/helm/charts/tree/master/stable/nfs-server-provisioner),
+    a NFS-provisioner deployed in the Kubernetes cluster itself. Refer to
+    [this guide](/helm-charts/gerrit-replica/docs/nfs-provisioner.md) 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](http://alesnosek.com/blog/2017/02/14/accessing-kubernetes-pods-from-outside-of-the-cluster/)).
+
+- (Optional: Required, if SSL is configured)
+  A [Java keystore](https://gerrit-review.googlesource.com/Documentation/config-gerrit.html#httpd.sslKeyStore)
+  to be used by Gerrit.
+
+## Installing the Chart
+
+***note
+**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-replica`, execute:
+
+```sh
+cd $(git rev-parse --show-toplevel)/helm-charts
+helm install \
+  gerrit-replica \  # release name
+  ./gerrit-replica \  # path to chart
+  -f <path-to-custom-values>.yaml
+```
+
+The command deploys the Gerrit replica on the current Kubernetes cluster. The
+[configuration section](#Configuration) lists the parameters that can be
+configured during installation.
+
+The Gerrit replica requires the replicated `All-Projects.git`- and `All-Users.git`-
+repositories to be present in the `/var/gerrit/git`-directory. The `gerrit-init`-
+InitContainer will wait for this being the case. A way to do this is to access
+the Gerrit replica pod and to clone the repositories from the primary Gerrit (Make
+sure that you have the correct access rights do so.):
+
+```sh
+kubectl exec -it <gerrit-replica-pod> -c gerrit-init ash
+gerrit@<gerrit-replica-pod>:/var/tools$ cd /var/gerrit/git
+gerrit@<gerrit-replica-pod>:/var/gerrit/git$ git clone "http://gerrit.com/All-Projects" --mirror
+Cloning into bare repository 'All-Projects.git'...
+gerrit@<gerrit-replica-pod>:/var/gerrit/git$ git clone "http://gerrit.com/All-Users" --mirror
+Cloning into bare repository 'All-Users.git'...
+```
+
+## Configuration
+
+The following sections list the configurable values in `values.yaml`. To configure
+a Gerrit replica 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](#Installing-the-chart).
+
+In addition, single options can be set without creating a custom `values.yaml`:
+
+```sh
+cd $(git rev-parse --show-toplevel)/helm-charts
+helm install \
+  gerrit-replica \  # release name
+  ./gerrit-replica \  # path to chart
+  --set=gitRepositoryStorage.size=100Gi,gitBackend.replicas=2
+```
+
+### Container images
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `images.busybox.registry` | The registry to pull the busybox container images from | `docker.io` |
+| `images.busybox.tag` | The busybox image tag to use | `latest` |
+| `images.registry.name` | The image registry to pull the container images from | `` |
+| `images.registry.ImagePullSecret.name` | Name of the ImagePullSecret | `image-pull-secret` (if empty no image pull secret will be deployed) |
+| `images.registry.ImagePullSecret.create` | Whether to create an ImagePullSecret | `false` |
+| `images.registry.ImagePullSecret.username` | The image registry username | `nil` |
+| `images.registry.ImagePullSecret.password` | The image registry password | `nil` |
+| `images.version` | The image version (image tag) to use | `latest` |
+| `images.imagePullPolicy` | Image pull policy | `Always` |
+| `images.additionalImagePullSecrets` | Additional image pull policies that pods should use | `[]` |
+
+### Labels
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `additionalLabels` | Additional labels for resources managed by this Helm chart | `{}` |
+
+### Storage classes
+
+For information of how a `StorageClass` is configured in Kubernetes, read the
+[official Documentation](https://kubernetes.io/docs/concepts/storage/storage-classes/#introduction).
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `storageClasses.default.name` | The name of the default StorageClass (RWO) | `default` |
+| `storageClasses.default.create` | Whether to create the StorageClass | `false` |
+| `storageClasses.default.provisioner` | Provisioner of the StorageClass | `kubernetes.io/aws-ebs` |
+| `storageClasses.default.reclaimPolicy` | Whether to `Retain` or `Delete` volumes, when they become unbound | `Delete` |
+| `storageClasses.default.parameters` | Parameters for the provisioner | `parameters.type: gp2`, `parameters.fsType: ext4` |
+| `storageClasses.default.mountOptions` | The mount options of the default StorageClass | `[]` |
+| `storageClasses.default.allowVolumeExpansion` | Whether to allow volume expansion. | `false` |
+| `storageClasses.shared.name` | The name of the shared StorageClass (RWM) | `shared-storage` |
+| `storageClasses.shared.create` | Whether to create the StorageClass | `false` |
+| `storageClasses.shared.provisioner` | Provisioner of the StorageClass | `nfs` |
+| `storageClasses.shared.reclaimPolicy` | Whether to `Retain` or `Delete` volumes, when they become unbound | `Delete` |
+| `storageClasses.shared.parameters` | Parameters for the provisioner | `parameters.mountOptions: vers=4.1` |
+| `storageClasses.shared.mountOptions` | The mount options of the shared StorageClass | `[]` |
+| `storageClasses.shared.allowVolumeExpansion` | Whether to allow volume expansion. | `false` |
+
+### 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.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `caCert` | CA certificate for TLS verification (if not set, the default will be used) | `None` |
+
+### Workaround for NFS
+
+Kubernetes will not always be able to adapt the ownership of the files within NFS
+volumes. Thus, a workaround exists that will add init-containers to
+adapt file ownership. Note, that only the ownership of the root directory of the
+volume will be changed. All data contained within will be expected to already be
+owned by the user used by Gerrit. Also the ID-domain will be configured to ensure
+correct ID-mapping.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `nfsWorkaround.enabled` | Whether the volume used is an NFS-volume | `false` |
+| `nfsWorkaround.chownOnStartup` | Whether to chown the volume on pod startup | `false` |
+| `nfsWorkaround.idDomain` | The ID-domain that should be used to map user-/group-IDs for the NFS mount | `localdomain.com` |
+
+### Network policies
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `networkPolicies.enabled` | Whether to enable preconfigured NetworkPolicies | `false` |
+| `networkPolicies.dnsPorts` | List 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
+connecting to a database. On the other hand some defaults may be not restrictive
+enough. By default, the ingress traffic of the git-backend pod is not restricted.
+Thus, every source (with the right credentials) could push to the git-backend.
+To add an additional layer of security, the ingress rule could be defined more
+finegrained. The chart provides the possibility to define custom rules for ingress-
+traffic of the git-backend pod under `gitBackend.networkPolicy.ingress`.
+Depending on the scenario, there are different ways to restrict the incoming
+connections.
+
+If the replicator (e.g. Gerrit) is running in a pod on the same cluster,
+a podSelector (and namespaceSelector, if the pod is running in a different
+namespace) can be used to whitelist the traffic:
+
+```yaml
+gitBackend:
+  networkPolicy:
+    ingress:
+    - from:
+      - podSelector:
+          matchLabels:
+            app: gerrit
+```
+
+If the replicator is outside the cluster, the IP of the replicator can also be
+whitelisted, e.g.:
+
+```yaml
+gitBackend:
+  networkPolicy:
+    ingress:
+    - from:
+      - 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](https://kubernetes.io/docs/concepts/services-networking/network-policies/).
+
+### Storage for Git repositories
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gitRepositoryStorage.externalPVC.use` | Whether to use a PVC deployed outside the chart | `false` |
+| `gitRepositoryStorage.externalPVC.name` | Name of the external PVC | `git-repositories-pvc` |
+| `gitRepositoryStorage.size` | Size of the volume storing the Git repositories | `5Gi` |
+
+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`.
+
+### Storage for Logs
+
+In addition to collecting logs with a log collection tool like Promtail, the logs
+can also be stored in a persistent volume. This volume has to be a read-write-many
+volume to be able to be used by multiple pods.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `logStorage.enabled` | Whether to enable persistence of logs | `false` |
+| `logStorage.externalPVC.use` | Whether to use a PVC deployed outside the chart | `false` |
+| `logStorage.externalPVC.name` | Name of the external PVC | `gerrit-logs-pvc` |
+| `logStorage.size` | Size of the volume | `5Gi` |
+| `logStorage.cleanup.enabled` | Whether to regularly delete old logs | `false` |
+| `logStorage.cleanup.schedule` | Cron schedule defining when to run the cleanup job | `0 0 * * *` |
+| `logStorage.cleanup.retentionDays` | Number of days to retain the logs | `14` |
+| `logStorage.cleanup.resources` | Resources the container is allowed to use | `requests.cpu: 100m` |
+| `logStorage.cleanup.additionalPodLabels` | Additional labels for pods | `{}` |
+| | | `requests.memory: 256Mi` |
+| | | `limits.cpu: 100m` |
+| | | `limits.memory: 256Mi` |
+
+Each pod will create a separate folder for its logs, allowing to trace logs to
+the respective pods.
+
+### Istio
+
+Istio can be used as an alternative to Kubernetes Ingresses to manage the traffic
+into the cluster and also inside the cluster. This requires istio to be installed
+beforehand. Some guidance on how to set up istio can be found [here](/Documentation/istio.md).
+The helm chart expects `istio-injection` to be enabled in the namespace, in which
+it will be installed.
+
+In the case istio is used, all configuration for ingresses in the chart will be
+ignored.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `istio.enabled` | Whether istio should be used (requires istio to be installed) | `false` |
+| `istio.host` | Hostname (CNAME must point to istio ingress gateway loadbalancer service) | `nil` |
+| `istio.tls.enabled` | Whether to enable TLS | `false` |
+| `istio.tls.secret.create` | Whether to create TLS certificate secret | `true` |
+| `istio.tls.secret.name` | Name of external secret containing TLS certificates | `nil` |
+| `istio.tls.cert` | TLS certificate | `-----BEGIN CERTIFICATE-----` |
+| `istio.tls.key` | TLS key | `-----BEGIN RSA PRIVATE KEY-----` |
+| `istio.ssh.enabled` | Whether to enable SSH | `false` |
+
+### Ingress
+
+As an alternative to istio the Nginx Ingress controller can be used to manage
+ingress traffic.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `ingress.enabled` | Whether to deploy an Ingress | `false` |
+| `ingress.host` | Host name to use for the Ingress (required for Ingress) | `nil` |
+| `ingress.maxBodySize` | Maximum request body size allowed (Set to 0 for an unlimited request body size) | `50m` |
+| `ingress.additionalAnnotations` | Additional annotations for the Ingress | `nil` |
+| `ingress.tls.enabled` | Whether to enable TLS termination in the Ingress | `false` |
+| `ingress.tls.secret.create` | Whether to create a TLS-secret | `true` |
+| `ingress.tls.secret.name` | Name of an external secret that will be used as a TLS-secret | `nil` |
+| `ingress.tls.cert` | Public SSL server certificate | `-----BEGIN CERTIFICATE-----` |
+| `ingress.tls.key` | Private SSL server certificate | `-----BEGIN RSA PRIVATE KEY-----` |
+
+***note
+For graceful shutdown to work with an ingress, the ingress controller has to be
+configured to gracefully close the connections as well.
+***
+
+### Promtail Sidecar
+
+To collect Gerrit logs, a Promtail sidecar can be deployed into the Gerrit replica
+pods. This can for example be used together with the [gerrit-monitoring](https://gerrit-review.googlesource.com/admin/repos/gerrit-monitoring)
+project.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `promtailSidecar.enabled` | Whether to install the Promatil sidecar container | `false` |
+| `promtailSidecar.image` | The promtail container image to use | `grafana/promtail` |
+| `promtailSidecar.version` | The promtail container image version | `1.3.0` |
+| `promtailSidecar.resources` | Configure the amount of resources the container requests/is allowed | `requests.cpu: 100m` |
+|                             |                                                                     | `requests.memory: 128Mi` |
+|                             |                                                                     | `limits.cpu: 200m` |
+|                             |                                                                     | `limits.memory: 128Mi` |
+| `promtailSidecar.tls.skipverify` | Whether to skip TLS verification | `true` |
+| `promtailSidecar.tls.caCert` | CA certificate for TLS verification | `-----BEGIN CERTIFICATE-----` |
+| `promtailSidecar.loki.url` | URL to reach Loki | `loki.example.com` |
+| `promtailSidecar.loki.user` | Loki user | `admin` |
+| `promtailSidecar.loki.password` | Loki password | `secret` |
+
+
+### Apache-Git-HTTP-Backend (Git-Backend)
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gitBackend.image` | Image name of the Apache-git-http-backend container image | `k8sgerrit/apache-git-http-backend` |
+| `gitBackend.additionalPodLabels` | Additional labels for Pods | `{}` |
+| `gitBackend.tolerations` | Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. For more information, please refer to the following documents. [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration) | [] |
+| `gitBackend.topologySpreadConstraints` | Control how Pods are spread across your cluster among failure-domains. For more information, please refer to the following documents. [Pod Topology Spread Constraints](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints) | {} |
+| `gitBackend.nodeSelector` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gitBackend.affinity` | Assigns a Pod to the specified Nodes | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].weight: 100 |
+|                       |                                      | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey: "topology.kubernetes.io/zone" |
+|                       |                                      | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].key: app |
+|                       |                                      | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].operator: In |
+|                       |                                      | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].values[0]: git-backend |
+| `gitBackend.replicas` | Number of pod replicas to deploy | `1` |
+| `gitBackend.maxSurge` | Max. percentage or number of pods allowed to be scheduled above the desired number | `25%` |
+| `gitBackend.maxUnavailable` | Max. percentage or number of pods allowed to be unavailable at a time | `100%` |
+| `gitBackend.networkPolicy.ingress` | Custom ingress-network policy for git-backend pods | `[{}]` (allow all) |
+| `gitBackend.networkPolicy.egress` | Custom egress-network policy for git-backend pods | `nil` |
+| `gitBackend.resources` | Configure the amount of resources the pod requests/is allowed | `requests.cpu: 100m` |
+|                        |                                                               | `requests.memory: 256Mi` |
+|                        |                                                               | `limits.cpu: 100m` |
+|                        |                                                               | `limits.memory: 256Mi` |
+| `gitBackend.livenessProbe` | Configuration of the liveness probe timings | `{initialDelaySeconds: 10, periodSeconds: 5}` |
+| `gitBackend.readinessProbe` | Configuration of the readiness probe timings | `{initialDelaySeconds: 5, periodSeconds: 1}` |
+| `gitBackend.credentials.htpasswd` | `.htpasswd`-file containing username/password-credentials for accessing git | `git:$apr1$O/LbLKC7$Q60GWE7OcqSEMSfe/K8xU.` (user: git, password: secret) |
+| `gitBackend.service.additionalAnnotations` | Additional annotations for the Service | `{}` |
+| `gitBackend.service.loadBalancerSourceRanges` | The list of allowed IPs for the Service | `[]` |
+| `gitBackend.service.type` | Which kind of Service to deploy | `LoadBalancer` |
+| `gitBackend.service.externalTrafficPolicy` | Specify how traffic from external is handled | `Cluster` |
+| `gitBackend.service.http.enabled` | Whether to serve HTTP-requests (needed for Ingress) | `true` |
+| `gitBackend.service.http.port` | Port over which to expose HTTP | `80` |
+| `gitBackend.service.https.enabled` | Whether to serve HTTPS-requests | `false` |
+| `gitBackend.service.https.port` | Port over which to expose HTTPS | `443` |
+
+***note
+At least one endpoint (HTTP and/or HTTPS) has to be enabled in the service!
+***
+
+Project creation, project deletion and HEAD update can also replicated. To enable
+this feature configure the replication plugin to use an adminUrl using the format
+`gerrit+https://<apache-git-http-backend host>`.
+
+### Git garbage collection
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gitGC.image` | Image name of the Git-GC container image | `k8sgerrit/git-gc` |
+| `gitGC.schedule` | Cron-formatted schedule with which to run Git garbage collection | `0 6,18 * * *` |
+| `gitGC.resources` | Configure the amount of resources the pod requests/is allowed | `requests.cpu: 100m` |
+|                   |                                                               | `requests.memory: 256Mi` |
+|                   |                                                               | `limits.cpu: 100m` |
+|                   |                                                               | `limits.memory: 256Mi` |
+| `gitGC.tolerations` | Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. For more information, please refer to the following documents. [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration) | [] |
+| `gitGC.nodeSelector` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gitGC.affinity` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes using Node Affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gitGC.additionalPodLabels` | Additional labels for Pods | `{}` |
+
+### Gerrit replica
+
+***note
+The way the Jetty servlet used by Gerrit works, the Gerrit replica component of the
+gerrit-replica 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!
+***
+
+***note
+Setting the canonical web URL in the gerrit.config to the host used for the Ingress
+is mandatory, if access to the Gerrit replica is required!
+***
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gerritReplica.images.gerritInit` | Image name of the Gerrit init container image | `k8sgerrit/gerrit-init` |
+| `gerritReplica.images.gerritReplica` | Image name of the Gerrit replica container image | `k8sgerrit/gerrit` |
+| `gerritReplica.tolerations` | Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. For more information, please refer to the following documents. [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration) | [] |
+| `gerritReplica.topologySpreadConstraints` | Control how Pods are spread across your cluster among failure-domains. For more information, please refer to the following documents. [Pod Topology Spread Constraints](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints) | {} |
+| `gerritReplica.nodeSelector` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gerritReplica.affinity` | Assigns a Pod to the specified Nodes. By default, gerrit-replica is evenly distributed on `topology.kubernetes.io/zone`. For more information, please refer to the following documents. [Assign Pods to Nodes using Node Affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].weight: 100 |
+| | | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey: "topology.kubernetes.io/zone" |
+| | | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].key: app |
+| | | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].operator: In |
+| | | podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].values[0]: gerrit-replica |
+| `gerritReplica.replicas` | Number of pod replicas to deploy | `1` |
+| `gerritReplica.additionalAnnotations` | Additional annotations for the Pods | {} |
+| `gerritReplica.additionalPodLabels` | Additional labels for the Pods | `{}` |
+| `gerritReplica.maxSurge` | Max. percentage or number of pods allowed to be scheduled above the desired number | `25%` |
+| `gerritReplica.maxUnavailable` | Max. percentage or number of pods allowed to be unavailable at a time | `100%` |
+| `gerritReplica.livenessProbe` | Configuration of the liveness probe timings | `{initialDelaySeconds: 60, periodSeconds: 5}` |
+| `gerritReplica.probeScheme` | Scheme for probes, for example HTTPS | `nil` |
+| `gerritReplica.readinessProbe` | Configuration of the readiness probe timings | `{initialDelaySeconds: 10, periodSeconds: 10}` |
+| `gerritReplica.startupProbe` | Configuration of the startup probe timings | `{initialDelaySeconds: 10, periodSeconds: 5}` |
+| `gerritReplica.gracefulStopTimeout` | Time in seconds Kubernetes will wait until killing the pod during termination (has to be longer then Gerrit's httpd.gracefulStopTimeout to allow graceful shutdown of Gerrit) | `90` |
+| `gerritReplica.resources` | Configure the amount of resources the pod requests/is allowed | `requests.cpu: 1` |
+|                           |                                                               | `requests.memory: 5Gi` |
+|                           |                                                               | `limits.cpu: 1` |
+|                           |                                                               | `limits.memory: 6Gi` |
+| `gerritReplica.networkPolicy.ingress` | Custom ingress-network policy for gerrit-replica pods | `nil` |
+| `gerritReplica.networkPolicy.egress` | Custom egress-network policy for gerrit-replica pods | `nil` |
+| `gerritReplica.service.additionalAnnotations` | Additional annotations for the Service | `{}` |
+| `gerritReplica.service.loadBalancerSourceRanges` | The list of allowed IPs for the Service | `[]` |
+| `gerritReplica.service.type` | Which kind of Service to deploy | `NodePort` |
+| `gerritReplica.service.externalTrafficPolicy` | Specify how traffic from external is handled | `Cluster` |
+| `gerritReplica.service.http.port` | Port over which to expose HTTP | `80` |
+| `gerritReplica.service.ssh.enabled` | Whether to enable SSH for the Gerrit replica | `false` |
+| `gerritReplica.service.ssh.port` | Port for SSH | `29418` |
+| `gerritReplica.keystore` | base64-encoded Java keystore (`cat keystore.jks \| base64`) to be used by Gerrit, when using SSL | `nil` |
+| `gerritReplica.pluginManagement.plugins` | List of Gerrit plugins to install | `[]` |
+| `gerritReplica.pluginManagement.plugins[0].name` | Name of plugin | `nil` |
+| `gerritReplica.pluginManagement.plugins[0].url` | Download url of plugin. If given the plugin will be downloaded, otherwise it will be installed from the gerrit.war-file. | `nil` |
+| `gerritReplica.pluginManagement.plugins[0].sha1` | SHA1 sum of plugin jar used to ensure file integrity and version (optional) | `nil` |
+| `gerritReplica.pluginManagement.plugins[0].installAsLibrary` | Whether the plugin should be symlinked to the lib-dir in the Gerrit site. | `nil` |
+| `gerritReplica.pluginManagement.libs` | List of Gerrit library modules to install | `[]` |
+| `gerritReplica.pluginManagement.libs[0].name` | Name of the lib module | `nil` |
+| `gerritReplica.pluginManagement.libs[0].url` | Download url of lib module. | `nil` |
+| `gerritReplica.pluginManagement.libs[0].sha1` | SHA1 sum of plugin jar used to ensure file integrity and version | `nil` |
+| `gerritReplica.pluginManagement.cache.enabled` | Whether to cache downloaded plugins | `false` |
+| `gerritReplica.pluginManagement.cache.size` | Size of the volume used to store cached plugins | `1Gi` |
+| `gerritReplica.priorityClassName` | Name of the PriorityClass to apply to replica pods | `nil` |
+| `gerritReplica.etc.config` | Map of config files (e.g. `gerrit.config`) that will be mounted to `$GERRIT_SITE/etc`by a ConfigMap | `{gerrit.config: ..., replication.config: ...}`[see here](#Gerrit-config-files) |
+| `gerritReplica.etc.secret` | Map of config files (e.g. `secure.config`) that will be mounted to `$GERRIT_SITE/etc`by a Secret | `{secure.config: ...}` [see here](#Gerrit-config-files) |
+| `gerritReplica.additionalConfigMaps` | Allows to mount additional ConfigMaps into a subdirectory of `$SITE/data` | `[]` |
+| `gerritReplica.additionalConfigMaps[*].name` | Name of the ConfigMap | `nil` |
+| `gerritReplica.additionalConfigMaps[*].subDir` | Subdirectory under `$SITE/data` into which the files should be symlinked | `nil` |
+| `gerritReplica.additionalConfigMaps[*].data` | Data of the ConfigMap. If not set, ConfigMap has to be created manually | `nil` |
+
+### Gerrit config files
+
+The gerrit-replica 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 `gerritReplica.etc.config` and `gerritReplica.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](https://gerrit-review.googlesource.com/Documentation/config-gerrit.html).
+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.
+
+- `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.
+
+- `httpd.gracefulStopTimeout` / `sshd.gracefulStopTimeout`
+
+    To enable graceful shutdown of the embedded jetty server and SSHD, a timeout
+    has to be set with this option. This will be the maximum time, Gerrit will wait
+    for HTTP requests to finish before shutdown.
+
+- `container.user`
+
+    The technical user in the Gerrit replica container is called `gerrit`. Thus, this
+    value is required to be `gerrit`.
+
+- `container.replica`
+
+    Since this chart is meant to install a Gerrit replica, this naturally has to be
+    `true`.
+
+- `container.javaHome`
+
+    This has to be set to `/usr/lib/jvm/java-11-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 the Gerrit replica does not index changes and a new
+Gerrit server will not yet necessarily have an user to validate authentication.
+
+The default configuration can be overwritten by adding the `healthcheck.config`
+file as a key-value pair to `gerritReplica.etc.config` as for every other configuration.
+
+SSH keys should be configured via the helm-chart using the `gerritReplica.etc.secret`
+map. Gerrit will create its own keys, if none are present in the site, but if
+multiple Gerrit pods are running, each Gerrit instance would have its own keys.
+Users accessing Gerrit via a load balancer would get issues due to changing
+host keys.
+
+## Upgrading the Chart
+
+To upgrade an existing installation of the gerrit-replica chart, e.g. to install
+a newer chart version or to use an updated custom `values.yaml`-file, execute
+the following command:
+
+```sh
+cd $(git rev-parse --show-toplevel)/helm-charts
+helm upgrade \
+  <release-name> \
+  ./gerrit-replica \ # path to chart
+  -f <path-to-custom-values>.yaml \
+```
+
+## Uninstalling the Chart
+
+To delete the chart from the cluster, use:
+
+```sh
+helm delete <release-name>
+```
diff --git a/charts/gerrit-replica/docs/nfs-provisioner.md b/charts/gerrit-replica/docs/nfs-provisioner.md
new file mode 100644
index 0000000..e2d0806
--- /dev/null
+++ b/charts/gerrit-replica/docs/nfs-provisioner.md
@@ -0,0 +1,64 @@
+# Installing a NFS-provisioner
+
+The Gerrit replica requires access to a persistent volume capable of running in
+`Read Write Many (RWM)`-mode to store the git repositories, since the repositories
+have to be accessed by mutiple pods. One possibility to provide such volumes
+is to install a provisioner for NFS-volumes into the same Kubernetes-cluster.
+This document will guide through the process.
+
+The [Kubernetes external-storage project](https://github.com/kubernetes-incubator/external-storage)
+provides an out-of-tree dynamic [provisioner](https://github.com/kubernetes-incubator/external-storage/tree/master/nfs)
+for NFS volumes. A chart exists for easy deployment of the project onto a
+Kubernetes cluster. The chart's sources can be found [here](https://github.com/helm/charts/tree/master/stable/nfs-server-provisioner).
+
+## Prerequisites
+
+This guide will use Helm to install the NFS-provisioner. Thus, Helm has to be
+installed.
+
+## Installing the nfs-server-provisioner chart
+
+A custom `values.yaml`-file containing a configuration tested with the
+gerrit-replica chart can be found in the `supplements/nfs`-directory in the
+gerrit-replica chart's root directory. In addition a file stating the tested
+version of the nfs-server-provisioner chart is present in the same directory.
+
+If needed, adapt the `values.yaml`-file for the nfs-server-provisioner chart
+further and then run:
+
+```sh
+cd $(git rev-parse --show-toplevel)/helm-charts/gerrit-replica/supplements/nfs
+helm install nfs \
+  stable/nfs-server-provisioner \
+  -f values.yaml \
+  --version $(cat VERSION)
+```
+
+For a description of the configuration options, refer to the
+[chart's documentation](https://github.com/helm/charts/blob/master/stable/nfs-server-provisioner/README.md).
+
+Here are some tips for configuring the nfs-server-provisioner chart to work with
+the gerrit-replica chart:
+
+- Deploying more than 1 `replica` led to some reliability issues in tests and
+  should be further tested for now, if required.
+- The name of the StorageClass created for NFS-volumes has to be the same as the
+  one defined in the gerrit-replica chart for `storageClasses.shared.name`
+- The StorageClas for NFS-volumes needs to have the parameter `mountOptions: vers=4.1`,
+  due to compatibility [issues](https://github.com/kubernetes-incubator/external-storage/issues/223)
+  with Ganesha.
+
+## Deleting the nfs-server-provisioner chart
+
+***note
+**Attention:** Never delete the nfs-server-provisioner chart, if there is still a
+PersistentVolumeClaim and Pods using a NFS-volume provisioned by the NFS server
+provisioner. This will lead to crashed pods, that will not be terminated correctly.
+***
+
+If no Pod or PVC is using a NFS-volume provisioned by the NFS server provisioner
+anymore, delete it like any other chart:
+
+```sh
+helm delete nfs
+```
diff --git a/charts/gerrit-replica/supplements/nfs/VERSION b/charts/gerrit-replica/supplements/nfs/VERSION
new file mode 100644
index 0000000..7dff5b8
--- /dev/null
+++ b/charts/gerrit-replica/supplements/nfs/VERSION
@@ -0,0 +1 @@
+0.2.1
\ No newline at end of file
diff --git a/charts/gerrit-replica/supplements/nfs/values.yaml b/charts/gerrit-replica/supplements/nfs/values.yaml
new file mode 100644
index 0000000..aa3d9ce
--- /dev/null
+++ b/charts/gerrit-replica/supplements/nfs/values.yaml
@@ -0,0 +1,42 @@
+# Deploying more than 1 `replica` led to some reliability issues in tests and
+# should be further tested for now, if required.
+replicaCount: 1
+
+image:
+  repository: quay.io/kubernetes_incubator/nfs-provisioner
+  tag: v1.0.9
+  pullPolicy: IfNotPresent
+
+service:
+  type: ClusterIP
+  nfsPort: 2049
+  mountdPort: 20048
+  rpcbindPort: 51413
+
+persistence:
+  enabled: true
+  storageClass: default
+  accessMode: ReadWriteOnce
+  size: 7.5Gi
+
+storageClass:
+  create: true
+  defaultClass: false
+  # The name of the StorageClass has to be the same as the one defined in the
+  # gerrit-replica chart for `storageClasses.shared.name`
+  name: shared-storage
+  parameters:
+    # Required!
+    mountOptions: vers=4.1
+  reclaimPolicy: Delete
+
+rbac:
+  create: true
+
+resources:
+  requests:
+    cpu: 100m
+    memory: 256Mi
+  limits:
+    cpu: 100m
+    memory: 256Mi
diff --git a/charts/gerrit-replica/templates/NOTES.txt b/charts/gerrit-replica/templates/NOTES.txt
new file mode 100644
index 0000000..30e263f
--- /dev/null
+++ b/charts/gerrit-replica/templates/NOTES.txt
@@ -0,0 +1,35 @@
+A Gerrit replica has been deployed.
+=================================
+
+The Apache-Git-HTTP-Backend is now ready to receive replication requests from the
+primary Gerrit. Please configure the replication plugin of the primary Gerrit to
+push the repositories to:
+
+{{ if .Values.istio.enabled -}}
+  http {{- if .Values.istio.tls.enabled -}} s {{- end -}} :// {{- .Values.istio.host -}} /${name}.git
+{{ else if .Values.ingress.enabled -}}
+  http {{- if .Values.ingress.tls.enabled -}} s {{- end -}} :// {{- .Values.ingress.host -}} /${name}.git
+{{- else }}
+  http://<EXTERNAL-IP>: {{- .Values.gitBackend.service.http.port -}} /${name}.git
+  The external IP of the service can be found by running:
+  kubectl get svc git-backend-service
+{{- end }}
+
+Project creation, project deletion and HEAD update can also be replicated. To enable
+this feature configure the replication plugin to use an adminUrl using the format
+`gerrit+http {{- if .Values.ingress.tls.enabled -}} s {{- end -}} :// {{- .Values.ingress.host -}}`.
+
+A detailed guide of how to configure Gerrit's replication plugin can be found here:
+
+https://gerrit.googlesource.com/plugins/replication/+doc/master/src/main/resources/Documentation/config.md
+
+The Gerrit replica is starting up.
+
+The initialization process may take some time. Afterwards the git repositories
+will be available under:
+
+{{ if .Values.istio.enabled -}}
+  http {{- if .Values.istio.tls.enabled -}} s {{- end -}} :// {{- .Values.istio.host -}} /<repository-name>.git
+{{- else }}
+  http {{- if .Values.ingress.tls.enabled -}} s {{- end -}} :// {{- .Values.ingress.host -}} /<repository-name>.git
+{{- end }}
diff --git a/charts/gerrit-replica/templates/_helpers.tpl b/charts/gerrit-replica/templates/_helpers.tpl
new file mode 100644
index 0000000..500d58c
--- /dev/null
+++ b/charts/gerrit-replica/templates/_helpers.tpl
@@ -0,0 +1,20 @@
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "gerrit-replica.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create secret to access docker registry
+*/}}
+{{- define "imagePullSecret" }}
+{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.images.registry.name (printf "%s:%s" .Values.images.registry.ImagePullSecret.username .Values.images.registry.ImagePullSecret.password | b64enc) | b64enc }}
+{{- end }}
+
+{{/*
+Add '/' to registry if needed.
+*/}}
+{{- define "registry" -}}
+{{ if .Values.images.registry.name }}{{- printf "%s/" .Values.images.registry.name -}}{{end}}
+{{- end -}}
diff --git a/charts/gerrit-replica/templates/gerrit-replica.configmap.yaml b/charts/gerrit-replica/templates/gerrit-replica.configmap.yaml
new file mode 100644
index 0000000..1aa9496
--- /dev/null
+++ b/charts/gerrit-replica/templates/gerrit-replica.configmap.yaml
@@ -0,0 +1,78 @@
+{{- $root := . -}}
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-gerrit-replica-configmap
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  {{- range $key, $value := .Values.gerritReplica.etc.config }}
+  {{ $key }}:
+{{ toYaml $value | indent 4 }}
+  {{- end }}
+  {{- if not (hasKey .Values.gerritReplica.etc.config "healthcheck.config") }}
+  healthcheck.config: |-
+    [healthcheck "auth"]
+      # On new instances there may be no users to use for healthchecks
+      enabled = false
+    [healthcheck "querychanges"]
+      # On new instances there won't be any changes to query
+      enabled = false
+  {{- end }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-gerrit-init-configmap
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  gerrit-init.yaml: |-
+    {{ if .Values.caCert -}}
+    caCertPath: /var/config/ca.crt
+    {{- end }}
+    pluginCacheEnabled: {{ .Values.gerritReplica.pluginManagement.cache.enabled }}
+    pluginCacheDir: /var/mnt/plugins
+    {{- if .Values.gerritReplica.pluginManagement.plugins }}
+    plugins:
+{{ toYaml .Values.gerritReplica.pluginManagement.plugins | indent 6}}
+    {{- end }}
+    {{- if .Values.gerritReplica.pluginManagement.libs }}
+    libs:
+{{ toYaml .Values.gerritReplica.pluginManagement.libs | indent 6}}
+    {{- end }}
+{{- range .Values.gerritReplica.additionalConfigMaps -}}
+{{- if .data }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name:  {{ $root.Release.Name }}-{{ .name }}
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ $root.Release.Name }}
+    chart: {{ template "gerrit-replica.chart" $root }}
+    heritage: {{ $root.Release.Service }}
+    release: {{ $root.Release.Name }}
+    {{- if $root.Values.additionalLabels }}
+{{ toYaml $root.Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+{{ toYaml .data | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/gerrit-replica.secrets.yaml b/charts/gerrit-replica/templates/gerrit-replica.secrets.yaml
new file mode 100644
index 0000000..ece9b9a
--- /dev/null
+++ b/charts/gerrit-replica/templates/gerrit-replica.secrets.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-gerrit-replica-secure-config
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  {{ if .Values.gerritReplica.keystore -}}
+  keystore: {{ .Values.gerritReplica.keystore }}
+  {{- end }}
+  {{- range $key, $value := .Values.gerritReplica.etc.secret }}
+  {{ $key }}: {{ $value | b64enc }}
+  {{- end }}
+type: Opaque
diff --git a/charts/gerrit-replica/templates/gerrit-replica.service.yaml b/charts/gerrit-replica/templates/gerrit-replica.service.yaml
new file mode 100644
index 0000000..01030b4
--- /dev/null
+++ b/charts/gerrit-replica/templates/gerrit-replica.service.yaml
@@ -0,0 +1,40 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Release.Name }}-gerrit-replica-service
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+  {{- if .Values.gerritReplica.service.additionalAnnotations }}
+  annotations:
+{{ toYaml .Values.gerritReplica.service.additionalAnnotations  | indent 4 }}
+  {{- end }}
+spec:
+  {{ with .Values.gerritReplica.service }}
+  {{- if .loadBalancerSourceRanges -}}
+  loadBalancerSourceRanges:
+{{- range .loadBalancerSourceRanges }}
+    - {{ . | quote }}
+{{- end }}
+  {{- end }}
+  ports:
+  - name: http
+    port: {{ .http.port }}
+    targetPort: 8080
+  {{ if .ssh.enabled -}}
+  - name: ssh
+    port: {{ .ssh.port }}
+    targetPort: 29418
+  {{- end }}
+  type: {{ .type }}
+  externalTrafficPolicy: {{ .externalTrafficPolicy }}
+  {{- end }}
+  selector:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
diff --git a/charts/gerrit-replica/templates/gerrit-replica.stateful-set.yaml b/charts/gerrit-replica/templates/gerrit-replica.stateful-set.yaml
new file mode 100644
index 0000000..8493c7a
--- /dev/null
+++ b/charts/gerrit-replica/templates/gerrit-replica.stateful-set.yaml
@@ -0,0 +1,346 @@
+{{- $root := . -}}
+
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ .Release.Name }}-gerrit-replica-statefulset
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  serviceName: {{ .Release.Name }}-gerrit-replica-service
+  replicas: {{ .Values.gerritReplica.replicas }}
+  updateStrategy:
+    rollingUpdate:
+      partition: {{ .Values.gerritReplica.updatePartition }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/component: gerrit-replica
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/component: gerrit-replica
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        chart: {{ template "gerrit-replica.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
+        {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 8 }}
+        {{- end }}
+        {{- if .Values.gerritReplica.additionalPodLabels }}
+{{ toYaml .Values.gerritReplica.additionalPodLabels  | indent 8 }}
+        {{- end }}
+      annotations:
+        chartRevision: "{{ .Release.Revision }}"
+        {{- if .Values.gerritReplica.additionalAnnotations }}
+{{ toYaml .Values.gerritReplica.additionalAnnotations  | indent 8 }}
+        {{- end }}
+    spec:
+      {{- with .Values.gerritReplica.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerritReplica.topologySpreadConstraints }}
+      topologySpreadConstraints:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerritReplica.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerritReplica.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerritReplica.priorityClassName }}
+      priorityClassName: {{ . }}
+      {{- end }}
+      terminationGracePeriodSeconds: {{ .Values.gerritReplica.gracefulStopTimeout }}
+      securityContext:
+        fsGroup: 100
+      {{ if .Values.images.registry.ImagePullSecret.name -}}
+      imagePullSecrets:
+      - name: {{ .Values.images.registry.ImagePullSecret.name }}
+      {{- range .Values.images.additionalImagePullSecrets }}
+      - name: {{ . }}
+      {{- end }}
+      {{- end }}
+      initContainers:
+      {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.chownOnStartup }}
+      - name: nfs-init
+        image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+        command:
+        - sh
+        - -c
+        args:
+        - |
+          chown 1000:100 /var/mnt/logs
+          chown 1000:100 /var/mnt/git
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        {{- if .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+      {{- end }}
+      - name: gerrit-init
+        image: {{ template "registry" . }}{{ .Values.gerritReplica.images.gerritInit }}:{{ .Values.images.version }}
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: gerrit-site
+          mountPath: "/var/gerrit"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: gerrit-init-config
+          mountPath: "/var/config/gerrit-init.yaml"
+          subPath: gerrit-init.yaml
+        {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+        {{- if and .Values.gerritReplica.pluginManagement.cache.enabled }}
+        - name: gerrit-plugin-cache
+          mountPath: "/var/mnt/plugins"
+        {{- end }}
+        - name: gerrit-config
+          mountPath: "/var/mnt/etc/config"
+        - name: gerrit-replica-secure-config
+          mountPath: "/var/mnt/etc/secret"
+        {{ if .Values.caCert -}}
+        - name: tls-ca
+          subPath: ca.crt
+          mountPath: "/var/config/ca.crt"
+        {{- end }}
+        {{- range .Values.gerritReplica.additionalConfigMaps }}
+        - name: {{ .name }}
+          mountPath: "/var/mnt/data/{{ .subDir }}"
+        {{- end }}
+      containers:
+      - name: gerrit-replica
+        image: {{ template "registry" . }}{{ .Values.gerritReplica.images.gerritReplica }}:{{ .Values.images.version }}
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        lifecycle:
+          preStop:
+            exec:
+              command:
+                - "/bin/ash"
+                - "-c"
+                - "kill -2 $(pidof java) && tail --pid=$(pidof java) -f /dev/null"
+        ports:
+        - name: http
+          containerPort: 8080
+        {{ if .Values.gerritReplica.service.ssh -}}
+        - name: ssh
+          containerPort: 29418
+        {{- end }}
+        volumeMounts:
+        - name: gerrit-site
+          mountPath: "/var/gerrit"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+        - name: gerrit-config
+          mountPath: "/var/mnt/etc/config"
+        - name: gerrit-replica-secure-config
+          mountPath: "/var/mnt/etc/secret"
+        {{- range .Values.gerritReplica.additionalConfigMaps }}
+        - name: {{ .name }}
+          mountPath: "/var/mnt/data/{{ .subDir }}"
+        {{- end }}
+        livenessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: http
+{{- if .Values.gerritReplica.probeScheme }}
+            scheme: {{ .Values.gerritReplica.probeScheme }}
+{{- end }}
+{{ toYaml .Values.gerritReplica.livenessProbe | indent 10 }}
+        readinessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: http
+{{- if .Values.gerritReplica.probeScheme }}
+            scheme: {{ .Values.gerritReplica.probeScheme }}
+{{- end }}
+{{ toYaml .Values.gerritReplica.readinessProbe | indent 10 }}
+        startupProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: http
+{{- if .Values.gerritReplica.probeScheme }}
+            scheme: {{ .Values.gerritReplica.probeScheme }}
+{{- end }}
+{{ toYaml .Values.gerritReplica.startupProbe | indent 10 }}
+        resources:
+{{ toYaml .Values.gerritReplica.resources | indent 10 }}
+      {{ if .Values.istio.enabled -}}
+      - name: istio-proxy
+        image: auto
+        lifecycle:
+          preStop:
+            exec:
+              command:
+              - "/bin/sh"
+              - "-c"
+              - "while [ $(netstat -plunt | grep tcp | grep -v envoy | wc -l | xargs) -ne 0 ]; do sleep 1; done"
+      {{- end }}
+      {{ if .Values.promtailSidecar.enabled -}}
+      - name: promtail
+        image: {{ .Values.promtailSidecar.image }}:v{{ .Values.promtailSidecar.version }}
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        command:
+        - sh
+        - -ec
+        args:
+        - |-
+          /usr/bin/promtail \
+            -config.file=/etc/promtail/promtail.yaml \
+            -client.url={{ .Values.promtailSidecar.loki.url }}/loki/api/v1/push \
+            -client.external-labels=instance=$HOSTNAME
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        resources:
+{{ toYaml .Values.promtailSidecar.resources | indent 10 }}
+        volumeMounts:
+        - name: promtail-config
+          mountPath: /etc/promtail/promtail.yaml
+          subPath: promtail.yaml
+        - name: promtail-secret
+          mountPath: /etc/promtail/promtail.secret
+          subPath: promtail.secret
+        {{- if not .Values.promtailSidecar.tls.skipVerify }}
+        - name: tls-ca
+          mountPath: /etc/promtail/promtail.ca.crt
+          subPath: ca.crt
+        {{- end }}
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/gerrit/logs"
+        {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+      {{- end }}
+      volumes:
+      {{ if not .Values.gerritReplica.persistence.enabled -}}
+      - name: gerrit-site
+        emptyDir: {}
+      {{- end }}
+      {{- if and .Values.gerritReplica.pluginManagement.cache.enabled }}
+      - name: gerrit-plugin-cache
+        persistentVolumeClaim:
+          claimName: {{ .Release.Name }}-plugin-cache-pvc
+      {{- end }}
+      - name: git-repositories
+        persistentVolumeClaim:
+          {{- if .Values.gitRepositoryStorage.externalPVC.use }}
+          claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-git-repositories-pvc
+          {{- end }}
+      - name: logs
+        {{ if .Values.logStorage.enabled -}}
+        persistentVolumeClaim:
+          {{- if .Values.logStorage.externalPVC.use }}
+          claimName: {{ .Values.logStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-log-pvc
+          {{- end }}
+        {{ else -}}
+        emptyDir: {}
+        {{- end }}
+      - name: gerrit-init-config
+        configMap:
+          name: {{ .Release.Name }}-gerrit-init-configmap
+      - name: gerrit-config
+        configMap:
+          name: {{ .Release.Name }}-gerrit-replica-configmap
+      - name: gerrit-replica-secure-config
+        secret:
+          secretName: {{ .Release.Name }}-gerrit-replica-secure-config
+      {{ if .Values.caCert -}}
+      - name: tls-ca
+        secret:
+          secretName: {{ .Release.Name }}-tls-ca
+      {{- end }}
+      {{- range .Values.gerritReplica.additionalConfigMaps }}
+      - name: {{ .name }}
+        configMap:
+          name: {{ if .data }}{{ $root.Release.Name }}-{{ .name }}{{ else }}{{ .name }}{{ end }}
+      {{- end }}
+      {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+      - name: nfs-config
+        configMap:
+          name: {{ .Release.Name }}-nfs-configmap
+      {{- end }}
+      {{ if .Values.promtailSidecar.enabled -}}
+      - name: promtail-config
+        configMap:
+          name: {{ .Release.Name }}-promtail-gerrit-configmap
+      - name: promtail-secret
+        secret:
+          secretName: {{ .Release.Name }}-promtail-secret
+      {{- end }}
+  {{ if .Values.gerritReplica.persistence.enabled -}}
+  volumeClaimTemplates:
+  - metadata:
+      name: gerrit-site
+      labels:
+        app.kubernetes.io/component: gerrit-replica
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        chart: {{ template "gerrit-replica.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
+        {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 8 }}
+        {{- end }}
+    spec:
+      accessModes:
+      - ReadWriteOnce
+      resources:
+        requests:
+          storage: {{ .Values.gerritReplica.persistence.size }}
+      storageClassName: {{ .Values.storageClasses.default.name }}
+  {{- end }}
diff --git a/charts/gerrit-replica/templates/gerrit-replica.storage.yaml b/charts/gerrit-replica/templates/gerrit-replica.storage.yaml
new file mode 100644
index 0000000..c710737
--- /dev/null
+++ b/charts/gerrit-replica/templates/gerrit-replica.storage.yaml
@@ -0,0 +1,22 @@
+{{- if and .Values.gerritReplica.pluginManagement.cache.enabled }}
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-plugin-cache-pvc
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: {{ .Values.gerritReplica.pluginManagement.cache.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/git-backend.deployment.yaml b/charts/gerrit-replica/templates/git-backend.deployment.yaml
new file mode 100644
index 0000000..037bcb9
--- /dev/null
+++ b/charts/gerrit-replica/templates/git-backend.deployment.yaml
@@ -0,0 +1,168 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Release.Name }}-git-backend-deployment
+  labels:
+    app.kubernetes.io/component: git-backend
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.gitBackend.replicas }}
+  strategy:
+    rollingUpdate:
+      maxSurge: {{ .Values.gitBackend.maxSurge }}
+      maxUnavailable: {{ .Values.gitBackend.maxUnavailable }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/component: git-backend
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/component: git-backend
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        chart: {{ template "gerrit-replica.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
+        {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 8 }}
+        {{- end }}
+        {{- if .Values.gitBackend.additionalPodLabels }}
+{{ toYaml .Values.gitBackend.additionalPodLabels  | indent 8 }}
+        {{- end }}
+      annotations:
+        chartRevision: "{{ .Release.Revision }}"
+    spec:
+      {{- with .Values.gitBackend.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gitBackend.topologySpreadConstraints }}
+      topologySpreadConstraints:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gitBackend.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gitBackend.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      securityContext:
+        fsGroup: 100
+      {{ if .Values.images.registry.ImagePullSecret.name -}}
+      imagePullSecrets:
+      - name: {{ .Values.images.registry.ImagePullSecret.name }}
+      {{- range .Values.images.additionalImagePullSecrets }}
+      - name: {{ . }}
+      {{- end }}
+      {{- end }}
+      initContainers:
+      {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.chownOnStartup }}
+      - name: nfs-init
+        image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+        command:
+        - sh
+        - -c
+        args:
+        - |
+          chown 1000:100 /var/mnt/logs
+          chown 1000:100 /var/mnt/git
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        {{- if .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+      {{- end }}
+      containers:
+      - name: apache-git-http-backend
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        image: {{ template "registry" . }}{{ .Values.gitBackend.image }}:{{ .Values.images.version }}
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        ports:
+        - name: http-port
+          containerPort: 80
+        resources:
+{{ toYaml .Values.gitBackend.resources | indent 10 }}
+        livenessProbe:
+          tcpSocket:
+            port: http-port
+{{ toYaml .Values.gitBackend.livenessProbe | indent 10 }}
+        readinessProbe:
+          tcpSocket:
+            port: http-port
+{{ toYaml .Values.gitBackend.readinessProbe | indent 10 }}
+        volumeMounts:
+        - name: git-repositories
+          mountPath: "/var/gerrit/git"
+        - name: logs
+          subPathExpr: "apache-git-http-backend/$(POD_NAME)"
+          mountPath: "/var/log/apache2"
+        {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+        - name: git-backend-secret
+          readOnly: true
+          subPath: .htpasswd
+          mountPath: "/var/apache/credentials/.htpasswd"
+      {{ if .Values.istio.enabled -}}
+      - name: istio-proxy
+        image: auto
+        lifecycle:
+          preStop:
+            exec:
+              command:
+              - "/bin/sh"
+              - "-c"
+              - "while [ $(netstat -plunt | grep tcp | grep -v envoy | wc -l | xargs) -ne 0 ]; do sleep 1; done"
+      {{- end }}
+      volumes:
+      - name: git-repositories
+        persistentVolumeClaim:
+          {{- if .Values.gitRepositoryStorage.externalPVC.use }}
+          claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-git-repositories-pvc
+          {{- end }}
+      - name: git-backend-secret
+        secret:
+          secretName: {{ .Release.Name }}-git-backend-secret
+      - name: logs
+        {{ if .Values.logStorage.enabled -}}
+        persistentVolumeClaim:
+          {{- if .Values.logStorage.externalPVC.use }}
+          claimName: {{ .Values.logStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-log-pvc
+          {{- end }}
+        {{ else -}}
+        emptyDir: {}
+        {{- end }}
+      {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+      - name: nfs-config
+        configMap:
+          name: {{ .Release.Name }}-nfs-configmap
+      {{- end }}
diff --git a/charts/gerrit-replica/templates/git-backend.secrets.yaml b/charts/gerrit-replica/templates/git-backend.secrets.yaml
new file mode 100644
index 0000000..94b1705
--- /dev/null
+++ b/charts/gerrit-replica/templates/git-backend.secrets.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-git-backend-secret
+  labels:
+    app.kubernetes.io/component: git-backend
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  .htpasswd: {{ required "A .htpasswd-file is required for the git backend." .Values.gitBackend.credentials.htpasswd | b64enc }}
+type: Opaque
diff --git a/charts/gerrit-replica/templates/git-backend.service.yaml b/charts/gerrit-replica/templates/git-backend.service.yaml
new file mode 100644
index 0000000..7bd47ef
--- /dev/null
+++ b/charts/gerrit-replica/templates/git-backend.service.yaml
@@ -0,0 +1,35 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Release.Name }}-git-backend-service
+  labels:
+    app.kubernetes.io/component: git-backend
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+  {{- if .Values.gitBackend.service.additionalAnnotations }}
+  annotations:
+{{ toYaml .Values.gitBackend.service.additionalAnnotations  | indent 4 }}
+  {{- end }}
+spec:
+  {{ with .Values.gitBackend.service }}
+  {{- if .loadBalancerSourceRanges -}}
+  loadBalancerSourceRanges:
+{{- range .loadBalancerSourceRanges }}
+    - {{ . | quote }}
+{{- end }}
+  {{- end }}
+  ports:
+  - name: http
+    port: {{ .http.port }}
+    targetPort: 80
+  type: {{ .type }}
+  externalTrafficPolicy: {{ .externalTrafficPolicy }}
+  {{- end }}
+  selector:
+    app.kubernetes.io/component: git-backend
+    app.kubernetes.io/instance: {{ .Release.Name }}
diff --git a/charts/gerrit-replica/templates/git-gc.cronjob.yaml b/charts/gerrit-replica/templates/git-gc.cronjob.yaml
new file mode 100644
index 0000000..028ffe9
--- /dev/null
+++ b/charts/gerrit-replica/templates/git-gc.cronjob.yaml
@@ -0,0 +1,134 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name:  {{ .Release.Name }}-git-gc
+  labels:
+    app.kubernetes.io/component: git-gc
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  schedule: {{ .Values.gitGC.schedule | quote }}
+  concurrencyPolicy: "Forbid"
+  jobTemplate:
+    spec:
+      template:
+        metadata:
+          annotations:
+            cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
+          {{ if .Values.istio.enabled }}
+            sidecar.istio.io/inject: "false"
+          {{- end }}
+          labels:
+            app.kubernetes.io/component: git-gc
+            app.kubernetes.io/instance: {{ .Release.Name }}
+            chart: {{ template "gerrit-replica.chart" . }}
+            heritage: {{ .Release.Service }}
+            release: {{ .Release.Name }}
+            {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 12 }}
+            {{- end }}
+            {{- if .Values.gitGC.additionalPodLabels }}
+{{ toYaml .Values.gitGC.additionalPodLabels  | indent 12 }}
+            {{- end }}
+        spec:
+          {{- with .Values.gitGC.tolerations }}
+          tolerations:
+            {{- toYaml . | nindent 10 }}
+          {{- end }}
+          {{- with .Values.gitGC.nodeSelector }}
+          nodeSelector:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          {{- with .Values.gitGC.affinity }}
+          affinity:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          restartPolicy: OnFailure
+          securityContext:
+            fsGroup: 100
+          {{ if .Values.images.registry.ImagePullSecret.name -}}
+          imagePullSecrets:
+          - name: {{ .Values.images.registry.ImagePullSecret.name }}
+          {{- range .Values.images.additionalImagePullSecrets }}
+          - name: {{ . }}
+          {{- end }}
+          {{- end }}
+          initContainers:
+          {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.chownOnStartup }}
+          - name: nfs-init
+            image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+            command:
+            - sh
+            - -c
+            args:
+            - |
+              chown 1000:100 /var/mnt/logs
+              chown 1000:100 /var/mnt/git
+            env:
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            volumeMounts:
+            - name: logs
+              subPathExpr: "git-gc/$(POD_NAME)"
+              mountPath: "/var/mnt/logs"
+            - name: git-repositories
+              mountPath: "/var/mnt/git"
+            {{- if .Values.nfsWorkaround.idDomain }}
+            - name: nfs-config
+              mountPath: "/etc/idmapd.conf"
+              subPath: idmapd.conf
+            {{- end }}
+          {{- end }}
+          containers:
+          - name: git-gc
+            imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+            image: {{ template "registry" . }}{{ .Values.gitGC.image }}:{{ .Values.images.version }}
+            resources:
+{{ toYaml .Values.gitGC.resources | indent 14 }}
+            env:
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            volumeMounts:
+            - name: git-repositories
+              mountPath: "/var/gerrit/git"
+            - name: logs
+              subPathExpr: "git-gc/$(POD_NAME)"
+              mountPath: "/var/log/git"
+            {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+            - name: nfs-config
+              mountPath: "/etc/idmapd.conf"
+              subPath: idmapd.conf
+            {{- end }}
+          volumes:
+          - name: git-repositories
+            persistentVolumeClaim:
+              {{- if .Values.gitRepositoryStorage.externalPVC.use }}
+              claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-git-repositories-pvc
+              {{- end }}
+          - name: logs
+            {{ if .Values.logStorage.enabled -}}
+            persistentVolumeClaim:
+              {{- if .Values.logStorage.externalPVC.use }}
+              claimName: {{ .Values.logStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-log-pvc
+              {{- end }}
+            {{ else -}}
+            emptyDir: {}
+            {{- end }}
+          {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+          - name: nfs-config
+            configMap:
+              name: {{ .Release.Name }}-nfs-configmap
+          {{- end }}
diff --git a/charts/gerrit-replica/templates/global.secrets.yaml b/charts/gerrit-replica/templates/global.secrets.yaml
new file mode 100644
index 0000000..7dfe4a1
--- /dev/null
+++ b/charts/gerrit-replica/templates/global.secrets.yaml
@@ -0,0 +1,18 @@
+{{ if .Values.caCert -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-tls-ca
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  ca.crt: {{ .Values.caCert | b64enc }}
+type: Opaque
+{{- end }}
diff --git a/charts/gerrit-replica/templates/image-pull.secret.yaml b/charts/gerrit-replica/templates/image-pull.secret.yaml
new file mode 100644
index 0000000..3f97cd0
--- /dev/null
+++ b/charts/gerrit-replica/templates/image-pull.secret.yaml
@@ -0,0 +1,13 @@
+{{ if and .Values.images.registry.ImagePullSecret.name .Values.images.registry.ImagePullSecret.create -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ .Values.images.registry.ImagePullSecret.name }}
+  labels:
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+type: kubernetes.io/dockerconfigjson
+data:
+  .dockerconfigjson: {{ template "imagePullSecret" . }}
+{{- end }}
\ No newline at end of file
diff --git a/charts/gerrit-replica/templates/ingress.yaml b/charts/gerrit-replica/templates/ingress.yaml
new file mode 100644
index 0000000..e78dfcc
--- /dev/null
+++ b/charts/gerrit-replica/templates/ingress.yaml
@@ -0,0 +1,86 @@
+{{ if and .Values.ingress.enabled (not .Values.istio.enabled) -}}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ .Release.Name }}-ingress
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+  annotations:
+    kubernetes.io/ingress.class: nginx
+    nginx.ingress.kubernetes.io/proxy-body-size: {{ .Values.ingress.maxBodySize | default "50m" }}
+    nginx.ingress.kubernetes.io/use-regex: "true"
+    nginx.ingress.kubernetes.io/configuration-snippet: |-
+      if ($args ~ service=git-receive-pack){
+        set $proxy_upstream_name "{{ .Release.Namespace }}-{{ .Release.Name }}-git-backend-service-http";
+        set $proxy_host $proxy_upstream_name;
+        set $service_name "{{ .Release.Name }}-git-backend-service";
+      }
+    {{- if .Values.ingress.additionalAnnotations }}
+{{ toYaml .Values.ingress.additionalAnnotations  | indent 4 }}
+    {{- end }}
+spec:
+  {{ if .Values.ingress.tls.enabled -}}
+  tls:
+  - hosts:
+    - {{ .Values.ingress.host }}
+    {{ if .Values.ingress.tls.secret.create -}}
+    secretName: {{ .Release.Name }}-tls-secret
+    {{- else }}
+    secretName: {{ .Values.ingress.tls.secret.name }}
+    {{- end }}
+  {{- end }}
+  rules:
+  - host: {{required "A host URL is required for the ingress. Please set 'ingress.host'" .Values.ingress.host }}
+    http:
+      paths:
+      - pathType: Prefix
+        path: /a/projects
+        backend:
+          service:
+            name: {{ .Release.Name }}-git-backend-service
+            port:
+              number: {{ .Values.gitBackend.service.http.port }}
+      - pathType: Prefix
+        path: "/.*/git-receive-pack"
+        backend:
+          service:
+            name: {{ .Release.Name }}-git-backend-service
+            port:
+              number: {{ .Values.gitBackend.service.http.port }}
+      - pathType: Prefix
+        path: /
+        backend:
+          service:
+            name: {{ .Release.Name }}-gerrit-replica-service
+            port:
+              number: {{ .Values.gerritReplica.service.http.port }}
+{{- end }}
+---
+{{ if and (and .Values.ingress.tls.enabled .Values.ingress.tls.secret.create) (not .Values.istio.enabled) -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-tls-secret
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+type: kubernetes.io/tls
+data:
+  {{ with .Values.ingress.tls -}}
+  tls.crt: {{ .cert | b64enc }}
+  tls.key: {{ .key | b64enc }}
+  {{- end }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/istio.ingressgateway.yaml b/charts/gerrit-replica/templates/istio.ingressgateway.yaml
new file mode 100644
index 0000000..5938536
--- /dev/null
+++ b/charts/gerrit-replica/templates/istio.ingressgateway.yaml
@@ -0,0 +1,144 @@
+{{ if .Values.istio.enabled -}}
+{{ if and .Values.istio.tls.enabled .Values.istio.tls.secret.create }}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-istio-tls-secret
+  namespace: istio-system
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+type: kubernetes.io/tls
+data:
+  {{ with .Values.istio.tls -}}
+  tls.crt: {{ .cert | b64enc }}
+  tls.key: {{ .key | b64enc }}
+  {{- end }}
+{{- end }}
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: Gateway
+metadata:
+  name: {{ .Release.Name }}-istio-gateway
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  selector:
+    istio: ingressgateway
+  servers:
+  - port:
+      number: 80
+      name: http
+      protocol: HTTP
+    hosts:
+    - {{ .Values.istio.host }}
+  {{ if .Values.istio.tls.enabled }}
+    tls:
+      httpsRedirect: true
+  - port:
+      number: 443
+      name: https
+      protocol: HTTPS
+    hosts:
+    - {{ .Values.istio.host }}
+    tls:
+      mode: SIMPLE
+      {{ if .Values.istio.tls.secret.create }}
+      credentialName: {{ .Release.Name }}-istio-tls-secret
+      {{- else  }}
+      credentialName: {{ .Values.istio.tls.secret.name }}
+      {{- end }}
+  {{- end }}
+  {{ if .Values.istio.ssh.enabled }}
+  - port:
+      number: 29418
+      name: ssh
+      protocol: TCP
+    hosts:
+    - {{ .Values.istio.host }}
+  {{- end }}
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+  name: {{ .Release.Name }}-istio-virtual-service
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  hosts:
+  - {{ .Values.istio.host }}
+  gateways:
+  - {{ .Release.Name }}-istio-gateway
+  http:
+  - name: apache-git-http-backend
+    match:
+    - uri:
+        prefix: "/a/projects/"
+    - uri:
+        regex: "/.*/git-receive-pack"
+    - uri:
+        regex: "/.*/info/refs"
+      queryParams:
+        service:
+          exact: git-receive-pack
+    route:
+    - destination:
+        host: {{ .Release.Name }}-git-backend-service.{{ .Release.Namespace }}.svc.cluster.local
+        port:
+          number: 80
+  - name: gerrit-replica
+    route:
+    - destination:
+        host: {{ .Release.Name }}-gerrit-replica-service.{{ .Release.Namespace }}.svc.cluster.local
+        port:
+          number: 80
+  {{ if .Values.istio.ssh.enabled }}
+  tcp:
+  - match:
+    - port: {{ .Values.gerritReplica.service.ssh.port }}
+    route:
+    - destination:
+        host: {{ .Release.Name }}-gerrit-replica-service.{{ .Release.Namespace }}.svc.cluster.local
+        port:
+          number: {{ .Values.gerritReplica.service.ssh.port }}
+  {{- end }}
+---
+apiVersion: networking.istio.io/v1alpha3
+kind: DestinationRule
+metadata:
+  name: {{ .Release.Name }}-gerrit-destination-rule
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  host: {{ .Release.Name }}-gerrit-replica-service.{{ .Release.Namespace }}.svc.cluster.local
+  trafficPolicy:
+    loadBalancer:
+      simple: LEAST_CONN
+{{- end }}
diff --git a/charts/gerrit-replica/templates/log-cleaner.cronjob.yaml b/charts/gerrit-replica/templates/log-cleaner.cronjob.yaml
new file mode 100644
index 0000000..cbeb88f
--- /dev/null
+++ b/charts/gerrit-replica/templates/log-cleaner.cronjob.yaml
@@ -0,0 +1,69 @@
+{{- if and .Values.logStorage.enabled .Values.logStorage.cleanup.enabled }}
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: {{ .Release.Name }}-log-cleaner
+  labels:
+    app.kubernetes.io/component: log-cleaner
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  schedule: {{ .Values.logStorage.cleanup.schedule | quote }}
+  concurrencyPolicy: "Forbid"
+  jobTemplate:
+    spec:
+      template:
+        metadata:
+          labels:
+            app.kubernetes.io/component: log-cleaner
+            app.kubernetes.io/instance: {{ .Release.Name }}
+            chart: {{ template "gerrit-replica.chart" . }}
+            heritage: {{ .Release.Service }}
+            release: {{ .Release.Name }}
+            {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 12 }}
+            {{- end }}
+            {{- if .Values.logStorage.cleanup.additionalPodLabels }}
+{{ toYaml .Values.logStorage.cleanup.additionalPodLabels  | indent 12 }}
+            {{- end }}
+        {{ if .Values.istio.enabled -}}
+          annotations:
+            sidecar.istio.io/inject: "false"
+        {{- end }}
+        spec:
+          restartPolicy: OnFailure
+          containers:
+          - name: log-cleaner
+            imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+            image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+            command:
+            - sh
+            - -c
+            args:
+            - |
+              find /var/logs/ \
+                -mindepth 1 \
+                -type f \
+                -mtime +{{ .Values.logStorage.cleanup.retentionDays }} \
+                -print \
+                -delete
+              find /var/logs/ -type d -empty -delete
+            resources:
+{{ toYaml .Values.logStorage.cleanup.resources | indent 14 }}
+            volumeMounts:
+            - name: logs
+              mountPath: "/var/logs"
+          volumes:
+          - name: logs
+            persistentVolumeClaim:
+              {{- if .Values.logStorage.externalPVC.use }}
+              claimName: {{ .Values.logStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-log-pvc
+              {{- end }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/netpol.yaml b/charts/gerrit-replica/templates/netpol.yaml
new file mode 100644
index 0000000..72a2bbd
--- /dev/null
+++ b/charts/gerrit-replica/templates/netpol.yaml
@@ -0,0 +1,248 @@
+{{ if .Values.networkPolicies.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: {{ .Release.Name }}-default-deny-all
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  policyTypes:
+  - Ingress
+  - Egress
+  ingress: []
+  egress: []
+---
+{{ if .Values.networkPolicies.dnsPorts -}}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ .Release.Name }}-allow-dns-access
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  policyTypes:
+  - Egress
+  egress:
+  - ports:
+    {{ range .Values.networkPolicies.dnsPorts -}}
+    - port: {{ . }}
+      protocol: UDP
+    - port: {{ . }}
+      protocol: TCP
+    {{ end }}
+{{- end }}
+---
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-replica-allow-external
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: gerrit-replica
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  ingress:
+  - ports:
+    - port: 8080
+    from: []
+---
+{{ if or .Values.gitBackend.networkPolicy.ingress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: git-backend-custom-ingress-policies
+  labels:
+    app.kubernetes.io/component: git-backend
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  policyTypes:
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: git-backend
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  ingress:
+{{ toYaml .Values.gitBackend.networkPolicy.ingress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gitBackend.networkPolicy.egress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: git-backend-custom-egress-policies
+  labels:
+    app.kubernetes.io/component: git-backend
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  policyTypes:
+  - Egress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: git-backend
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  egress:
+{{ toYaml .Values.gitBackend.networkPolicy.egress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gerritReplica.networkPolicy.ingress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-replica-custom-ingress-policies
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  policyTypes:
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: gerrit-replica
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  ingress:
+{{ toYaml .Values.gerritReplica.networkPolicy.ingress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gerritReplica.networkPolicy.egress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-replica-custom-egress-policies
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  policyTypes:
+  - Egress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: gerrit-replica
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  egress:
+{{ toYaml .Values.gerritReplica.networkPolicy.egress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.istio.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: istio-proxy
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  policyTypes:
+  - Egress
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  egress:
+  - ports:
+    - protocol: TCP
+      port: 15012
+  ingress:
+  - ports:
+    - protocol: TCP
+      port: 15012
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ .Release.Name }}-istio-ingress
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit-replica.chart" . }}
+      release: {{ .Release.Name }}
+  ingress:
+  - ports:
+    - protocol: TCP
+      port: 80
+    {{ if .Values.istio.ssh.enabled }}
+    - protocol: TCP
+      port: {{ .Values.gerritReplica.service.ssh.port }}
+    {{- end }}
+    from:
+    - namespaceSelector:
+        matchLabels:
+          name: istio-system
+    - podSelector:
+        matchLabels:
+          istio: ingressgateway
+
+{{- end }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/nfs.configmap.yaml b/charts/gerrit-replica/templates/nfs.configmap.yaml
new file mode 100644
index 0000000..32b167b
--- /dev/null
+++ b/charts/gerrit-replica/templates/nfs.configmap.yaml
@@ -0,0 +1,28 @@
+{{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain -}}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-nfs-configmap
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  idmapd.conf: |-
+    [General]
+
+    Verbosity = 0
+    Pipefs-Directory = /run/rpc_pipefs
+    # set your own domain here, if it differs from FQDN minus hostname
+    Domain = {{ .Values.nfsWorkaround.idDomain }}
+
+    [Mapping]
+
+    Nobody-User = nobody
+    Nobody-Group = nogroup
+{{- end }}
diff --git a/charts/gerrit-replica/templates/promtail.configmap.yaml b/charts/gerrit-replica/templates/promtail.configmap.yaml
new file mode 100644
index 0000000..8dac380
--- /dev/null
+++ b/charts/gerrit-replica/templates/promtail.configmap.yaml
@@ -0,0 +1,94 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-promtail-gerrit-configmap
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  promtail.yaml: |-
+    positions:
+      filename: /var/gerrit/logs/promtail-positions.yaml
+
+    client:
+        tls_config:
+          insecure_skip_verify: {{ .Values.promtailSidecar.tls.skipVerify }}
+          {{- if not .Values.promtailSidecar.tls.skipVerify }}
+          ca_file: /etc/promtail/promtail.ca.crt
+          {{- end }}
+        basic_auth:
+          username: {{ .Values.promtailSidecar.loki.user }}
+          password_file: /etc/promtail/promtail.secret
+    scrape_configs:
+    - job_name: gerrit_error
+      static_configs:
+      - targets:
+        - localhost
+        labels:
+          job: gerrit_error
+          __path__: /var/gerrit/logs/error_log.json
+      entry_parser: raw
+      pipeline_stages:
+      - json:
+          expressions:
+            timestamp: '"@timestamp"'
+            message:
+      - template:
+          source: timestamp
+          template: {{`'{{ Replace .Value "," "." 1 }}'`}}
+      - template:
+          source: timestamp
+          template: {{`'{{ Replace .Value "Z" " +0000" 1 }}'`}}
+      - template:
+          source: timestamp
+          template: {{`'{{ Replace .Value "T" " " 1 }}'`}}
+      - timestamp:
+          source: timestamp
+          format: "2006-01-02 15:04:05.999 -0700"
+      - regex:
+          source: message
+          expression: "Gerrit Code Review (?P<gerrit_version>.*) ready"
+      - labels:
+          gerrit_version:
+    - job_name: gerrit_httpd
+      static_configs:
+      - targets:
+        - localhost
+        labels:
+          job: gerrit_httpd
+          __path__: /var/gerrit/logs/httpd_log.json
+      entry_parser: raw
+      pipeline_stages:
+      - json:
+          expressions:
+            timestamp: null
+      - template:
+          source: timestamp
+          template: {{`'{{ Replace .Value "," "." 1 }}'`}}
+      - timestamp:
+          format: 02/Jan/2006:15:04:05.999 -0700
+          source: timestamp
+    - job_name: gerrit_sshd
+      static_configs:
+      - targets:
+        - localhost
+        labels:
+          job: gerrit_sshd
+          __path__: /var/gerrit/logs/sshd_log.json
+      entry_parser: raw
+      pipeline_stages:
+      - json:
+          expressions:
+            timestamp:
+      - template:
+          source: timestamp
+          template: {{`'{{ Replace .Value "," "." 1 }}'`}}
+      - timestamp:
+          source: timestamp
+          format: 2006-01-02 15:04:05.999 -0700
diff --git a/charts/gerrit-replica/templates/promtail.secret.yaml b/charts/gerrit-replica/templates/promtail.secret.yaml
new file mode 100644
index 0000000..012fb5b
--- /dev/null
+++ b/charts/gerrit-replica/templates/promtail.secret.yaml
@@ -0,0 +1,18 @@
+{{ if .Values.promtailSidecar.enabled -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-promtail-secret
+  labels:
+    app.kubernetes.io/component: gerrit-replica
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+type: Opaque
+data:
+  promtail.secret: {{ .Values.promtailSidecar.loki.password | b64enc }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/storage.pvc.yaml b/charts/gerrit-replica/templates/storage.pvc.yaml
new file mode 100644
index 0000000..5f8974e
--- /dev/null
+++ b/charts/gerrit-replica/templates/storage.pvc.yaml
@@ -0,0 +1,27 @@
+{{- if not .Values.gitRepositoryStorage.externalPVC.use }}
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-git-repositories-pvc
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: {{ .Values.gitRepositoryStorage.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
+{{- if and .Values.logStorage.enabled (not .Values.logStorage.externalPVC.use) }}
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-log-pvc
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: {{ .Values.logStorage.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
diff --git a/charts/gerrit-replica/templates/storageclasses.yaml b/charts/gerrit-replica/templates/storageclasses.yaml
new file mode 100644
index 0000000..fb91856
--- /dev/null
+++ b/charts/gerrit-replica/templates/storageclasses.yaml
@@ -0,0 +1,57 @@
+{{ if .Values.storageClasses.default.create -}}
+kind: StorageClass
+apiVersion: storage.k8s.io/v1
+metadata:
+  name: {{ .Values.storageClasses.default.name }}
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+provisioner: {{ .Values.storageClasses.default.provisioner }}
+reclaimPolicy: {{ .Values.storageClasses.default.reclaimPolicy }}
+{{ if .Values.storageClasses.default.parameters -}}
+parameters:
+{{- range $key, $value := .Values.storageClasses.default.parameters }}
+  {{ $key }}: {{ $value }}
+{{- end }}
+{{ if .Values.storageClasses.default.mountOptions -}}
+mountOptions:
+{{- range .Values.storageClasses.default.mountOptions }}
+  - {{ . }}
+{{- end }}
+{{- end }}
+allowVolumeExpansion: {{ .Values.storageClasses.default.allowVolumeExpansion }}
+{{- end }}
+{{- end }}
+---
+{{ if .Values.storageClasses.shared.create -}}
+kind: StorageClass
+apiVersion: storage.k8s.io/v1
+metadata:
+  name: {{ .Values.storageClasses.shared.name }}
+  labels:
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+provisioner: {{ .Values.storageClasses.shared.provisioner }}
+reclaimPolicy: {{ .Values.storageClasses.shared.reclaimPolicy }}
+{{ if .Values.storageClasses.shared.parameters -}}
+parameters:
+{{- range $key, $value := .Values.storageClasses.shared.parameters }}
+  {{ $key }}: {{ $value }}
+{{- end }}
+{{ if .Values.storageClasses.shared.mountOptions -}}
+mountOptions:
+{{- range .Values.storageClasses.shared.mountOptions }}
+  - {{ . }}
+{{- end }}
+{{- end }}
+allowVolumeExpansion: {{ .Values.storageClasses.shared.allowVolumeExpansion }}
+{{- end }}
+{{- end }}
diff --git a/charts/gerrit-replica/values.yaml b/charts/gerrit-replica/values.yaml
new file mode 100644
index 0000000..f2ba93c
--- /dev/null
+++ b/charts/gerrit-replica/values.yaml
@@ -0,0 +1,433 @@
+images:
+  busybox:
+    registry: docker.io
+    tag: latest
+  # Registry used for container images created by this project
+  registry:
+    # The registry name must NOT contain a trailing slash
+    name:
+    ImagePullSecret:
+      # Leave blank, if no ImagePullSecret is needed.
+      name: image-pull-secret
+      # If set to false, the gerrit-replica chart expects either a ImagePullSecret
+      # with the name configured above to be present on the cluster or that no
+      # credentials are needed.
+      create: false
+      username:
+      password:
+  version: latest
+  imagePullPolicy: Always
+  # Additional ImagePullSecrets that already exist and should be used by the
+  # pods of this chart. E.g. to pull busybox from dockerhub.
+  additionalImagePullSecrets: []
+
+# Additional labels that should be applied to all resources
+additionalLabels: {}
+
+storageClasses:
+  # Storage class used for storing logs and other pod-specific persisted data
+  default:
+    # If create is set to false, an existing StorageClass with the given
+    # name is expected to exist in the cluster. Setting create to true will
+    # create a storage class with the parameters given below.
+    name: default
+    create: false
+    provisioner: kubernetes.io/aws-ebs
+    reclaimPolicy: Delete
+    # Use the parameters key to set all parameters needed for the provisioner
+    parameters:
+      type: gp2
+      fsType: ext4
+    mountOptions: []
+    allowVolumeExpansion: false
+  # Storage class used for storing git repositories. Has to provide RWM access.
+  shared:
+    # If create is set to false, an existing StorageClass with RWM access
+    # mode and the given name has to be provided.
+    name: shared-storage
+    create: false
+    provisioner: nfs
+    reclaimPolicy: Delete
+    # Use the parameters key to set all parameters needed for the provisioner
+    parameters:
+      mountOptions: vers=4.1
+    mountOptions: []
+    allowVolumeExpansion: false
+
+nfsWorkaround:
+  enabled: false
+  chownOnStartup: false
+  idDomain: localdomain.com
+
+
+networkPolicies:
+  enabled: false
+  dnsPorts:
+  - 53
+  - 8053
+
+
+gitRepositoryStorage:
+  externalPVC:
+    use: false
+    name: git-repositories-pvc
+  size: 5Gi
+
+
+logStorage:
+  enabled: false
+  externalPVC:
+    use: false
+    name: gerrit-logs-pvc
+  size: 5Gi
+  cleanup:
+    enabled: false
+    additionalPodLabels: {}
+    schedule: "0 0 * * *"
+    retentionDays: 14
+    resources:
+      requests:
+        cpu: 100m
+        memory: 256Mi
+      limits:
+        cpu: 100m
+        memory: 256Mi
+
+
+istio:
+  enabled: false
+  host:
+  tls:
+    enabled: false
+    secret:
+      # If using an external secret, make sure to name the keys `tls.crt`
+      # and `tls.key`, respectively.
+      create: true
+      # `name` will only be used, if `create` is set to false to bind an
+      # existing secret. Otherwise the name will be automatically generated to
+      # avoid conflicts between multiple chart installations.
+      name:
+    # `cert`and `key` will only be used, if the secret will be created by
+    # this chart.
+    cert: |-
+      -----BEGIN CERTIFICATE-----
+
+      -----END CERTIFICATE-----
+    key: |-
+      -----BEGIN RSA PRIVATE KEY-----
+
+      -----END RSA PRIVATE KEY-----
+  ssh:
+    enabled: false
+
+caCert:
+
+ingress:
+  enabled: false
+  host:
+  # The maximum body size to allow for requests. Use "0" to allow unlimited
+  # reuqest body sizes.
+  maxBodySize: 50m
+  additionalAnnotations:
+    kubernetes.io/ingress.class: nginx
+  #  nginx.ingress.kubernetes.io/server-alias: example.com
+  #  nginx.ingress.kubernetes.io/whitelist-source-range: xxx.xxx.xxx.xxx
+  tls:
+    enabled: false
+    secret:
+      # If using an external secret, make sure to name the keys `tls.crt`
+      # and `tls.key`, respectively.
+      create: true
+      # `name` will only be used, if `create` is set to false to bind an
+      # existing secret. Otherwise the name will be automatically generated to
+      # avoid conflicts between multiple chart installations.
+      name:
+    # `cert`and `key` will only be used, if the secret will be created by
+    # this chart.
+    cert: |-
+      -----BEGIN CERTIFICATE-----
+
+      -----END CERTIFICATE-----
+    key: |-
+      -----BEGIN RSA PRIVATE KEY-----
+
+      -----END RSA PRIVATE KEY-----
+
+promtailSidecar:
+  enabled: false
+  image: grafana/promtail
+  version: 1.3.0
+  resources:
+    requests:
+      cpu: 100m
+      memory: 128Mi
+    limits:
+      cpu: 200m
+      memory: 128Mi
+  tls:
+    skipVerify: true
+  loki:
+    url: loki.example.com
+    user: admin
+    password: secret
+
+
+gitBackend:
+  image: k8sgerrit/apache-git-http-backend
+
+  additionalPodLabels: {}
+  tolerations: []
+  topologySpreadConstraints: {}
+  nodeSelector: {}
+  affinity:
+    podAntiAffinity:
+      preferredDuringSchedulingIgnoredDuringExecution:
+      - weight: 100
+        podAffinityTerm:
+          labelSelector:
+            matchExpressions:
+            - key: app
+              operator: In
+              values:
+              - git-backend
+          topologyKey: "topology.kubernetes.io/zone"
+
+  replicas: 1
+  maxSurge: 25%
+  # For just one replica, 100 % unavailability has to be allowed for updates to
+  # work.
+  maxUnavailable: 100%
+
+  # The general NetworkPolicy rules implemented by this chart may be too restrictive
+  # for some setups. Here custom rules may be added to whitelist some additional
+  # connections.
+  networkPolicy:
+    # This allows ingress traffic from all sources. If possible, this should be
+    # limited to the respective primary Gerrit that replicates to this replica.
+    ingress:
+    - {}
+    egress: []
+
+  resources:
+    requests:
+      cpu: 100m
+      memory: 256Mi
+    limits:
+      cpu: 100m
+      memory: 256Mi
+
+  livenessProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 5
+
+  readinessProbe:
+    initialDelaySeconds: 5
+    periodSeconds: 1
+
+  service:
+    additionalAnnotations: {}
+    loadBalancerSourceRanges: []
+    type: NodePort
+    externalTrafficPolicy: Cluster
+    http:
+      port: 80
+
+  credentials:
+    # example: user: 'git'; password: 'secret'
+    # run `man htpasswd` to learn about how to create .htpasswd-files
+    htpasswd: git:$apr1$O/LbLKC7$Q60GWE7OcqSEMSfe/K8xU.
+    # TODO: Create htpasswd-file on container startup instead and set user
+    # and password in values.yaml.
+    #user:
+    #password:
+
+
+gitGC:
+  image: k8sgerrit/git-gc
+
+  tolerations: []
+  nodeSelector: {}
+  affinity: {}
+  additionalPodLabels: {}
+
+  schedule: 0 6,18 * * *
+
+  resources:
+    requests:
+      cpu: 100m
+      memory: 256Mi
+    limits:
+      cpu: 100m
+      memory: 256Mi
+
+gerritReplica:
+  images:
+    gerritInit: k8sgerrit/gerrit-init
+    gerritReplica: k8sgerrit/gerrit
+
+  tolerations: []
+  topologySpreadConstraints: {}
+  nodeSelector: {}
+  affinity:
+    podAntiAffinity:
+      preferredDuringSchedulingIgnoredDuringExecution:
+      - weight: 100
+        podAffinityTerm:
+          labelSelector:
+            matchExpressions:
+            - key: app
+              operator: In
+              values:
+              - gerrit-replica
+          topologyKey: "topology.kubernetes.io/zone"
+
+  replicas: 1
+  updatePartition: 0
+  additionalAnnotations: {}
+  additionalPodLabels: {}
+
+  # If no value for probeScheme, the probe will use the default HTTP
+  probeScheme: HTTP
+
+  livenessProbe:
+    initialDelaySeconds: 60
+    periodSeconds: 5
+
+  readinessProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 10
+
+  startupProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 30
+
+  gracefulStopTimeout: 90
+
+  # The memory limit has to be higher than the configures heap-size for Java!
+  resources:
+    requests:
+      cpu: 1
+      memory: 5Gi
+    limits:
+      cpu: 1
+      memory: 6Gi
+
+  persistence:
+    enabled: true
+    size: 5Gi
+
+  # The general NetworkPolicy rules implemented by this chart may be too restrictive
+  # for some setups, e.g. when trying to connect to an external database. Here
+  # custom rules may be added to whitelist some additional connections.
+  networkPolicy:
+    ingress: []
+    egress: []
+
+  service:
+    additionalAnnotations: {}
+    loadBalancerSourceRanges: []
+    type: NodePort
+    externalTrafficPolicy: Cluster
+    http:
+      port: 80
+    ssh:
+      enabled: false
+      port: 29418
+
+  # `gerritReplica.keystore` expects a base64-encoded Java-keystore
+  # Since Java keystores are binary files, adding the unencoded content and
+  # automatic encoding using helm does not work here.
+  keystore:
+
+  pluginManagement:
+    plugins: []
+    # A plugin packaged in the gerrit.war-file
+    # - name: download-commands
+
+    # A plugin packaged in the gerrit.war-file that will also be installed as a
+    # lib
+    # - name: replication
+    #   installAsLibrary: true
+
+    # A plugin that will be downloaded on startup
+    # - name: delete-project
+    #   url: https://example.com/gerrit-plugins/delete-project.jar
+    #   sha1:
+    #   installAsLibrary: false
+
+    # Only downloaded plugins will be cached. This will be ignored, if no plugins
+    # are downloaded.
+    libs: []
+    cache:
+      enabled: false
+      size: 1Gi
+
+  priorityClassName:
+
+  etc:
+    # Some values are expected to have a specific value for the deployment installed
+    # by this chart to work. These are marked with `# FIXED`.
+    # Do not change them!
+    config:
+      gerrit.config: |-
+        [gerrit]
+          basePath = git # FIXED
+          serverId = gerrit-replica-1
+          # The canonical web URL has to be set to the Ingress host, if an Ingress
+          # is used. If a LoadBalancer-service is used, this should be set to the
+          # LoadBalancer's external IP. This can only be done manually after installing
+          # the chart, when you know the external IP the LoadBalancer got from the
+          # cluster.
+          canonicalWebUrl = http://example.com/
+          disableReverseDnsLookup = true
+        [index]
+          type = LUCENE
+        [index "scheduledIndexer"]
+          runOnStartup = false
+        [auth]
+          type = DEVELOPMENT_BECOME_ANY_ACCOUNT
+        [httpd]
+          # If using an ingress use proxy-http or proxy-https
+          listenUrl = proxy-http://*:8080/
+          requestLog = true
+          gracefulStopTimeout = 1m
+        [sshd]
+          listenAddress = *:29418
+          gracefulStopTimeout = 1m
+        [transfer]
+          timeout = 120 s
+        [user]
+          name = Gerrit Code Review
+          email = gerrit@example.com
+          anonymousCoward = Unnamed User
+        [cache]
+          directory = cache
+        [container]
+          user = gerrit # FIXED
+          replica = true # FIXED
+          javaHome = /usr/lib/jvm/java-17-openjdk # FIXED
+          javaOptions = -Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore # FIXED
+          javaOptions = -Xms200m
+          # Has to be lower than 'gerritReplica.resources.limits.memory'. Also
+          # consider memories used by other applications in the container.
+          javaOptions = -Xmx4g
+
+    secret:
+      secure.config: |-
+        # Password for the keystore added as value for 'gerritReplica.keystore'
+        # Only needed, if SSL is enabled.
+        #[httpd]
+        #  sslKeyPassword = gerrit
+
+      # ssh_host_ecdsa_key: |-
+      #   -----BEGIN EC PRIVATE KEY-----
+
+      #   -----END EC PRIVATE KEY-----
+
+      # ssh_host_ecdsa_key.pub: ecdsa-sha2-nistp256...
+
+  additionalConfigMaps:
+    # - name:
+    #   subDir:
+    #   data:
+    #     file.txt: test
diff --git a/charts/gerrit/.helmignore b/charts/gerrit/.helmignore
new file mode 100644
index 0000000..4f4562f
--- /dev/null
+++ b/charts/gerrit/.helmignore
@@ -0,0 +1,24 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+
+docs/
+supplements/
diff --git a/charts/gerrit/Chart.yaml b/charts/gerrit/Chart.yaml
new file mode 100644
index 0000000..cafaa43
--- /dev/null
+++ b/charts/gerrit/Chart.yaml
@@ -0,0 +1,27 @@
+apiVersion: v2
+appVersion: 3.9.1
+description: |-
+    Gerrit is a free, web-based team code collaboration tool. Software developers
+    in a team can review each other's modifications on their source code using
+    a Web browser and approve or reject those changes. It integrates closely with
+    Git, a distributed version control system. [1]
+
+    [1](https://en.wikipedia.org/wiki/Gerrit_(software)
+name: gerrit
+version: 0.2.0
+maintainers:
+- name: Thomas Draebing
+  email: thomas.draebing@sap.com
+- name: Matthias Sohn
+  email: matthias.sohn@sap.com
+- name: Sasa Zivkov
+  email: sasa.zivkov@sap.com
+- name: Christian Halstrick
+  email: christian.halstrick@sap.com
+home: https://gerrit.googlesource.com/k8s-gerrit/+/master/helm-charts/gerrit-replica
+icon: http://commondatastorage.googleapis.com/gerrit-static/diffy-w200.png
+sources:
+- https://gerrit.googlesource.com/k8s-gerrit/+/master/
+keywords:
+- gerrit
+- git
diff --git a/charts/gerrit/LICENSE b/charts/gerrit/LICENSE
new file mode 100644
index 0000000..028fc9f
--- /dev/null
+++ b/charts/gerrit/LICENSE
@@ -0,0 +1,201 @@
+   Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/charts/gerrit/README.md b/charts/gerrit/README.md
new file mode 100644
index 0000000..8300e0a
--- /dev/null
+++ b/charts/gerrit/README.md
@@ -0,0 +1,460 @@
+# 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.
+
+***note
+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](https://docs.helm.sh/using_helm/#quickstart-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](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes).
+    This project was developed using the
+    [NFS-server-provisioner helm chart](https://github.com/helm/charts/tree/master/stable/nfs-server-provisioner),
+    a NFS-provisioner deployed in the Kubernetes cluster itself. Refer to
+    [this guide](/helm-charts/gerrit/docs/nfs-provisioner.md) 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](http://alesnosek.com/blog/2017/02/14/accessing-kubernetes-pods-from-outside-of-the-cluster/)).
+
+- (Optional: Required, if SSL is configured)
+  A [Java keystore](https://gerrit-review.googlesource.com/Documentation/config-gerrit.html#httpd.sslKeyStore)
+  to be used by Gerrit.
+
+## Installing the Chart
+
+***note
+**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:
+
+```sh
+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](#Configuration) 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](#Installing-the-chart).
+
+In addition, single options can be set without creating a custom `values.yaml`:
+
+```sh
+cd $(git rev-parse --show-toplevel)/helm-charts
+helm install \
+  gerrit \  # release name
+  ./gerrit \  # path to chart
+  --set=gitRepositoryStorage.size=100Gi
+```
+
+### Container images
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `images.busybox.registry` | The registry to pull the busybox container images from | `docker.io` |
+| `images.busybox.tag` | The busybox image tag to use | `latest` |
+| `images.registry.name` | The image registry to pull the container images from | `` |
+| `images.registry.ImagePullSecret.name` | Name of the ImagePullSecret | `image-pull-secret` (if empty no image pull secret will be deployed) |
+| `images.registry.ImagePullSecret.create` | Whether to create an ImagePullSecret | `false` |
+| `images.registry.ImagePullSecret.username` | The image registry username | `nil` |
+| `images.registry.ImagePullSecret.password` | The image registry password | `nil` |
+| `images.version` | The image version (image tag) to use | `latest` |
+| `images.imagePullPolicy` | Image pull policy | `Always` |
+| `images.additionalImagePullSecrets` | Additional image pull policies that pods should use | `[]` |
+
+### Labels
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `additionalLabels` | Additional labels for resources managed by this Helm chart | `{}` |
+
+### Storage classes
+
+For information of how a `StorageClass` is configured in Kubernetes, read the
+[official Documentation](https://kubernetes.io/docs/concepts/storage/storage-classes/#introduction).
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `storageClasses.default.name` | The name of the default StorageClass (RWO) | `default` |
+| `storageClasses.default.create` | Whether to create the StorageClass | `false` |
+| `storageClasses.default.provisioner` | Provisioner of the StorageClass | `kubernetes.io/aws-ebs` |
+| `storageClasses.default.reclaimPolicy` | Whether to `Retain` or `Delete` volumes, when they become unbound | `Delete` |
+| `storageClasses.default.parameters` | Parameters for the provisioner | `parameters.type: gp2`, `parameters.fsType: ext4` |
+| `storageClasses.default.mountOptions` | The mount options of the default StorageClass | `[]` |
+| `storageClasses.default.allowVolumeExpansion` | Whether to allow volume expansion. | `false` |
+| `storageClasses.shared.name` | The name of the shared StorageClass (RWM) | `shared-storage` |
+| `storageClasses.shared.create` | Whether to create the StorageClass | `false` |
+| `storageClasses.shared.provisioner` | Provisioner of the StorageClass | `nfs` |
+| `storageClasses.shared.reclaimPolicy` | Whether to `Retain` or `Delete` volumes, when they become unbound | `Delete` |
+| `storageClasses.shared.parameters` | Parameters for the provisioner | `parameters.mountOptions: vers=4.1` |
+| `storageClasses.shared.mountOptions` | The mount options of the shared StorageClass | `[]` |
+| `storageClasses.shared.allowVolumeExpansion` | Whether to allow volume expansion. | `false` |
+
+### Network policies
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `networkPolicies.enabled` | Whether to enable preconfigured NetworkPolicies | `false` |
+| `networkPolicies.dnsPorts` | List 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:
+
+```yaml
+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:
+
+```yaml
+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.:
+
+```yaml
+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](https://kubernetes.io/docs/concepts/services-networking/network-policies/).
+
+### Workaround for NFS
+
+Kubernetes will not always be able to adapt the ownership of the files within NFS
+volumes. Thus, a workaround exists that will add init-containers to
+adapt file ownership. Note, that only the ownership of the root directory of the
+volume will be changed. All data contained within will be expected to already be
+owned by the user used by Gerrit. Also the ID-domain will be configured to ensure
+correct ID-mapping.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `nfsWorkaround.enabled` | Whether the volume used is an NFS-volume | `false` |
+| `nfsWorkaround.chownOnStartup` | Whether to chown the volume on pod startup | `false` |
+| `nfsWorkaround.idDomain` | The ID-domain that should be used to map user-/group-IDs for the NFS mount | `localdomain.com` |
+
+### Storage for Git repositories
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gitRepositoryStorage.externalPVC.use` | Whether to use a PVC deployed outside the chart | `false` |
+| `gitRepositoryStorage.externalPVC.name` | Name of the external PVC | `git-repositories-pvc` |
+| `gitRepositoryStorage.size` | Size of the volume storing the Git repositories | `5Gi` |
+
+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`.
+
+### Storage for Logs
+
+The logs can be stored in a dedicated persistent volume. This volume has to be a
+read-write-many volume to be able to be used by multiple pods.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `logStorage.enabled` | Whether to enable persistence of logs | `false` |
+| `logStorage.externalPVC.use` | Whether to use a PVC deployed outside the chart | `false` |
+| `logStorage.externalPVC.name` | Name of the external PVC | `gerrit-logs-pvc` |
+| `logStorage.size` | Size of the volume | `5Gi` |
+| `logStorage.cleanup.enabled` | Whether to regularly delete old logs | `false` |
+| `logStorage.cleanup.schedule` | Cron schedule defining when to run the cleanup job | `0 0 * * *` |
+| `logStorage.cleanup.retentionDays` | Number of days to retain the logs | `14` |
+| `logStorage.cleanup.resources` | Resources the container is allowed to use | `requests.cpu: 100m` |
+| `logStorage.cleanup.additionalPodLabels` | Additional labels for pods | `{}` |
+| | | `requests.memory: 256Mi` |
+| | | `limits.cpu: 100m` |
+| | | `limits.memory: 256Mi` |
+
+Each pod will create a separate folder for its logs, allowing to trace logs to
+the respective pods.
+
+### 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.
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `caCert` | CA certificate for TLS verification (if not set, the default will be used) | `None` |
+
+### Ingress
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `ingress.enabled` | Whether to enable the Ingress | `false` |
+| `ingress.host` | REQUIRED: Host name to use for the Ingress (required for Ingress) | `nil` |
+| `ingress.additionalAnnotations` | Additional annotations for the Ingress | `nil` |
+| `ingress.tls.enabled` | Whether to enable TLS termination in the Ingress | `false` |
+| `ingress.tls.secret.create` | Whether to create a TLS-secret | `true` |
+| `ingress.tls.secret.name` | Name of an external secret that will be used as a TLS-secret | `nil` |
+| `ingress.tls.cert` | Public SSL server certificate | `-----BEGIN CERTIFICATE-----` |
+| `ingress.tls.key` | Private SSL server certificate | `-----BEGIN RSA PRIVATE KEY-----` |
+
+***note
+For graceful shutdown to work with an ingress, the ingress controller has to be
+configured to gracefully close the connections as well.
+***
+
+### Git garbage collection
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gitGC.image` | Image name of the Git-GC container image | `k8sgerrit/git-gc` |
+| `gitGC.schedule` | Cron-formatted schedule with which to run Git garbage collection | `0 6,18 * * *` |
+| `gitGC.resources` | Configure the amount of resources the pod requests/is allowed | `requests.cpu: 100m` |
+|                   |                                                               | `requests.memory: 256Mi` |
+|                   |                                                               | `limits.cpu: 100m` |
+|                   |                                                               | `limits.memory: 256Mi` |
+| `gitGC.logging.persistence.enabled` | Whether to persist logs | `true` |
+| `gitGC.logging.persistence.size` | Storage size for persisted logs | `1Gi` |
+| `gitGC.tolerations` | Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. For more information, please refer to the following documents. [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration) | [] |
+| `gitGC.nodeSelector` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gitGC.affinity` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes using Node Affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gitGC.additionalPodLabels` | Additional labels for Pods | `{}` |
+
+### Gerrit
+
+***note
+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!
+***
+
+***note
+Setting the canonical web URL in the gerrit.config to the host used for the Ingress
+is mandatory, if access to Gerrit is required!
+***
+
+***note
+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.
+***
+
+| Parameter | Description | Default |
+|-----------|-------------|---------|
+| `gerrit.images.gerritInit` | Image name of the Gerrit init container image | `k8sgerrit/gerrit-init` |
+| `gerrit.images.gerrit` | Image name of the Gerrit container image | `k8sgerrit/gerrit` |
+| `gerrit.tolerations` | Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. For more information, please refer to the following documents. [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration) | [] |
+| `gerrit.topologySpreadConstraints` | Control how Pods are spread across your cluster among failure-domains. For more information, please refer to the following documents. [Pod Topology Spread Constraints](https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints) | {} |
+| `gerrit.nodeSelector` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gerrit.affinity` | Assigns a Pod to the specified Nodes. For more information, please refer to the following documents. [Assign Pods to Nodes using Node Affinity](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/). [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | {} |
+| `gerrit.additionalAnnotations` | Additional annotations for the Pods | {} |
+| `gerrit.additionalPodLabels` | Additional labels for Pods | `{}` |
+| `gerrit.replicas` | Number of replica pods to deploy | `1` |
+| `gerrit.updatePartition` | Ordinal at which to start updating pods. Pods with a lower ordinal will not be updated. | `0` |
+| `gerrit.resources` | Configure the amount of resources the pod requests/is allowed | `requests.cpu: 1` |
+|                    |                                                               | `requests.memory: 5Gi` |
+|                    |                                                               | `limits.cpu: 1` |
+|                    |                                                               | `limits.memory: 6Gi` |
+| `gerrit.persistence.enabled` | Whether to persist the Gerrit site | `true` |
+| `gerrit.persistence.size` | Storage size for persisted Gerrit site | `10Gi` |
+| `gerrit.probeScheme` | Scheme for probes, for example HTTPS | `nil` |
+| `gerrit.livenessProbe` | Configuration of the liveness probe timings | `{initialDelaySeconds: 30, periodSeconds: 5}` |
+| `gerrit.readinessProbe` | Configuration of the readiness probe timings | `{initialDelaySeconds: 5, periodSeconds: 1}` |
+| `gerrit.startupProbe` | Configuration of the startup probe timings | `{initialDelaySeconds: 10, periodSeconds: 5}` |
+| `gerrit.gracefulStopTimeout` | Time in seconds Kubernetes will wait until killing the pod during termination (has to be longer then Gerrit's httpd.gracefulStopTimeout to allow graceful shutdown of Gerrit) | `90` |
+| `gerrit.networkPolicy.ingress` | Custom ingress-network policy for gerrit pods | `nil` |
+| `gerrit.networkPolicy.egress` | Custom egress-network policy for gerrit pods | `nil` |
+| `gerrit.service.additionalAnnotations` | Additional annotations for the Service | `{}` |
+| `gerrit.service.loadBalancerSourceRanges` | The list of allowed IPs for the Service | `[]` |
+| `gerrit.service.type` | Which kind of Service to deploy | `NodePort` |
+| `gerrit.service.externalTrafficPolicy` | Specify how traffic from external is handled | `Cluster` |
+| `gerrit.service.http.port` | Port over which to expose HTTP | `80` |
+| `gerrit.service.ssh.enabled` | Whether to enable SSH | `false` |
+| `gerrit.service.ssh.port` | Port over which to expose SSH | `29418` |
+| `gerrit.keystore` | base64-encoded Java keystore (`cat keystore.jks \| base64`) to be used by Gerrit, when using SSL | `nil` |
+| `gerrit.index.type` | Index type used by Gerrit (either `lucene` or `elasticsearch`) | `lucene` |
+| `gerrit.pluginManagement.plugins` | List of Gerrit plugins to install | `[]` |
+| `gerrit.pluginManagement.plugins[0].name` | Name of plugin | `nil` |
+| `gerrit.pluginManagement.plugins[0].url` | Download url of plugin. If given the plugin will be downloaded, otherwise it will be installed from the gerrit.war-file. | `nil` |
+| `gerrit.pluginManagement.plugins[0].sha1` | SHA1 sum of plugin jar used to ensure file integrity and version (optional) | `nil` |
+| `gerrit.pluginManagement.plugins[0].installAsLibrary` | Whether the plugin should be symlinked to the lib-dir in the Gerrit site. | `nil` |
+| `gerrit.pluginManagement.libs` | List of Gerrit library modules to install | `[]` |
+| `gerrit.pluginManagement.libs[0].name` | Name of the lib module | `nil` |
+| `gerrit.pluginManagement.libs[0].url` | Download url of lib module. | `nil` |
+| `gerrit.pluginManagement.libs[0].sha1` | SHA1 sum of plugin jar used to ensure file integrity and version | `nil` |
+| `gerrit.pluginManagement.cache.enabled` | Whether to cache downloaded plugins | `false` |
+| `gerrit.pluginManagement.cache.size` | Size of the volume used to store cached plugins | `1Gi` |
+| `gerrit.priorityClassName` | Name of the PriorityClass to apply to the master pod | `nil` |
+| `gerrit.etc.config` | Map of config files (e.g. `gerrit.config`) that will be mounted to `$GERRIT_SITE/etc`by a ConfigMap | `{gerrit.config: ..., replication.config: ...}`[see here](#Gerrit-config-files) |
+| `gerrit.etc.secret` | Map of config files (e.g. `secure.config`) that will be mounted to `$GERRIT_SITE/etc`by a Secret | `{secure.config: ...}` [see here](#Gerrit-config-files) |
+| `gerrit.additionalConfigMaps` | Allows to mount additional ConfigMaps into a subdirectory of `$SITE/data` | `[]` |
+| `gerrit.additionalConfigMaps[*].name` | Name of the ConfigMap | `nil` |
+| `gerrit.additionalConfigMaps[*].subDir` | Subdirectory under `$SITE/data` into which the files should be symlinked | `nil` |
+| `gerrit.additionalConfigMaps[*].data` | Data of the ConfigMap. If not set, ConfigMap has to be created manually | `nil` |
+
+### 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](https://gerrit-review.googlesource.com/Documentation/config-gerrit.html).
+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.
+
+- `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.
+
+- `httpd.gracefulStopTimeout` / `sshd.gracefulStopTimeout`
+
+    To enable graceful shutdown of the embedded jetty server and SSHD, a timeout
+    has to be set with this option. This will be the maximum time, Gerrit will wait
+    for HTTP requests to finish before shutdown.
+
+- `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-11-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.
+
+SSH keys should be configured via the helm-chart using the `gerrit.etc.secret`
+map. Gerrit will create its own keys, if none are present in the site, but if
+multiple Gerrit pods are running, each Gerrit instance would have its own keys.
+Users accessing Gerrit via a load balancer would get issues due to changing
+host keys.
+
+### 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:
+
+```sh
+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:
+
+```sh
+helm delete <release-name>
+```
diff --git a/charts/gerrit/docs/nfs-provisioner.md b/charts/gerrit/docs/nfs-provisioner.md
new file mode 100644
index 0000000..9e83d47
--- /dev/null
+++ b/charts/gerrit/docs/nfs-provisioner.md
@@ -0,0 +1,64 @@
+# Installing a NFS-provisioner
+
+Gerrit requires access to a persistent volume capable of running in
+`Read Write Many (RWM)`-mode to store the git repositories, since the repositories
+have to be accessed by mutiple pods. One possibility to provide such volumes
+is to install a provisioner for NFS-volumes into the same Kubernetes-cluster.
+This document will guide through the process.
+
+The [Kubernetes external-storage project](https://github.com/kubernetes-incubator/external-storage)
+provides an out-of-tree dynamic [provisioner](https://github.com/kubernetes-incubator/external-storage/tree/master/nfs)
+for NFS volumes. A chart exists for easy deployment of the project onto a
+Kubernetes cluster. The chart's sources can be found [here](https://github.com/helm/charts/tree/master/stable/nfs-server-provisioner).
+
+## Prerequisites
+
+This guide will use Helm to install the NFS-provisioner. Thus, Helm has to be
+installed.
+
+## Installing the nfs-server-provisioner chart
+
+A custom `values.yaml`-file containing a configuration tested with the
+gerrit charts can be found in the `supplements/nfs`-directory in the
+gerrit chart's root directory. In addition a file stating the tested
+version of the nfs-server-provisioner chart is present in the same directory.
+
+If needed, adapt the `values.yaml`-file for the nfs-server-provisioner chart
+further and then run:
+
+```sh
+cd $(git rev-parse --show-toplevel)/helm-charts/gerrit/supplements/nfs
+helm install nfs \
+  stable/nfs-server-provisioner \
+  -f values.yaml \
+  --version $(cat VERSION)
+```
+
+For a description of the configuration options, refer to the
+[chart's documentation](https://github.com/helm/charts/blob/master/stable/nfs-server-provisioner/README.md).
+
+Here are some tips for configuring the nfs-server-provisioner chart to work with
+the gerrit chart:
+
+- Deploying more than 1 `replica` led to some reliability issues in tests and
+  should be further tested for now, if required.
+- The name of the StorageClass created for NFS-volumes has to be the same as the
+  one defined in the gerrit chart for `storageClasses.shared.name`
+- The StorageClas for NFS-volumes needs to have the parameter `mountOptions: vers=4.1`,
+  due to compatibility [issues](https://github.com/kubernetes-incubator/external-storage/issues/223)
+  with Ganesha.
+
+## Deleting the nfs-server-provisioner chart
+
+***note
+**Attention:** Never delete the nfs-server-provisioner chart, if there is still a
+PersistentVolumeClaim and Pods using a NFS-volume provisioned by the NFS server
+provisioner. This will lead to crashed pods, that will not be terminated correctly.
+***
+
+If no Pod or PVC is using a NFS-volume provisioned by the NFS server provisioner
+anymore, delete it like any other chart:
+
+```sh
+helm delete nfs
+```
diff --git a/charts/gerrit/supplements/nfs/VERSION b/charts/gerrit/supplements/nfs/VERSION
new file mode 100644
index 0000000..7dff5b8
--- /dev/null
+++ b/charts/gerrit/supplements/nfs/VERSION
@@ -0,0 +1 @@
+0.2.1
\ No newline at end of file
diff --git a/charts/gerrit/supplements/nfs/values.yaml b/charts/gerrit/supplements/nfs/values.yaml
new file mode 100644
index 0000000..a413d8a
--- /dev/null
+++ b/charts/gerrit/supplements/nfs/values.yaml
@@ -0,0 +1,42 @@
+# Deploying more than 1 `replica` led to some reliability issues in tests and
+# should be further tested for now, if required.
+replicaCount: 1
+
+image:
+  repository: quay.io/kubernetes_incubator/nfs-provisioner
+  tag: v1.0.9
+  pullPolicy: IfNotPresent
+
+service:
+  type: ClusterIP
+  nfsPort: 2049
+  mountdPort: 20048
+  rpcbindPort: 51413
+
+persistence:
+  enabled: true
+  storageClass: default
+  accessMode: ReadWriteOnce
+  size: 7.5Gi
+
+storageClass:
+  create: true
+  defaultClass: false
+  # The name of the StorageClass has to be the same as the one defined in the
+  # gerrit chart for `storageClasses.shared.name`
+  name: shared-storage
+  parameters:
+    # Required!
+    mountOptions: vers=4.1
+  reclaimPolicy: Delete
+
+rbac:
+  create: true
+
+resources:
+  requests:
+    cpu: 100m
+    memory: 256Mi
+  limits:
+    cpu: 100m
+    memory: 256Mi
diff --git a/charts/gerrit/templates/NOTES.txt b/charts/gerrit/templates/NOTES.txt
new file mode 100644
index 0000000..b71b3b0
--- /dev/null
+++ b/charts/gerrit/templates/NOTES.txt
@@ -0,0 +1,4 @@
+A primary Gerrit instance has been deployed.
+==================================
+
+Gerrit may be accessed under: {{ .Values.ingress.host }}
diff --git a/charts/gerrit/templates/_helpers.tpl b/charts/gerrit/templates/_helpers.tpl
new file mode 100644
index 0000000..bace6fe
--- /dev/null
+++ b/charts/gerrit/templates/_helpers.tpl
@@ -0,0 +1,20 @@
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "gerrit.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create secret to access docker registry
+*/}}
+{{- define "imagePullSecret" }}
+{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.images.registry.name (printf "%s:%s" .Values.images.registry.ImagePullSecret.username .Values.images.registry.ImagePullSecret.password | b64enc) | b64enc }}
+{{- end }}
+
+{{/*
+Add '/' to registry if needed.
+*/}}
+{{- define "registry" -}}
+{{ if .Values.images.registry.name }}{{- printf "%s/" .Values.images.registry.name -}}{{end}}
+{{- end -}}
diff --git a/charts/gerrit/templates/gerrit.configmap.yaml b/charts/gerrit/templates/gerrit.configmap.yaml
new file mode 100644
index 0000000..83c188c
--- /dev/null
+++ b/charts/gerrit/templates/gerrit.configmap.yaml
@@ -0,0 +1,78 @@
+{{- $root := . -}}
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-gerrit-configmap
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  {{- range $key, $value := .Values.gerrit.etc.config }}
+  {{ $key }}:
+{{ toYaml $value | indent 4 }}
+  {{- end }}
+  {{- if not (hasKey .Values.gerrit.etc.config "healthcheck.config") }}
+  healthcheck.config: |-
+    [healthcheck "auth"]
+      # On new instances there may be no users to use for healthchecks
+      enabled = false
+    [healthcheck "querychanges"]
+      # On new instances there won't be any changes to query
+      enabled = false
+  {{- end }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-gerrit-init-configmap
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  gerrit-init.yaml: |-
+    {{ if .Values.caCert -}}
+    caCertPath: /var/config/ca.crt
+    {{- end }}
+    pluginCacheEnabled: {{ .Values.gerrit.pluginManagement.cache.enabled }}
+    pluginCacheDir: /var/mnt/plugins
+    {{- if .Values.gerrit.pluginManagement.plugins }}
+    plugins:
+{{ toYaml .Values.gerrit.pluginManagement.plugins | indent 6}}
+    {{- end }}
+    {{- if .Values.gerrit.pluginManagement.libs }}
+    libs:
+{{ toYaml .Values.gerrit.pluginManagement.libs | indent 6}}
+    {{- end }}
+{{- range .Values.gerrit.additionalConfigMaps -}}
+{{- if .data }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name:  {{ $root.Release.Name }}-{{ .name }}
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ $root.Release.Name }}
+    chart: {{ template "gerrit.chart" $root }}
+    heritage: {{ $root.Release.Service }}
+    release: {{ $root.Release.Name }}
+    {{- if $root.Values.additionalLabels }}
+{{ toYaml $root.Values.additionalLabels | indent 4 }}
+    {{- end }}
+data:
+{{ toYaml .data | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/charts/gerrit/templates/gerrit.secrets.yaml b/charts/gerrit/templates/gerrit.secrets.yaml
new file mode 100644
index 0000000..72cfad3
--- /dev/null
+++ b/charts/gerrit/templates/gerrit.secrets.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-gerrit-secure-config
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  {{ if .Values.gerrit.keystore -}}
+  keystore: {{ .Values.gerrit.keystore }}
+  {{- end }}
+  {{- range $key, $value := .Values.gerrit.etc.secret }}
+  {{ $key }}: {{ $value | b64enc }}
+  {{- end }}
+type: Opaque
diff --git a/charts/gerrit/templates/gerrit.service.yaml b/charts/gerrit/templates/gerrit.service.yaml
new file mode 100644
index 0000000..fe16d45
--- /dev/null
+++ b/charts/gerrit/templates/gerrit.service.yaml
@@ -0,0 +1,41 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Release.Name }}-gerrit-service
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+  {{- if .Values.gerrit.service.additionalAnnotations }}
+  annotations:
+{{ toYaml .Values.gerrit.service.additionalAnnotations  | indent 4 }}
+  {{- end }}
+spec:
+  {{ with .Values.gerrit.service }}
+  {{- if .loadBalancerSourceRanges -}}
+  loadBalancerSourceRanges:
+{{- range .loadBalancerSourceRanges }}
+    - {{ . | quote }}
+{{- end }}
+  {{- end }}
+  ports:
+  - name: http
+    port: {{ .http.port }}
+    targetPort: 8080
+  {{- if .ssh.enabled }}
+  - name: ssh
+    port: {{ .ssh.port }}
+    targetPort: 29418
+  {{- end }}
+  type: {{ .type }}
+  externalTrafficPolicy: {{ .externalTrafficPolicy }}
+  {{- end }}
+  selector:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+
diff --git a/charts/gerrit/templates/gerrit.stateful-set.yaml b/charts/gerrit/templates/gerrit.stateful-set.yaml
new file mode 100644
index 0000000..2669325
--- /dev/null
+++ b/charts/gerrit/templates/gerrit.stateful-set.yaml
@@ -0,0 +1,299 @@
+{{- $root := . -}}
+
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ .Release.Name }}-gerrit-stateful-set
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  serviceName: {{ .Release.Name }}-gerrit-service
+  replicas: {{ .Values.gerrit.replicas }}
+  updateStrategy:
+    rollingUpdate:
+      partition: {{ .Values.gerrit.updatePartition }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/component: gerrit
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/component: gerrit
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        chart: {{ template "gerrit.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
+        {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 8 }}
+        {{- end }}
+        {{- if .Values.gerrit.additionalPodLabels }}
+{{ toYaml .Values.gerrit.additionalPodLabels  | indent 8 }}
+        {{- end }}
+      annotations:
+        chartRevision: "{{ .Release.Revision }}"
+        {{- if .Values.gerrit.additionalAnnotations }}
+{{ toYaml .Values.gerrit.additionalAnnotations  | indent 8 }}
+        {{- end }}
+    spec:
+      {{- with .Values.gerrit.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerrit.topologySpreadConstraints }}
+      topologySpreadConstraints:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerrit.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerrit.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.gerrit.priorityClassName }}
+      priorityClassName: {{ . }}
+      {{- end }}
+      terminationGracePeriodSeconds: {{ .Values.gerrit.gracefulStopTimeout }}
+      securityContext:
+        fsGroup: 100
+      {{ if .Values.images.registry.ImagePullSecret.name -}}
+      imagePullSecrets:
+      - name: {{ .Values.images.registry.ImagePullSecret.name }}
+      {{- range .Values.images.additionalImagePullSecrets }}
+      - name: {{ . }}
+      {{- end }}
+      {{- end }}
+      initContainers:
+      {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.chownOnStartup }}
+      - name: nfs-init
+        image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+        command:
+        - sh
+        - -c
+        args:
+        - |
+          chown 1000:100 /var/mnt/logs
+          chown 1000:100 /var/mnt/git
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        {{- if .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+      {{- end }}
+      - name: gerrit-init
+        image: {{ template "registry" . }}{{ .Values.gerrit.images.gerritInit }}:{{ .Values.images.version }}
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: gerrit-site
+          mountPath: "/var/gerrit"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        - name: logs
+          subPathExpr: "gerrit/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: gerrit-init-config
+          mountPath: "/var/config/gerrit-init.yaml"
+          subPath: gerrit-init.yaml
+        {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+        {{- if and .Values.gerrit.pluginManagement.cache.enabled }}
+        - name: gerrit-plugin-cache
+          mountPath: "/var/mnt/plugins"
+        {{- end }}
+        {{ if eq .Values.gerrit.index.type "elasticsearch" -}}
+        - name: gerrit-index-config
+          mountPath: "/var/mnt/index"
+        {{- end }}
+        - name: gerrit-config
+          mountPath: "/var/mnt/etc/config"
+        - name: gerrit-secure-config
+          mountPath: "/var/mnt/etc/secret"
+        {{ if .Values.caCert -}}
+        - name: tls-ca
+          subPath: ca.crt
+          mountPath: "/var/config/ca.crt"
+        {{- end }}
+        {{- range .Values.gerrit.additionalConfigMaps }}
+        - name: {{ .name }}
+          mountPath: "/var/mnt/data/{{ .subDir }}"
+        {{- end }}
+      containers:
+      - name: gerrit
+        image: {{ template "registry" . }}{{ .Values.gerrit.images.gerrit }}:{{ .Values.images.version }}
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        lifecycle:
+          preStop:
+            exec:
+              command:
+                - "/bin/ash"
+                - "-c"
+                - "kill -2 $(pidof java) && tail --pid=$(pidof java) -f /dev/null"
+        ports:
+        - name: gerrit-port
+          containerPort: 8080
+        {{- if .Values.gerrit.service.ssh.enabled }}
+        - name: gerrit-ssh
+          containerPort: 29418
+        {{- end }}
+        volumeMounts:
+        - name: gerrit-site
+          mountPath: "/var/gerrit"
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        - name: logs
+          subPathExpr: "gerrit/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+        {{ if eq .Values.gerrit.index.type "elasticsearch" -}}
+        - name: gerrit-index-config
+          mountPath: "/var/mnt/index"
+        {{- end }}
+        - name: gerrit-config
+          mountPath: "/var/mnt/etc/config"
+        - name: gerrit-secure-config
+          mountPath: "/var/mnt/etc/secret"
+        {{- range .Values.gerrit.additionalConfigMaps }}
+        - name: {{ .name }}
+          mountPath: "/var/mnt/data/{{ .subDir }}"
+        {{- end }}
+        resources:
+{{ toYaml .Values.gerrit.resources | indent 10 }}
+        livenessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: gerrit-port
+{{- if .Values.gerrit.probeScheme }}
+            scheme: {{ .Values.gerrit.probeScheme }}
+{{- end }}
+{{ toYaml .Values.gerrit.livenessProbe | indent 10 }}
+        readinessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: gerrit-port
+{{- if .Values.gerrit.probeScheme }}
+            scheme: {{ .Values.gerrit.probeScheme }}
+{{- end }}
+{{ toYaml .Values.gerrit.readinessProbe | indent 10 }}
+        startupProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: gerrit-port
+{{- if .Values.gerrit.probeScheme }}
+            scheme: {{ .Values.gerrit.probeScheme }}
+{{- end }}
+{{ toYaml .Values.gerrit.startupProbe | indent 10 }}
+      volumes:
+      {{ if not .Values.gerrit.persistence.enabled -}}
+      - name: gerrit-site
+        emptyDir: {}
+      {{- end }}
+      {{- if and .Values.gerrit.pluginManagement.cache.enabled }}
+      - name: gerrit-plugin-cache
+        persistentVolumeClaim:
+          claimName: {{ .Release.Name }}-plugin-cache-pvc
+      {{- end }}
+      - name: git-repositories
+        persistentVolumeClaim:
+          {{- if .Values.gitRepositoryStorage.externalPVC.use }}
+          claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-git-repositories-pvc
+          {{- end }}
+      - name: logs
+        {{ if .Values.logStorage.enabled -}}
+        persistentVolumeClaim:
+          {{- if .Values.logStorage.externalPVC.use }}
+          claimName: {{ .Values.logStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-log-pvc
+          {{- end }}
+        {{ else -}}
+        emptyDir: {}
+        {{- end }}
+      - name: gerrit-init-config
+        configMap:
+          name: {{ .Release.Name }}-gerrit-init-configmap
+      {{ if eq .Values.gerrit.index.type "elasticsearch" -}}
+      - name: gerrit-index-config
+        persistentVolumeClaim:
+          claimName: {{ .Release.Name }}-gerrit-index-config-pvc
+      {{- end }}
+      - name: gerrit-config
+        configMap:
+          name: {{ .Release.Name }}-gerrit-configmap
+      - name: gerrit-secure-config
+        secret:
+          secretName: {{ .Release.Name }}-gerrit-secure-config
+      {{ if .Values.caCert -}}
+      - name: tls-ca
+        secret:
+          secretName: {{ .Release.Name }}-tls-ca
+      {{- end }}
+      {{- range .Values.gerrit.additionalConfigMaps }}
+      - name: {{ .name }}
+        configMap:
+          name: {{ if .data }}{{ $root.Release.Name }}-{{ .name }}{{ else }}{{ .name }}{{ end }}
+      {{- end }}
+      {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+      - name: nfs-config
+        configMap:
+          name: {{ .Release.Name }}-nfs-configmap
+      {{- end }}
+  {{ if .Values.gerrit.persistence.enabled -}}
+  volumeClaimTemplates:
+  - metadata:
+      name: gerrit-site
+      labels:
+        app.kubernetes.io/component: gerrit
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        chart: {{ template "gerrit.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
+        {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 8 }}
+        {{- end }}
+    spec:
+      accessModes:
+      - ReadWriteOnce
+      resources:
+        requests:
+          storage: {{ .Values.gerrit.persistence.size }}
+      storageClassName: {{ .Values.storageClasses.default.name }}
+  {{- end }}
diff --git a/charts/gerrit/templates/gerrit.storage.yaml b/charts/gerrit/templates/gerrit.storage.yaml
new file mode 100644
index 0000000..1d85fc6
--- /dev/null
+++ b/charts/gerrit/templates/gerrit.storage.yaml
@@ -0,0 +1,45 @@
+{{- if and .Values.gerrit.pluginManagement.cache.enabled }}
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-plugin-cache-pvc
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: {{ .Values.gerrit.pluginManagement.cache.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
+{{ if eq .Values.gerrit.index.type "elasticsearch" -}}
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-gerrit-index-config-pvc
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: 10Mi
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
diff --git a/charts/gerrit/templates/git-gc.cronjob.yaml b/charts/gerrit/templates/git-gc.cronjob.yaml
new file mode 100644
index 0000000..8230e5d
--- /dev/null
+++ b/charts/gerrit/templates/git-gc.cronjob.yaml
@@ -0,0 +1,132 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: {{ .Release.Name }}-git-gc
+  labels:
+    app.kubernetes.io/component: git-gc
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  schedule: {{ .Values.gitGC.schedule | quote }}
+  concurrencyPolicy: "Forbid"
+  jobTemplate:
+    spec:
+      template:
+        metadata:
+          labels:
+            app.kubernetes.io/component: git-gc
+            app.kubernetes.io/instance: {{ .Release.Name }}
+            chart: {{ template "gerrit.chart" . }}
+            heritage: {{ .Release.Service }}
+            release: {{ .Release.Name }}
+            {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 12 }}
+            {{- end }}
+            {{- if .Values.gitGC.additionalPodLabels }}
+{{ toYaml .Values.gitGC.additionalPodLabels  | indent 12 }}
+            {{- end }}
+          annotations:
+            cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
+        spec:
+          {{- with .Values.gitGC.tolerations }}
+          tolerations:
+            {{- toYaml . | nindent 10 }}
+          {{- end }}
+          {{- with .Values.gitGC.nodeSelector }}
+          nodeSelector:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          {{- with .Values.gitGC.affinity }}
+          affinity:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          restartPolicy: OnFailure
+          securityContext:
+            runAsUser: 1000
+            fsGroup: 100
+          {{ if .Values.images.registry.ImagePullSecret.name -}}
+          imagePullSecrets:
+          - name: {{ .Values.images.registry.ImagePullSecret.name }}
+          {{- range .Values.images.additionalImagePullSecrets }}
+          - name: {{ . }}
+          {{- end }}
+          {{- end }}
+          initContainers:
+          {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.chownOnStartup }}
+          - name: nfs-init
+            image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+            command:
+            - sh
+            - -c
+            args:
+            - |
+              chown 1000:100 /var/mnt/logs
+              chown 1000:100 /var/mnt/git
+            env:
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            volumeMounts:
+            - name: logs
+              subPathExpr: "git-gc/$(POD_NAME)"
+              mountPath: "/var/mnt/logs"
+            - name: git-repositories
+              mountPath: "/var/mnt/git"
+            {{- if .Values.nfsWorkaround.idDomain }}
+            - name: nfs-config
+              mountPath: "/etc/idmapd.conf"
+              subPath: idmapd.conf
+            {{- end }}
+          {{- end }}
+          containers:
+          - name: git-gc
+            imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+            image: {{ template "registry" . }}{{ .Values.gitGC.image }}:{{ .Values.images.version }}
+            env:
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            resources:
+{{ toYaml .Values.gitGC.resources | indent 14 }}
+            volumeMounts:
+            - name: git-repositories
+              mountPath: "/var/gerrit/git"
+            - name: logs
+              subPathExpr: "git-gc/$(POD_NAME)"
+              mountPath: "/var/log/git"
+            {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+            - name: nfs-config
+              mountPath: "/etc/idmapd.conf"
+              subPath: idmapd.conf
+            {{- end }}
+          volumes:
+          - name: git-repositories
+            persistentVolumeClaim:
+              {{- if .Values.gitRepositoryStorage.externalPVC.use }}
+              claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-git-repositories-pvc
+              {{- end }}
+          - name: logs
+            {{ if .Values.logStorage.enabled -}}
+            persistentVolumeClaim:
+              {{- if .Values.logStorage.externalPVC.use }}
+              claimName: {{ .Values.logStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-log-pvc
+              {{- end }}
+            {{ else -}}
+            emptyDir: {}
+            {{- end }}
+          {{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain }}
+          - name: nfs-config
+            configMap:
+              name: {{ .Release.Name }}-nfs-configmap
+          {{- end }}
diff --git a/charts/gerrit/templates/git-gc.storage.yaml b/charts/gerrit/templates/git-gc.storage.yaml
new file mode 100644
index 0000000..c69a647
--- /dev/null
+++ b/charts/gerrit/templates/git-gc.storage.yaml
@@ -0,0 +1,22 @@
+{{ if .Values.gitGC.logging.persistence.enabled -}}
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-git-gc-logs-pvc
+  labels:
+    app.kubernetes.io/component: git-gc
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  accessModes:
+  - ReadWriteOnce
+  resources:
+    requests:
+      storage: {{ .Values.gitGC.logging.persistence.size }}
+  storageClassName: {{ .Values.storageClasses.default.name }}
+{{- end }}
diff --git a/charts/gerrit/templates/global.secrets.yaml b/charts/gerrit/templates/global.secrets.yaml
new file mode 100644
index 0000000..b2c3d5d
--- /dev/null
+++ b/charts/gerrit/templates/global.secrets.yaml
@@ -0,0 +1,18 @@
+{{ if .Values.caCert -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-tls-ca
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  ca.crt: {{ .Values.caCert | b64enc }}
+type: Opaque
+{{- end }}
diff --git a/charts/gerrit/templates/image-pull.secret.yaml b/charts/gerrit/templates/image-pull.secret.yaml
new file mode 100644
index 0000000..d107472
--- /dev/null
+++ b/charts/gerrit/templates/image-pull.secret.yaml
@@ -0,0 +1,9 @@
+{{ if and .Values.images.registry.ImagePullSecret.name .Values.images.registry.ImagePullSecret.create -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ .Values.images.registry.ImagePullSecret.name }}
+type: kubernetes.io/dockerconfigjson
+data:
+  .dockerconfigjson: {{ template "imagePullSecret" . }}
+{{- end }}
\ No newline at end of file
diff --git a/charts/gerrit/templates/ingress.yaml b/charts/gerrit/templates/ingress.yaml
new file mode 100644
index 0000000..eb19655
--- /dev/null
+++ b/charts/gerrit/templates/ingress.yaml
@@ -0,0 +1,64 @@
+{{- if .Values.ingress.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ .Release.Name }}-gerrit-ingress
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.ingress.additionalLabels }}
+{{ toYaml .Values.ingress.additionalLabels  | indent 4 }}
+    {{- end }}
+  annotations:
+    nginx.ingress.kubernetes.io/proxy-body-size: {{ .Values.ingress.maxBodySize | default "50m" }}
+    {{- if .Values.ingress.additionalAnnotations }}
+{{ toYaml .Values.ingress.additionalAnnotations  | indent 4 }}
+    {{- end }}
+spec:
+  {{ if .Values.ingress.tls.enabled -}}
+  tls:
+  - hosts:
+    - {{ .Values.ingress.host }}
+    {{ if .Values.ingress.tls.secret.create -}}
+    secretName: {{ .Release.Name }}-gerrit-tls-secret
+    {{- else }}
+    secretName: {{ .Values.ingress.tls.secret.name }}
+    {{- end }}
+  {{- end }}
+  rules:
+  - host: {{required "A host URL is required for the Gerrit Ingress. Please set 'ingress.host'" .Values.ingress.host }}
+    http:
+      paths:
+      - pathType: Prefix
+        path: /
+        backend:
+          service:
+            name: {{ .Release.Name }}-gerrit-service
+            port:
+              number: {{ .Values.gerrit.service.http.port }}
+{{- end }}
+---
+{{ if and .Values.ingress.tls.enabled .Values.ingress.tls.secret.create -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-gerrit-tls-secret
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.ingress.additionalLabels }}
+{{ toYaml .Values.ingress.additionalLabels  | indent 4 }}
+    {{- end }}
+type: kubernetes.io/tls
+data:
+  {{ with .Values.ingress.tls -}}
+  tls.crt: {{ .cert | b64enc }}
+  tls.key: {{ .key | b64enc }}
+  {{- end }}
+{{- end }}
diff --git a/charts/gerrit/templates/log-cleaner.cronjob.yaml b/charts/gerrit/templates/log-cleaner.cronjob.yaml
new file mode 100644
index 0000000..c1314f1
--- /dev/null
+++ b/charts/gerrit/templates/log-cleaner.cronjob.yaml
@@ -0,0 +1,65 @@
+{{- if and .Values.logStorage.enabled .Values.logStorage.cleanup.enabled }}
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: {{ .Release.Name }}-log-cleaner
+  labels:
+    app.kubernetes.io/component: log-cleaner
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  schedule: {{ .Values.logStorage.cleanup.schedule | quote }}
+  concurrencyPolicy: "Forbid"
+  jobTemplate:
+    spec:
+      template:
+        metadata:
+          labels:
+            app.kubernetes.io/component: log-cleaner
+            app.kubernetes.io/instance: {{ .Release.Name }}
+            chart: {{ template "gerrit.chart" . }}
+            heritage: {{ .Release.Service }}
+            release: {{ .Release.Name }}
+            {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 12 }}
+            {{- end }}
+            {{- if .Values.logStorage.cleanup.additionalPodLabels }}
+{{ toYaml .Values.logStorage.cleanup.additionalPodLabels  | indent 12 }}
+            {{- end }}
+        spec:
+          restartPolicy: OnFailure
+          containers:
+          - name: log-cleaner
+            imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+            image: {{ .Values.images.busybox.registry -}}/busybox:{{- .Values.images.busybox.tag }}
+            command:
+            - sh
+            - -c
+            args:
+            - |
+              find /var/logs/ \
+                -mindepth 1 \
+                -type f \
+                -mtime +{{ .Values.logStorage.cleanup.retentionDays }} \
+                -print \
+                -delete
+              find /var/logs/ -type d -empty -delete
+            resources:
+{{ toYaml .Values.logStorage.cleanup.resources | indent 14 }}
+            volumeMounts:
+            - name: logs
+              mountPath: "/var/logs"
+          volumes:
+          - name: logs
+            persistentVolumeClaim:
+              {{- if .Values.logStorage.externalPVC.use }}
+              claimName: {{ .Values.logStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-log-pvc
+              {{- end }}
+{{- end }}
diff --git a/charts/gerrit/templates/netpol.yaml b/charts/gerrit/templates/netpol.yaml
new file mode 100644
index 0000000..c0cbc4d
--- /dev/null
+++ b/charts/gerrit/templates/netpol.yaml
@@ -0,0 +1,122 @@
+{{ if .Values.networkPolicies.enabled -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: {{ .Release.Name }}-default-deny-all
+  labels:
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.networkPolicies.additionalLabels }}
+{{ toYaml .Values.networkPolicies.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+  policyTypes:
+  - Ingress
+  - Egress
+  ingress: []
+  egress: []
+---
+{{ if .Values.networkPolicies.dnsPorts -}}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ .Release.Name }}-allow-dns-access
+  labels:
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.networkPolicies.additionalLabels }}
+{{ toYaml .Values.networkPolicies.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+  policyTypes:
+  - Egress
+  egress:
+  - ports:
+    {{ range .Values.networkPolicies.dnsPorts -}}
+    - port: {{ . }}
+      protocol: UDP
+    - port: {{ . }}
+      protocol: TCP
+    {{ end }}
+{{- end }}
+---
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-allow-external
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: gerrit
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  ingress:
+  - ports:
+    - port: 8080
+    from: []
+---
+{{ if or .Values.gerrit.networkPolicy.ingress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-custom-ingress-policies
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Ingress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: gerrit
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  ingress:
+{{ toYaml .Values.gerrit.networkPolicy.ingress | indent 2 }}
+{{- end }}
+---
+{{ if or .Values.gerrit.networkPolicy.egress -}}
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: gerrit-custom-egress-policies
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  policyTypes:
+  - Egress
+  podSelector:
+    matchLabels:
+      chart: {{ template "gerrit.chart" . }}
+      release: {{ .Release.Name }}
+      app.kubernetes.io/component: gerrit
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  egress:
+{{ toYaml .Values.gerrit.networkPolicy.egress | indent 2 }}
+{{- end }}
+{{- end }}
diff --git a/charts/gerrit/templates/nfs.configmap.yaml b/charts/gerrit/templates/nfs.configmap.yaml
new file mode 100644
index 0000000..dd2c3dd
--- /dev/null
+++ b/charts/gerrit/templates/nfs.configmap.yaml
@@ -0,0 +1,28 @@
+{{- if and .Values.nfsWorkaround.enabled .Values.nfsWorkaround.idDomain -}}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-nfs-configmap
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+data:
+  idmapd.conf: |-
+    [General]
+
+    Verbosity = 0
+    Pipefs-Directory = /run/rpc_pipefs
+    # set your own domain here, if it differs from FQDN minus hostname
+    Domain = {{ .Values.nfsWorkaround.idDomain }}
+
+    [Mapping]
+
+    Nobody-User = nobody
+    Nobody-Group = nogroup
+{{- end }}
diff --git a/charts/gerrit/templates/storage.pvc.yaml b/charts/gerrit/templates/storage.pvc.yaml
new file mode 100644
index 0000000..b262402
--- /dev/null
+++ b/charts/gerrit/templates/storage.pvc.yaml
@@ -0,0 +1,45 @@
+{{- if not .Values.gitRepositoryStorage.externalPVC.use }}
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-git-repositories-pvc
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: {{ .Values.gitRepositoryStorage.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
+{{- if and .Values.logStorage.enabled (not .Values.logStorage.externalPVC.use) }}
+---
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+  name: {{ .Release.Name }}-log-pvc
+  labels:
+    app.kubernetes.io/component: gerrit
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: {{ .Values.logStorage.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
+{{- end }}
diff --git a/charts/gerrit/templates/storageclasses.yaml b/charts/gerrit/templates/storageclasses.yaml
new file mode 100644
index 0000000..552cd6a
--- /dev/null
+++ b/charts/gerrit/templates/storageclasses.yaml
@@ -0,0 +1,53 @@
+{{ if .Values.storageClasses.default.create -}}
+kind: StorageClass
+apiVersion: storage.k8s.io/v1
+metadata:
+  name: {{ .Values.storageClasses.default.name }}
+  labels:
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+provisioner: {{ .Values.storageClasses.default.provisioner }}
+reclaimPolicy: {{ .Values.storageClasses.default.reclaimPolicy }}
+{{ if .Values.storageClasses.default.parameters -}}
+parameters:
+{{- range $key, $value := .Values.storageClasses.default.parameters }}
+  {{ $key }}: {{ $value }}
+{{- end }}
+mountOptions:
+{{- range $value := .Values.storageClasses.default.mountOptions }}
+  - {{ $value }}
+{{- end }}
+allowVolumeExpansion: {{ .Values.storageClasses.default.allowVolumeExpansion }}
+{{- end }}
+{{- end }}
+---
+{{ if .Values.storageClasses.shared.create -}}
+kind: StorageClass
+apiVersion: storage.k8s.io/v1
+metadata:
+  name: {{ .Values.storageClasses.shared.name }}
+  labels:
+    chart: {{ template "gerrit.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+    {{- if .Values.additionalLabels }}
+{{ toYaml .Values.additionalLabels  | indent 4 }}
+    {{- end }}
+provisioner: {{ .Values.storageClasses.shared.provisioner }}
+reclaimPolicy: {{ .Values.storageClasses.shared.reclaimPolicy }}
+{{ if .Values.storageClasses.shared.parameters -}}
+parameters:
+{{- range $key, $value := .Values.storageClasses.shared.parameters }}
+  {{ $key }}: {{ $value }}
+{{- end }}
+mountOptions:
+{{- range $value := .Values.storageClasses.shared.mountOptions }}
+  - {{ $value }}
+{{- end }}
+allowVolumeExpansion: {{ .Values.storageClasses.shared.allowVolumeExpansion }}
+{{- end }}
+{{- end }}
diff --git a/charts/gerrit/values.yaml b/charts/gerrit/values.yaml
new file mode 100644
index 0000000..ef27520
--- /dev/null
+++ b/charts/gerrit/values.yaml
@@ -0,0 +1,336 @@
+images:
+  busybox:
+    registry: docker.io
+    tag: latest
+  # Registry used for container images created by this project
+  registry:
+    # The registry name must NOT contain a trailing slash
+    name:
+    ImagePullSecret:
+      # Leave blank, if no ImagePullSecret is needed.
+      name: image-pull-secret
+      # If set to false, the gerrit chart expects either a ImagePullSecret
+      # with the name configured above to be present on the cluster or that no
+      # credentials are needed.
+      create: false
+      username:
+      password:
+  version: latest
+  imagePullPolicy: Always
+  # Additional ImagePullSecrets that already exist and should be used by the
+  # pods of this chart. E.g. to pull busybox from dockerhub.
+  additionalImagePullSecrets: []
+
+# Additional labels that should be applied to all resources
+additionalLabels: {}
+
+storageClasses:
+  # Storage class used for storing logs and other pod-specific persisted data
+  default:
+    # If create is set to false, an existing StorageClass with the given
+    # name is expected to exist in the cluster. Setting create to true will
+    # create a storage class with the parameters given below.
+    name: default
+    create: false
+    provisioner: kubernetes.io/aws-ebs
+    reclaimPolicy: Delete
+    # Use the parameters key to set all parameters needed for the provisioner
+    parameters:
+      type: gp2
+      fsType: ext4
+    mountOptions: []
+    allowVolumeExpansion: false
+  # Storage class used for storing git repositories. Has to provide RWM access.
+  shared:
+    # If create is set to false, an existing StorageClass with RWM access
+    # mode and the given name has to be provided.
+    name: shared-storage
+    create: false
+    provisioner: nfs
+    reclaimPolicy: Delete
+    # Use the parameters key to set all parameters needed for the provisioner
+    parameters:
+      mountOptions: vers=4.1
+    mountOptions: []
+    allowVolumeExpansion: false
+
+
+nfsWorkaround:
+  enabled: false
+  chownOnStartup: false
+  idDomain: localdomain.com
+
+
+networkPolicies:
+  enabled: false
+  dnsPorts:
+  - 53
+  - 8053
+
+
+gitRepositoryStorage:
+  externalPVC:
+    use: false
+    name: git-repositories-pvc
+  size: 5Gi
+
+logStorage:
+  enabled: false
+  externalPVC:
+    use: false
+    name: gerrit-logs-pvc
+  size: 5Gi
+  cleanup:
+    enabled: false
+    additionalPodLabels: {}
+    schedule: "0 0 * * *"
+    retentionDays: 14
+    resources:
+      requests:
+        cpu: 100m
+        memory: 256Mi
+      limits:
+        cpu: 100m
+        memory: 256Mi
+
+caCert:
+
+ingress:
+  enabled: false
+  host:
+  # The maximum body size to allow for requests. Use "0" to allow unlimited
+  # reuqest body sizes.
+  maxBodySize: 50m
+  additionalAnnotations:
+    kubernetes.io/ingress.class: nginx
+  #  nginx.ingress.kubernetes.io/server-alias: example.com
+  #  nginx.ingress.kubernetes.io/whitelist-source-range: xxx.xxx.xxx.xxx
+  tls:
+    enabled: false
+    secret:
+      create: true
+      # `name` will only be used, if `create` is set to false to bind an
+      # existing secret. Otherwise the name will be automatically generated to
+      # avoid conflicts between multiple chart installations.
+      name:
+    # `cert`and `key` will only be used, if the secret will be created by
+    # this chart.
+    cert: |-
+      -----BEGIN CERTIFICATE-----
+
+      -----END CERTIFICATE-----
+    key: |-
+      -----BEGIN RSA PRIVATE KEY-----
+
+      -----END RSA PRIVATE KEY-----
+
+
+gitGC:
+  image: k8sgerrit/git-gc
+
+  tolerations: []
+  nodeSelector: {}
+  affinity: {}
+  additionalPodLabels: {}
+
+  schedule: 0 6,18 * * *
+
+  resources:
+    requests:
+      cpu: 100m
+      memory: 256Mi
+    limits:
+      cpu: 100m
+      memory: 256Mi
+
+  logging:
+    persistence:
+      enabled: true
+      size: 1Gi
+
+
+gerrit:
+  images:
+    gerritInit: k8sgerrit/gerrit-init
+    gerrit: k8sgerrit/gerrit
+
+  tolerations: []
+  topologySpreadConstraints: {}
+  nodeSelector: {}
+  affinity: {}
+  additionalAnnotations: {}
+  additionalPodLabels: {}
+
+  replicas: 1
+  updatePartition: 0
+
+  # The memory limit has to be higher than the configures heap-size for Java!
+  resources:
+    requests:
+      cpu: 1
+      memory: 5Gi
+    limits:
+      cpu: 1
+      memory: 6Gi
+
+  persistence:
+    enabled: true
+    size: 10Gi
+
+  # If no value for probeScheme, the probe will use the default HTTP
+  probeScheme: HTTP
+
+  livenessProbe:
+    initialDelaySeconds: 30
+    periodSeconds: 5
+
+  readinessProbe:
+    initialDelaySeconds: 5
+    periodSeconds: 1
+
+  startupProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 30
+
+  gracefulStopTimeout: 90
+
+  # The general NetworkPolicy rules implemented by this chart may be too restrictive
+  # for some setups, e.g. when trying to replicate to a Gerrit replica. Here
+  # custom rules may be added to whitelist some additional connections.
+  networkPolicy:
+    ingress: []
+    egress: []
+    # An example for an egress rule to allow replication to a Gerrit replica
+    # installed with the gerrit-replica setup in the same cluster and namespace
+    # by using the service as the replication destination
+    # (e.g. http://gerrit-replica-git-backend-service:80/git/${name}.git):
+    #
+    # - to:
+    #   - podSelector:
+    #       matchLabels:
+    #         app: git-backend
+
+  service:
+    additionalAnnotations: {}
+    loadBalancerSourceRanges: []
+    type: NodePort
+    externalTrafficPolicy: Cluster
+    http:
+      port: 80
+    ssh:
+      enabled: false
+      port: 29418
+
+  # `gerrit.keystore` expects a base64-encoded Java-keystore
+  # Since Java keystores are binary files, adding the unencoded content and
+  # automatic encoding using helm does not work here.
+  keystore:
+
+  index:
+    # Either `lucene` or `elasticsearch`
+    type: lucene
+
+  pluginManagement:
+    plugins: []
+    # A plugin packaged in the gerrit.war-file
+    # - name: download-commands
+
+    # A plugin packaged in the gerrit.war-file that will also be installed as a
+    # lib
+    # - name: replication
+    #   installAsLibrary: true
+
+    # A plugin that will be downloaded on startup
+    # - name: delete-project
+    #   url: https://example.com/gerrit-plugins/delete-project.jar
+    #   sha1:
+    #   installAsLibrary: false
+
+    # Only downloaded plugins will be cached. This will be ignored, if no plugins
+    # are downloaded.
+    libs: []
+    cache:
+      enabled: false
+      size: 1Gi
+
+  priorityClassName:
+
+  etc:
+    # Some values are expected to have a specific value for the deployment installed
+    # by this chart to work. These are marked with `# FIXED`.
+    # Do not change them!
+    config:
+      gerrit.config: |-
+        [gerrit]
+          basePath = git # FIXED
+          serverId = gerrit-1
+          # The canonical web URL has to be set to the Ingress host, if an Ingress
+          # is used. If a LoadBalancer-service is used, this should be set to the
+          # LoadBalancer's external IP. This can only be done manually after installing
+          # the chart, when you know the external IP the LoadBalancer got from the
+          # cluster.
+          canonicalWebUrl = http://example.com/
+          disableReverseDnsLookup = true
+        [index]
+          type = LUCENE
+        [auth]
+          type = DEVELOPMENT_BECOME_ANY_ACCOUNT
+        [httpd]
+          # If using an ingress use proxy-http or proxy-https
+          listenUrl = proxy-http://*:8080/
+          requestLog = true
+          gracefulStopTimeout = 1m
+        [sshd]
+          listenAddress = off
+        [transfer]
+          timeout = 120 s
+        [user]
+          name = Gerrit Code Review
+          email = gerrit@example.com
+          anonymousCoward = Unnamed User
+        [cache]
+          directory = cache
+        [container]
+          user = gerrit # FIXED
+          javaHome = /usr/lib/jvm/java-17-openjdk # FIXED
+          javaOptions = -Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore # FIXED
+          javaOptions = -Xms200m
+          # Has to be lower than 'gerrit.resources.limits.memory'. Also
+          # consider memories used by other applications in the container.
+          javaOptions = -Xmx4g
+
+      replication.config: |-
+        [gerrit]
+          autoReload = false
+          replicateOnStartup = true
+          defaultForceUpdate = true
+
+        # [remote "replica"]
+        # url = http://gerrit-replica.example.com/git/${name}.git
+        # replicationDelay = 0
+        # timeout = 30
+
+    secret:
+      secure.config: |-
+        # Password for the keystore added as value for 'gerritReplica.keystore'
+        # Only needed, if SSL is enabled.
+        #[httpd]
+        #  sslKeyPassword = gerrit
+
+        # Credentials for replication targets
+        # [remote "replica"]
+        # username = git
+        # password = secret
+
+      # ssh_host_ecdsa_key: |-
+      #   -----BEGIN EC PRIVATE KEY-----
+
+      #   -----END EC PRIVATE KEY-----
+
+      # ssh_host_ecdsa_key.pub: ecdsa-sha2-nistp256...
+
+  additionalConfigMaps:
+    # - name:
+    #   subDir:
+    #   data:
+    #     file.txt: test
diff --git a/core/installer/Makefile b/core/installer/Makefile
index 1c83138..e36755b 100644
--- a/core/installer/Makefile
+++ b/core/installer/Makefile
@@ -21,6 +21,10 @@
 test:
 	/usr/local/go/bin/go test ./...
 
+test: export CGO_ENABLED=0
+testv:
+	/usr/local/go/bin/go test -v ./...
+
 bootstrap:
 	./pcloud --kubeconfig=../../priv/kubeconfig-hetzner bootstrap --env-name=dodo --charts-dir=../../charts --admin-pub-key=/Users/lekva/.ssh/id_rsa.pub --from-ip=192.168.100.210 --to-ip=192.168.100.240 --storage-dir=/pcloud-storage/longhorn
 
@@ -31,7 +35,7 @@
 	./pcloud --kubeconfig=../../priv/kubeconfig install --ssh-key=/Users/lekva/.ssh/id_rsa --app=rpuppy --repo-addr=ssh://localhost:2222/lekva
 
 appmanager:
-	./pcloud --kubeconfig=../../priv/kubeconfig appmanager --ssh-key=/Users/lekva/.ssh/id_ed25519 --repo-addr=ssh://localhost:2222/config --port=9090 --app-repo-addr=http://localhost:8080
+	./pcloud --kubeconfig=../../priv/kubeconfig-hetzner appmanager --ssh-key=/Users/lekva/.ssh/id_ed25519 --repo-addr=ssh://localhost:2222/config --port=9090 # --app-repo-addr=http://localhost:8080
 
 welc:
 	./pcloud --kubeconfig=../../priv/kubeconfig welcome --ssh-key=/Users/lekva/.ssh/id_rsa --repo-addr=ssh://192.168.0.210/config --port=9090
diff --git a/core/installer/app.go b/core/installer/app.go
index 8457fe2..3656231 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -34,6 +34,7 @@
 	"values-tmpl/soft-serve.cue",
 	"values-tmpl/vaultwarden.cue",
 	"values-tmpl/url-shortener.cue",
+	"values-tmpl/gerrit.cue",
 }
 
 var infraAppConfigs = []string{
diff --git a/core/installer/app_test.go b/core/installer/app_test.go
index 6b84005..237c806 100644
--- a/core/installer/app_test.go
+++ b/core/installer/app_test.go
@@ -129,3 +129,43 @@
 		t.Log(string(r))
 	}
 }
+
+func TestGerrit(t *testing.T) {
+	r := NewInMemoryAppRepository(CreateAllApps())
+	a, err := r.Find("gerrit")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if a == nil {
+		t.Fatal("returned app is nil")
+	}
+	d := Derived{
+		Release: Release{
+			Namespace: "foo",
+		},
+		Global: Values{
+			PCloudEnvName:   "dodo",
+			Id:              "id",
+			ContactEmail:    "foo@bar.ge",
+			Domain:          "bar.ge",
+			PrivateDomain:   "p.bar.ge",
+			PublicIP:        "1.2.3.4",
+			NamespacePrefix: "id-",
+		},
+		Values: map[string]any{
+			"subdomain": "gerrit",
+			"network": map[string]any{
+				"name":         "Private",
+				"ingressClass": "id-ingress-private",
+				"domain":       "p.bar.ge",
+			},
+		},
+	}
+	rendered, err := a.Render(d)
+	if err != nil {
+		t.Fatal(err)
+	}
+	for _, r := range rendered.Resources {
+		t.Log(string(r))
+	}
+}
diff --git a/core/installer/values-tmpl/gerrit.cue b/core/installer/values-tmpl/gerrit.cue
new file mode 100644
index 0000000..5045e52
--- /dev/null
+++ b/core/installer/values-tmpl/gerrit.cue
@@ -0,0 +1,256 @@
+input: {
+	network: #Network
+	subdomain: string
+}
+
+_domain: "\(input.subdomain).\(input.network.domain)"
+
+name: "gerrit"
+namespace: "app-gerrit"
+readme: "gerrit"
+description: "Gerrit Code Review is a web-based code review tool built on Git version control. Gerrit provides a framework you and your teams can use to review code before it becomes part of the code base. Gerrit works equally well in open source projects that limit the number of users who can approve changes (typical in open source software development) and in projects in which all contributors are trusted."
+icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 32 32'><path fill='currentColor' d='m16.865 3.573l-.328-.359c.005-.005.385-.354.552-.542c.161-.198.453-.646.458-.651l.406.26c-.021.021-.313.479-.5.698s-.573.573-.589.594zm2.104 14.125c-.016-.005-.323-.203-.49-.292a11.695 11.695 0 0 0-.563-.255l.286-.818l-1.198-.589l-.38 1.161c-.234.005-.953.068-2.016.516c-1.281.536-2.25 1.37-2.26 1.375l-.193.167l.859.031l.026-.021c.005-.01.958-.714 1.49-.943c.12-.047.276-.099.443-.135c-.281.135-.589.302-.802.422c-.266.161-.76.51-.781.526l-.25.172l.911.021l.026-.01c.016-.01 1.552-.833 2.385-1.016l.26-.063c.193-.047.328-.083.563-.083c.208 0 .49.026.917.094c.531.078.88.208.885.214l.318.125l-.427-.583l-.016-.01zM6.995 7.969h-.042L5.614 9.193v.036c-.021.354.104.693.344.958c.24.26.557.411.911.422h.057c.708 0 1.286-.547 1.323-1.25a1.338 1.338 0 0 0-1.255-1.391zm-.063 2.442H6.88a.999.999 0 0 1-.443-.115a.692.692 0 0 0 .797-.766a.689.689 0 0 0-.771-.589a.69.69 0 0 0-.594.708a1.113 1.113 0 0 1-.057-.37l1.214-1.115a1.141 1.141 0 0 1 1.026 1.177a1.12 1.12 0 0 1-1.125 1.068zM19.37 5.443l-.391-.26l-.547.354l-.526-.38l-.401.24l.542.391l-.557.359l.396.24l.536-.339l.516.375l.411-.229l-.542-.391zM32 26.031c-.286-.276-.557-.552-.839-.833a76.772 76.772 0 0 1-1.891-1.984a42.827 42.827 0 0 1-2.109-2.458a17.1 17.1 0 0 1-.859-1.172a13.625 13.625 0 0 1-.891-1.62a30.908 30.908 0 0 1-.771-1.807c.323.276.62.589.885.922c.026-.286.057-.573.078-.865l.031-.427c0-.047.016-.089-.01-.13a.46.46 0 0 0-.073-.099c-.156-.198-.349-.375-.536-.552a32.19 32.19 0 0 0-.781-.708l-.24-.208c-.036-.036-.078-.068-.115-.099c-.042-.042-.057-.13-.073-.182l-.208-.641c.813.38 1.479.99 2.104 1.62c.005-.292.005-.578 0-.87c0-.151 0-.302-.01-.458c0-.042.01-.135-.021-.172c-.016-.026-.042-.047-.057-.073c-.146-.156-.313-.286-.474-.417c-.229-.193-.469-.37-.703-.547c-.208-.156-.422-.307-.635-.458c-.026-.021-.104-.052-.089-.078l.052-.109c.031-.047.021-.057.073-.036l.229.078c.536.208 1.036.49 1.521.813a8.413 8.413 0 0 0-.698-1.729a13.423 13.423 0 0 0-1.953-2.807a16.75 16.75 0 0 0-1.625-1.594c-.297-.25-.609-.49-.932-.708c-.151-.099-.297-.198-.458-.292c-.068-.036-.141-.073-.203-.125c-.24-.188-.484-.375-.729-.568c.318.13.625.276.917.448c-.167-.26-.453-.443-.724-.578a7.706 7.706 0 0 0-1.292-.505c.151-.161.313-.307.464-.464c.151-.161.297-.328.438-.5c.172-.198.339-.396.5-.604l-2.182-1.37c-.161.323-.37.63-.609.906c-.24.271-.521.49-.802.719c-.25.208-.505.417-.75.625c-.068.057-.125.115-.198.161c-.031.031-.125.005-.167.005h-.318c-.396.01-.792.042-1.188.094c-.078.005-.151.016-.234.01l-.234-.016c-.182-.01-.365-.021-.547-.021c-.385-.005-.771 0-1.161.031a6.8 6.8 0 0 0-.969.151a2.52 2.52 0 0 0-.88.417c-.26.188-.516.427-.672.708c-.156.276-.229.604-.286.917c-.177.016-.354.016-.531.021a6.527 6.527 0 0 0-1.614.292a4.907 4.907 0 0 0-1.781 1a5.58 5.58 0 0 0-.719.797c-.026.031-.052.068-.083.089c-.016.01-.036.021-.047.036a.693.693 0 0 1-.068.099l-.177.286c-.224.38-.37.792-.51 1.208l-.063.161l.047-.026a3.772 3.772 0 0 0-.036.271l-.01.135v.073l-.089.016a5.981 5.981 0 0 0-.531.135a1.86 1.86 0 0 0-.448.203c-.141.083-.26.203-.38.318a3.42 3.42 0 0 0-.917 1.5c-.135.469-.182.984-.078 1.458c.026.12.063.25.141.349c.099.12.266.167.417.125c.177-.047.333-.161.495-.245l.422-.214c.604-.297 1.24-.594 1.917-.698c.047-.005.13.089.172.12c.068.052.135.099.198.141c.146.094.297.172.448.24c.349.151.719.234 1.089.307c.672.141 1.354.229 2.042.24c.276.005.552 0 .833-.021c.297-.026.599-.068.901-.068c.333-.005.661.031.99.073c.339.042.677.089 1.016.141c.693.104 1.375.224 2.057.37c-.151.24-.302.484-.448.729c-.01.016-.099 0-.12 0a.932.932 0 0 0-.167 0c-.099 0-.203.01-.302.026a3.886 3.886 0 0 0-.818.203c-.656.245-1.255.646-1.771 1.115c-.297.26-.573.542-.813.854a6.7 6.7 0 0 0-.182.255c.135-.031.281-.057.422-.094c.083-.021.156-.036.234-.052c.026-.01.036-.021.068-.036a9.04 9.04 0 0 1 .922-.75c.151-.104.302-.203.469-.286c.219-.109.469-.172.708-.229c-.438.24-.906.464-1.302.776c-.229.188-.438.391-.656.589l.875-.141c.01 0 .016-.005.031-.016l.224-.125c.151-.083.307-.167.464-.245c.318-.167.641-.323.974-.453c.318-.125.641-.24.979-.302c.292-.063.568-.068.865 0c.453.099.891.307 1.292.552c.026.021.047.047.073.021c.021-.021.13-.099.12-.125l-.24-.443c-.021-.042-.031-.068-.068-.089l-.177-.104a7.51 7.51 0 0 1-.677-.443c-.052-.031-.104-.052-.109-.12c-.01-.057.016-.12.036-.177c.042-.12.104-.229.172-.333c.047-.078.099-.146.146-.219c.021-.026.016-.031.042-.021l.161.047c.313.104.625.214.948.292c.359.094.724.167 1.094.234l.063.016c-.073-.042-.12-.12-.177-.182c-.031-.042-.047-.068-.099-.078l-.141-.031c-.099-.021-.193-.036-.297-.063a8.596 8.596 0 0 1-1.036-.281a15.4 15.4 0 0 0-1.526-.427a37.19 37.19 0 0 0-1.953-.365c-.333-.057-.667-.099-1-.146a15.528 15.528 0 0 0-.995-.12c-.719-.042-1.432.12-2.156.109c-.484-.005-.979-.073-1.458-.141l-.094-.01c.339-.125.667-.25 1-.38c.318-.125.63-.255.943-.385c.167-.068.333-.141.495-.208c.151-.068.302-.135.438-.229c.547-.37.901-.969 1.302-1.479c.365-.479.781-.932 1.318-1.208c.172-.089.349-.156.536-.208c-.38-.583-.734-1.24-.833-1.938l.125.047c.047.016.089.021.099.063l.036.177c.036.12.073.234.115.349c.099.255.214.5.349.734a10.87 10.87 0 0 0 1.021 1.495c.719.917 1.526 1.74 2.313 2.589c.193.208.37.432.547.656c.203.25.406.5.609.745c.161.188.313.38.474.568l.125.151c.021.026.052.036.083.047c.807.401 1.62.802 2.427 1.193c.583.281 1.161.563 1.75.833c.313.146.625.292.948.427c.036.016.083.036.13.052c.021.01.036.021.063.031l.021.063c.036.099.068.193.099.292c.068.188.13.37.198.552c.443 1.219.927 2.422 1.526 3.568a71.35 71.35 0 0 0 1.453 2.589c.536.906 1.083 1.802 1.635 2.698c.443.714.885 1.432 1.344 2.141c.193.302.385.615.583.917l.083.125l1.292-1.896c.01-.01.109-.135.099-.146l-.208-.323c-.385-.599-.776-1.198-1.161-1.797l-1.245-1.932l.875 1.063l1.49 1.802c.161.193.313.385.469.583c.292-.536.589-1.068.885-1.599c.115-.219.234-.443.354-.656zM16.172 2.552c.411-.328.75-.75 1.01-1.208l1.573.995l.24.146c-.328.401-.661.807-1.036 1.167a2.002 2.002 0 0 0-.141.135c-.026.036-.063.068-.094.099l-.042.052c-.031-.01-.063-.021-.094-.026c-.193-.052-.385-.104-.578-.146a11.358 11.358 0 0 0-1.182-.203c-.255-.031-.516-.052-.771-.078c.365-.313.74-.625 1.115-.932zM13.833 4.38c.313-.13.646-.198.974-.255a7.25 7.25 0 0 1 1.984-.052c.474.052.938.141 1.391.281l-.188.151l-.302-.083c-.188-.036-.375-.078-.563-.109a7.856 7.856 0 0 0-1-.083a6.98 6.98 0 0 0-1.828.208a5.861 5.861 0 0 0-1.172.443c-.38.208-.74.464-1.036.776a3.391 3.391 0 0 0-.479.609c-.078.12-.141.24-.203.365a1.56 1.56 0 0 0-.078.193l-.042.099a.406.406 0 0 1-.016.052l-.089-.016l-.109-.01c.313-.964 1.016-1.719 1.891-2.203c.276-.151.568-.286.865-.37zm-5.239.495c.354-.51.917-.865 1.521-.995c.667-.13 1.354-.156 2.031-.141c-.698.177-1.401.438-1.984.87a3.041 3.041 0 0 0-1.245.609a3.08 3.08 0 0 0-.328.318a1.25 1.25 0 0 0-.13.156c-.016.016-.036.036-.047.063h-.115c.031-.177.073-.359.13-.531c.042-.12.089-.24.161-.349zm1.172.078a4.718 4.718 0 0 0-.521.625c-.063.089-.13.203-.24.25c-.115.052-.26-.005-.375-.036a2.76 2.76 0 0 1 1.135-.839zM3.078 8.781c.104-.214.24-.422.365-.62c.021-.036.073-.063.099-.083c.068-.047.13-.094.193-.146c.411-.297.828-.594 1.25-.87c.224-.146.443-.286.672-.411c.24-.135.49-.24.75-.328A9.45 9.45 0 0 1 7.834 6c.229-.031.479-.078.708-.021c-.443.25-.88.5-1.323.745c-.453.255-.917.49-1.38.734c-.443.24-.88.5-1.307.771c-.448.276-.891.557-1.333.839c-.109.068-.214.141-.323.208c.063-.167.12-.339.203-.495zm1.344 4.073c-.036.073-.177.057-.25.057c-.125 0-.245 0-.37.005a4.13 4.13 0 0 0-1.01.188c-.635.193-1.229.5-1.823.802c-.13.073-.271.182-.422.219a.203.203 0 0 1-.219-.083a.704.704 0 0 1-.083-.266a2.255 2.255 0 0 1-.047-.49c0-.443.104-.88.286-1.281c.13-.281.297-.536.495-.766c.203-.234.438-.469.719-.599c.474-.219 1.036-.286 1.552-.313c.099-.01.193-.01.292-.01c.13 0 .286-.021.411.026c.099.036.161.141.203.229c.057.141.099.302.13.448c.083.349.167.698.193 1.057c.016.156.026.318.005.474c-.01.099-.016.208-.063.302zm3.771-2.635a4.38 4.38 0 0 1-.823.401a5.11 5.11 0 0 1-.88.24c-.13.016-.26.036-.391.026c-.135 0-.255-.047-.391-.089a4.004 4.004 0 0 1-.76-.307a.666.666 0 0 1-.229-.203a.34.34 0 0 1-.031-.229c.016-.307.125-.609.271-.88c.25-.458.641-.818 1.12-1.036c1.172-.526 2.484-.036 3.479.656l.109.078c-.208.224-.417.432-.63.641c-.266.25-.542.505-.849.703zm2.885-2.568a11.921 11.921 0 0 1-1.807-.984c.599.25 1.245.401 1.885.495c.344.047.698.094 1.042.104c.375.016.755-.026 1.12-.099c.729-.135 1.427-.406 2.089-.734s1.286-.714 1.885-1.146c.286-.203.573-.417.844-.646c.026-.021.229-.219.245-.208l.052.042l.719.557c.438.339.875.677 1.318 1.016a68.458 68.458 0 0 1-3.672 1.203c-.693.208-1.38.401-2.083.563c-.552.13-1.115.25-1.677.276c-.677.031-1.339-.177-1.958-.438zm11.797 5.255c.104.026.198.063.286.089l.13.047c.021.005.036.021.057.026l.026.078c.063.198.12.385.188.578c-.198-.172-.401-.339-.599-.505l-.12-.099c-.031-.021-.063-.031-.042-.063l.078-.151zm-.891 1.922l.047-.083l.036-.057c.016-.026.01-.031.042-.016c.172.068.344.146.51.224c.323.146.635.307.938.484c.146.089.292.182.432.276l.198.141l.099.073c.042.036.057.083.078.135c.135.375.292.755.448 1.125c.104.255.219.505.333.755a14.762 14.762 0 0 0-1.276-1.391a20.964 20.964 0 0 0-1.438-1.307l-.432-.354zm5.011 8.568l-.161.12l.01.021l.083.125l.365.557l1.203 1.87c.417.641.828 1.286 1.245 1.927l.411.641l.109.177a.256.256 0 0 1 .042.063c-.349.51-.698 1.026-1.047 1.536c-.036.047-.068.099-.099.146c-.318-.495-.635-.99-.953-1.49c-.531-.844-1.057-1.703-1.578-2.552a106.797 106.797 0 0 1-1.688-2.854c-.51-.901-1-1.818-1.411-2.771a39.425 39.425 0 0 1-1.078-2.828c.646.26 1.307.49 1.974.698c.193.057.385.12.578.167l.083.026c.01 0 .021-.052.026-.068c.026-.083.042-.172.063-.26c.036-.167.068-.339.094-.505c.276.568.583 1.125.938 1.646c.286.422.594.828.917 1.229a43.68 43.68 0 0 0 2.188 2.531c.62.656 1.245 1.313 1.88 1.953l.516.516c.01.01.052.042.052.057l-.042.068l-.198.37l-.786 1.422c-.24-.292-.479-.578-.719-.875l-1.5-1.818c-.422-.516-.849-1.031-1.271-1.547l-.25-.297z'/></svg>"
+
+_ingressWithAuthProxy: _IngressWithAuthProxy & {
+	inp: {
+		auth: {
+			enabled: true
+		}
+		network: input.network
+		subdomain: input.subdomain
+		serviceName: "gerrit-gerrit-service"
+		port: number: _httpPort // TODO(gio): make optional
+	}
+}
+
+// TODO(gio): configure busybox
+_images: _ingressWithAuthProxy.out.images & {
+	gerrit: #Image & {
+		repository: "k8sgerrit"
+		name: "gerrit"
+		tag: _latest
+		pullPolicy: "Always"
+	}
+	gerritInit: #Image & {
+		repository: "k8sgerrit"
+		name: "gerrit-init"
+		tag: _latest
+		pullPolicy: "Always"
+	}
+	gitGC: #Image & {
+		repository: "k8sgerrit"
+		name: "git-gc"
+		tag: _latest
+		pullPolicy: "Always"
+	}
+}
+images: _images
+
+charts: _ingressWithAuthProxy.out.charts & {
+	ingress: {
+		chart: "charts/ingress"
+		sourceRef: {
+			kind: "GitRepository"
+			name: "pcloud"
+			namespace: global.id
+		}
+	}
+	volume: {
+		chart: "charts/volumes"
+		sourceRef: {
+			kind: "GitRepository"
+			name: "pcloud"
+			namespace: global.id
+		}
+	}
+	gerrit: {
+		chart: "charts/gerrit"
+		sourceRef: {
+			kind: "GitRepository"
+			name: "pcloud"
+			namespace: global.id
+		}
+	}
+}
+
+volumes: {
+	git: {
+		name: "git"
+		accessMode: "ReadWriteMany"
+		size: "50Gi"
+	}
+	logs: {
+		name: "logs"
+		accessMode: "ReadWriteMany"
+		size: "5Gi"
+	}
+}
+
+_dockerIO: "docker.io"
+_latest: "latest"
+
+_longhorn: "longhorn"
+
+_httpPort: 80
+_sshPort: 22
+
+helm: _ingressWithAuthProxy.out.helm & {
+	gerrit: {
+		chart: charts.gerrit
+		values: {
+			images: {
+				busybox: {
+					registry: _dockerIO
+					tag: _latest
+				}
+				registry: {
+					name: _dockerIO
+					ImagePullSecret: create: false
+					version: _latest
+					imagePullPolicy: "Always"
+				}
+			}
+			storageClasses: {
+				default: {
+					name: _longhorn
+					create: false
+				}
+				shared: {
+					name: _longhorn
+					create: false
+				}
+			}
+			persistence: {
+				enabled: true
+				size: "10Gi"
+			}
+			nfsWorkaround: {
+				enabled: false
+				chownOnStartup: false
+				idDomain: _domain
+			}
+			networkPolicies: enabled: false
+			gitRepositoryStorage: {
+				externalPVC: {
+					use: true
+					name: volumes.git.name
+				}
+			}
+			logStorage: {
+				enabled: true
+				externalPVC: {
+					use: true
+					name: volumes.logs.name
+				}
+			}
+			ingress: enabled: false
+			gitGC: {
+				image: _images.gitGC.imageName
+				logging: persistence: enabled: false
+			}
+			gerrit: {
+				images: {
+					gerritInit: _images.gerritInit.imageName
+					gerrit: _images.gerrit.imageName
+				}
+				service: {
+					type: "LoadBalancer"
+					externalTrafficPolicy: ""
+					additionalAnnotations: {
+						"metallb.universe.tf/address-pool": global.id
+					}
+					http: port: _httpPort
+					ssh: {
+						enabled: true
+						port: _sshPort
+					}
+				}
+				pluginManagement: {
+					plugins: [{
+						name: "gitiles"
+					}]
+					libs: []
+					cache: enabled: false
+				}
+				etc: {
+					secret: {
+						// TODO(gio): auto generate
+						ssh_host_ecdsa_key: ###"""
+						-----BEGIN OPENSSH PRIVATE KEY-----
+						b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
+						1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTLpTYrZ3zFkfRda+q0O3nr119UeN1M
+						H4Ds59cN8NxLpSLZpWn7vLxigN2VCP373Lq5ulUbDojW5qvF2gGppA+4AAAAsHSkAHN0pA
+						BzAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMulNitnfMWR9F1r
+						6rQ7eevXX1R43UwfgOzn1w3w3EulItmlafu8vGKA3ZUI/fvcurm6VRsOiNbmq8XaAamkD7
+						gAAAAhAOzrB8wjiWKzKsrzepkgFbs/CoIT8TBdaPv2aLWPcZr4AAAAFmdlcnJpdEBwLnYw
+						LmRvZG8uY2xvdWQB
+						-----END OPENSSH PRIVATE KEY-----
+						"""###
+						"ssh_host_ecdsa_key.pub": "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMulNitnfMWR9F1r6rQ7eevXX1R43UwfgOzn1w3w3EulItmlafu8vGKA3ZUI/fvcurm6VRsOiNbmq8XaAamkD7g="
+					}
+					config: {
+						"replication.config": ###"""
+[gerrit]
+  autoReload = false
+  replicateOnStartup = true
+  defaultForceUpdate = true"""###
+						"gerrit.config": ###"""
+[gerrit]
+  basePath = git # FIXED
+  serverId = gerrit-1
+  # The canonical web URL has to be set to the Ingress host, if an Ingress
+  # is used. If a LoadBalancer-service is used, this should be set to the
+  # LoadBalancer's external IP. This can only be done manually after installing
+  # the chart, when you know the external IP the LoadBalancer got from the
+  # cluster.
+  canonicalWebUrl = https://gerrit.p.v0.dodo.cloud
+  disableReverseDnsLookup = true
+[index]
+  type = LUCENE
+[auth]
+  type = HTTP
+  httpHeader = X-User
+  emailFormat = '{0}@v0.dodo.cloud'
+  # loginUrl = https://accounts-ui.v0.dodo.cloud/
+  # loginText = Sign In with dodo
+  logoutUrl = https://accounts-ui.v0.dodo.cloud/logout
+  gitBasicAuthPolicy = HTTP
+  userNameToLowerCase = true
+  userNameCaseInsensitive = true
+[httpd]
+  # If using an ingress use proxy-http or proxy-https
+  listenUrl = proxy-http://*:8080/
+  requestLog = true
+  gracefulStopTimeout = 1m
+[sshd]
+  listenAddress = 0.0.0.0:29418
+[transfer]
+  timeout = 120 s
+[user]
+  name = Gerrit Code Review
+  email = gerrit@p.v0.dodo.cloud
+  anonymousCoward = Unnamed User
+[cache]
+  directory = cache
+[container]
+  user = gerrit # FIXED
+  javaHome = /usr/lib/jvm/java-11-openjdk # FIXED
+  javaOptions = -Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore # FIXED
+  javaOptions = -Xms200m
+  # Has to be lower than 'gerrit.resources.limits.memory'. Also
+  # consider memories used by other applications in the container.
+  javaOptions = -Xmx4g"""###
+					}
+				}
+			}
+		}
+	}
+	"git-volume": {
+		chart: charts.volume
+		values: volumes.git
+	}
+	"log-volume": {
+		chart: charts.volume
+		values: volumes.logs
+	}
+}