Merge "Do not run multiple Git-GC jobs concurrently"
diff --git a/Documentation/istio.md b/Documentation/istio.md
new file mode 100644
index 0000000..d9c7a31
--- /dev/null
+++ b/Documentation/istio.md
@@ -0,0 +1,57 @@
+# Istio
+
+Istio provides an alternative way to control ingress traffic into the cluster.
+In addition, it allows to finetune the traffic inside the cluster and provides
+a huge repertoire of load balancing and routing mechanisms.
+
+***note
+Currently, only the Gerrit replica chart allows using istio out of the box.
+***
+
+## Dependencies
+
+- istioctl \
+  To install follow these
+  [instructions](https://istio.io/docs/ops/diagnostic-tools/istioctl/#install-hahahugoshortcode-s2-hbhb)
+
+## Install istio
+
+An example configuration based on the default profile provided by istio can be
+found under `./istio/gerrit.profile.yaml`. To install istio with this profile,
+run:
+
+```sh
+istioctl manifest apply -f istio/gerrit.profile.yaml
+```
+
+To install Gerrit using istio for networking, the namespace running Gerrit has to
+be configured to enable sidecar injection, by setting the `istio-injection: enabled`
+label. An example for such a namespace can be found at `./istio/namespace.yaml`.
+
+To be able to use Kiali, credentials have to be provided. A secret for doing so,
+can be found at `./istio/kiali.secret.yaml`. Adapt the credentials and apply them:
+
+```sh
+kubectl apply -f ./istio/kiali.secret.yaml
+```
+
+## Uninstall istio
+
+To uninstall istio, run:
+
+```sh
+istioctl manifest generate -f istio/gerrit.profile.yaml > istio/gerrit.manifest.yaml
+kubectl delete -f istio/gerrit.manifest.yaml
+```
+
+## Restricting access to a list of allowed IPs
+
+In development setups, it might be wanted to allow access to the setup only from
+specified IPs. This can usually be done using an AuthorizationPolicy. On AWS this
+does not work, since the load balancer hides the original IP. However, the
+istio-ingressgateway can be patched to enable access only from a given range of
+IPs. To do this, use the following command:
+
+```sh
+kubectl patch service istio-ingressgateway -n istio-system -p '{"spec":{"loadBalancerSourceRanges":["1.2.3.4"]}}'
+```
diff --git a/README.md b/README.md
index 64447d3..709ff47 100644
--- a/README.md
+++ b/README.md
@@ -3,9 +3,38 @@
 Container images, configurations and [Helm](https://helm.sh/) charts for installing
 [Gerrit](https://www.gerritcodereview.com/) on [Kubernetes](https://kubernetes.io/).
 
+# Deploying Gerrit on Kubernetes
+
+This project provides helm-charts to install Gerrit either as a primary instance
+or a replica on Kubernetes.
+
+The helm-charts are located in the `./helm-charts`-directory. Currently, the
+charts are not published in a registry and have to be deployed from local
+sources.
+For a detailed guide of how to install the helm-charts refer to the respective
+READMEs in the helm-charts directories:
+
+- [gerrit](helm-charts/gerrit/README.md)
+- [gerrit-replica](helm-charts/gerrit-replica/README.md)
+
+These READMEs detail the prerequisites required by the charts as well as all
+configuration options currently provided by the charts.
+
+To evaluate and test the helm-charts, they can be installed on a local machine
+running Minikube. Follow this [guide](Documentation/minikube.md) to get a detailed
+description how to set up the Minikube cluster and install the charts.
+
 # Docker images
 
-Images to run a Gerrit and Gerrit replica setup based on the 3.1.7 Gerrit release.
+This project provides the sources for docker images based on the 3.1.7 Gerrit
+release used by the helm-charts. The images are also provided on
+[Dockerhub](https://hub.docker.com/u/k8sgerrit).
+
+The project also provides script to build and publish the images, so that custom
+versions can be used by the helm-charts. This requires however a docker registry
+that can be accessed from the Kubernetes cluster, on which Gerrit will be
+deployed. The functionality of the scripts is described in the following sub-
+sections.
 
 ## Building images
 
@@ -16,7 +45,7 @@
 ./build
 ```
 
-If a specific image should be build, the image name can be specified as an argument.
+If a specific image should be built, the image name can be specified as an argument.
 Multiple images can be specified at once:
 
 ```
@@ -30,6 +59,13 @@
 ./build --tag test
 ```
 
+The version of Gerrit built into the images can be changed by providing a download
+URL for a `.war`-file containing Gerrit:
+
+```
+./build --gerrit-url https://example.com/gerrit.war
+```
+
 The build script will in addition tag the image with the output of
 `git describe --dirty`.
 
@@ -60,7 +96,7 @@
 ```
 
 The `<component-name>` is one of: `apache-git-http-backend`, `git-gc`,
-`gerrit-replica`.
+`gerrit-replica`, `gerrit` or `gerrit-init`.
 
 Adding the `--update-latest`-flag will also update the images tagged `latest` in
 the repository:
@@ -69,7 +105,6 @@
 ./publish --update-latest <component-name>
 ```
 
-
 ## Running images in Docker
 
 The container images are meant to be used by the helm-charts provided in this
@@ -78,41 +113,6 @@
 [docker-gerrit](https://gerrit-review.googlesource.com/admin/repos/docker-gerrit)
 project.
 
-## Important notes
-
-Currently, java is installed under `/usr/lib/jvm/java-8-openjdk-amd64/jre`.
-Therefore, make sure that `container.javaHome` is set to that path in the `gerrit.config`:
-```
-  javaHome = /usr/lib/jvm/java-8-openjdk-amd64/jre
-```
-
-# Helm Charts
-
-These Helm charts can be used to install a Gerrit cluster consisting of a
-Gerrit and a Gerrit replica on a Kubernetes cluster. A helm version newer
-than 3.0 is required to follow the instructions provided with the helm charts.
-
-To evaluate and test the helm-charts, they can be installed on a local machine
-running Minikube. Follow this [guide](Documentation/minikube.md) to get a detailed
-description how to set up the Minikube cluster and install the charts.
-
-## File System Storage
-
-Currently this deployment uses NFS, some options:
-
-* Create an EFS volume on AWS
-* Install a NFS server on Kubernetes cluster which doesn't have read-write-many
-Persistent Volumes available using
-[NFS-provisioner](helm-charts/gerrit/docs/nfs-provisioner.md)
-
-## Gerrit
-
-* Install a [Gerrit](helm-charts/gerrit/README.md)
-
-## Gerrit Replica
-
-* Install a [Gerrit replica](helm-charts/gerrit-replica/README.md)
-
 # Running tests
 
 The tests are implemented using Python and `pytest`. To ensure a well-defined
@@ -256,3 +256,17 @@
 projects. The username has to be given by `--gerit-user`. Setting the
 `--gerrit-pwd`-flag will cause a password prompt to enter the password of the
 Gerrit-user.
+
+# Contributing
+
+Contributions to this project are welcome. If you are new to the Gerrit workflow,
+refer to the [Gerrit-documentation](https://gerrit-review.googlesource.com/Documentation/intro-gerrit-walkthrough.html)
+for guidance on how to contribute changes.
+
+The contribution guidelines for this project can be found
+[here](Documentation/developer-guide.md).
+
+# Contact
+
+The [Gerrit Mailing List](https://groups.google.com/forum/#!forum/repo-discuss)
+can be used to post questions and comments on this project or Gerrit in general.
diff --git a/build b/build
index 6511309..8dca157 100755
--- a/build
+++ b/build
@@ -2,12 +2,16 @@
 
 usage() {
     me=`basename "$0"`
-    echo >&2 "Usage: $me [--tag TAG] [--gerrit-url URL] [IMAGE]"
+    echo >&2 "Usage: $me [--help] [--tag TAG] [--gerrit-url URL] [IMAGE]"
     exit 1
 }
 
 while test $# -gt 0 ; do
   case "$1" in
+  --help)
+    usage
+    ;;
+
   --tag)
     shift
     TAG=$1
@@ -25,6 +29,10 @@
   esac
 done
 
+#Get list of images
+source container-images/publish_list
+IMAGES=$(get_image_list)
+
 GIT_REV=$(git describe --dirty)
 
 test -z "$TAG" && TAG=latest
@@ -63,7 +71,7 @@
 
 if test $# -eq 0 ; then
     docker_build_gerrit_base
-    for IMAGE in apache-git-http-backend gerrit gerrit-replica git-gc gerrit-init; do
+    for IMAGE in $IMAGES; do
         docker_build $IMAGE
     done
 else
diff --git a/container-images/apache-git-http-backend/config/git-http-backend.conf b/container-images/apache-git-http-backend/config/git-http-backend.conf
index 0996b15..2c84d00 100644
--- a/container-images/apache-git-http-backend/config/git-http-backend.conf
+++ b/container-images/apache-git-http-backend/config/git-http-backend.conf
@@ -24,8 +24,11 @@
   # modules, e.g.
   LogLevel warn
 
+  # Don't log probe requests performed by kubernetes
+  SetEnvIFNoCase User-Agent "^kube-probe" dontlog
+
   ErrorLog ${APACHE_LOG_DIR}/error.log
-  CustomLog ${APACHE_LOG_DIR}/access.log combined
+  CustomLog ${APACHE_LOG_DIR}/access.log combined env=!dontlog
 
   # For most configuration files from conf-available/, which are
   # enabled or disabled at a global level, it is possible to
diff --git a/container-images/apache-git-http-backend/config/git-https-backend.conf b/container-images/apache-git-http-backend/config/git-https-backend.conf
index 4ee3ea4..e2356f3 100644
--- a/container-images/apache-git-http-backend/config/git-https-backend.conf
+++ b/container-images/apache-git-http-backend/config/git-https-backend.conf
@@ -24,8 +24,11 @@
   # modules, e.g.
   LogLevel warn
 
+  # Don't log probe requests performed by kubernetes
+  SetEnvIFNoCase User-Agent "^kube-probe" dontlog
+
   ErrorLog ${APACHE_LOG_DIR}/error.log
-  CustomLog ${APACHE_LOG_DIR}/access.log combined
+  CustomLog ${APACHE_LOG_DIR}/access.log combined env=!dontlog
 
   SSLEngine on
   SSLCertificateFile /var/apache/credentials/server.crt
diff --git a/container-images/apache-git-http-backend/config/httpd.conf b/container-images/apache-git-http-backend/config/httpd.conf
index dab4881..ce11b35 100644
--- a/container-images/apache-git-http-backend/config/httpd.conf
+++ b/container-images/apache-git-http-backend/config/httpd.conf
@@ -178,6 +178,13 @@
 User ${APACHE_RUN_USER}
 Group ${APACHE_RUN_GROUP}
 
+#
+# Timeout defines, in seconds, the amount of time that the server waits for
+# receipts and transmissions during communications. Timeout is set to 300
+# seconds by default, which is appropriate for most situations.
+#
+Timeout 300
+
 </IfModule>
 
 # 'Main' server configuration
diff --git a/container-images/gerrit-base/Dockerfile b/container-images/gerrit-base/Dockerfile
index 59766c6..de4c378 100644
--- a/container-images/gerrit-base/Dockerfile
+++ b/container-images/gerrit-base/Dockerfile
@@ -8,6 +8,8 @@
 
 RUN mkdir -p /var/gerrit/bin && \
     mkdir -p /var/gerrit/etc && \
+    mkdir -p /var/gerrit/plugins && \
+    mkdir -p /var/plugins && \
     mkdir -p /var/war
 
 # Download Gerrit release
@@ -15,10 +17,16 @@
 RUN curl -k -o /var/war/gerrit.war ${GERRIT_WAR_URL} && \
     ln -s /var/war/gerrit.war /var/gerrit/bin/gerrit.war
 
+# Download healthcheck plugin
+RUN curl -k -o /var/plugins/healthcheck.jar \
+        https://gerrit-ci.gerritforge.com/job/plugin-healthcheck-bazel-stable-3.1/lastSuccessfulBuild/artifact/bazel-bin/plugins/healthcheck/healthcheck.jar && \
+    ln -s /var/plugins/healthcheck.jar /var/gerrit/plugins/healthcheck.jar
+
 # Allow incoming traffic
 EXPOSE 29418 8080
 
 RUN chown -R gerrit:users /var/gerrit && \
+    chown -R gerrit:users /var/plugins && \
     chown -R gerrit:users /var/war
 USER gerrit
 
diff --git a/container-images/gerrit-init/Dockerfile b/container-images/gerrit-init/Dockerfile
index 9049214..1cfa326 100644
--- a/container-images/gerrit-init/Dockerfile
+++ b/container-images/gerrit-init/Dockerfile
@@ -16,8 +16,6 @@
 COPY tools/* /var/tools/
 COPY config/* /var/config/
 
-COPY tools/* /var/tools/
-
 USER gerrit
 
 ENTRYPOINT ["/var/tools/gerrit_init.py", "-s", "/var/gerrit"]
diff --git a/container-images/gerrit-init/tools/download_plugins.py b/container-images/gerrit-init/tools/download_plugins.py
index 3615b93..e9fcc6c 100755
--- a/container-images/gerrit-init/tools/download_plugins.py
+++ b/container-images/gerrit-init/tools/download_plugins.py
@@ -17,6 +17,7 @@
 import argparse
 import hashlib
 import os
+import shutil
 import time
 
 from abc import ABC, abstractmethod
@@ -40,6 +41,8 @@
         self.site = site
         self.config = config
 
+        self.required_plugins = self._get_required_plugins()
+
         self.plugin_dir = os.path.join(site, "plugins")
         self.plugins_changed = False
 
@@ -54,6 +57,31 @@
 
         return list()
 
+    def _get_required_plugins(self):
+        required = [
+            os.path.splitext(f)[0]
+            for f in os.listdir("/var/plugins")
+            if f.endswith(".jar")
+        ]
+        return list(
+            filter(
+                lambda x: x not in self.config.get_all_configured_plugins(), required
+            )
+        )
+
+    def _install_plugins_from_container(self):
+        source_dir = "/var/plugins"
+        for plugin in self.required_plugins:
+            source_file = os.path.join(source_dir, plugin + ".jar")
+            target_file = os.path.join(self.plugin_dir, plugin + ".jar")
+            if os.path.exists(target_file) and self._get_file_sha(
+                source_file
+            ) == self._get_file_sha(target_file):
+                continue
+
+            shutil.copyfile(source_file, target_file)
+            self.plugins_changed = True
+
     @staticmethod
     def _get_file_sha(file):
         file_hash = hashlib.sha1()
@@ -69,8 +97,8 @@
         return file_hash.hexdigest()
 
     def _remove_unwanted_plugins(self):
-        wanted_plugins = [plugin["name"] for plugin in self.config.downloaded_plugins]
-        wanted_plugins.extend(self.config.packaged_plugins)
+        wanted_plugins = list(self.config.get_all_configured_plugins())
+        wanted_plugins.extend(self.required_plugins)
         for plugin in self._get_installed_plugins():
             if os.path.splitext(plugin)[0] not in wanted_plugins:
                 os.remove(os.path.join(self.plugin_dir, plugin))
@@ -79,6 +107,7 @@
     def execute(self):
         self._create_plugins_dir()
         self._remove_unwanted_plugins()
+        self._install_plugins_from_container()
 
         for plugin in self.config.downloaded_plugins:
             self._install_plugin(plugin)
diff --git a/container-images/gerrit-init/tools/init_config.py b/container-images/gerrit-init/tools/init_config.py
index 266fdde..f20c71b 100644
--- a/container-images/gerrit-init/tools/init_config.py
+++ b/container-images/gerrit-init/tools/init_config.py
@@ -44,3 +44,8 @@
             self.plugin_cache_dir = config["pluginCacheDir"]
 
         return self
+
+    def get_all_configured_plugins(self):
+        plugins = set(self.packaged_plugins)
+        plugins.update([p["name"] for p in self.downloaded_plugins])
+        return plugins
diff --git a/container-images/gerrit-replica/tools/start b/container-images/gerrit-replica/tools/start
index 9dfb11c..5433086 100755
--- a/container-images/gerrit-replica/tools/start
+++ b/container-images/gerrit-replica/tools/start
@@ -2,15 +2,14 @@
 
 symlink_config_to_site(){
   mkdir -p /var/gerrit/etc
-  for file in keystore gerrit.config secure.config; do
-    test -f /var/config/$file && \
-      ln -sf /var/config/$file /var/gerrit/etc/$file
+  for file in /var/mnt/etc/config/* /var/mnt/etc/secret/*; do
+      ln -sf $file /var/gerrit/etc/$(basename $file)
   done
 }
 
-# Ensure that configuration provided at /var/config is symlinked to the Gerrit
-# site. This is necessary, because mounting files from secrets/configmaps in
-# Kubernetes make the containing directory read-only.
+# Ensure that configuration provided at /var/mnt/config and /var/mnt/secret
+# is symlinked to the Gerrit site. This is necessary, because mounting files
+# from secrets/configmaps in Kubernetes make the containing directory read-only.
 symlink_config_to_site
 
 # workaround gerrit.sh does not start httpd
diff --git a/container-images/gerrit/tools/start b/container-images/gerrit/tools/start
index eddc1fd..05b76ba 100755
--- a/container-images/gerrit/tools/start
+++ b/container-images/gerrit/tools/start
@@ -2,15 +2,14 @@
 
 symlink_config_to_site(){
     mkdir -p /var/gerrit/etc
-    for file in keystore gerrit.config secure.config replication.config; do
-        test -f /var/config/$file && \
-            ln -sf /var/config/$file /var/gerrit/etc/$file
+    for file in /var/mnt/etc/config/* /var/mnt/etc/secret/*; do
+        ln -sf $file /var/gerrit/etc/$(basename $file)
     done
 }
 
-# Ensure that configuration provided at /var/config is symlinked to the Gerrit
-# site. This is necessary, because mounting files from secrets/configmaps in
-# Kubernetes make the containing directory read-only.
+# Ensure that configuration provided at /var/mnt/config and /var/mnt/secret
+# is symlinked to the Gerrit site. This is necessary, because mounting files
+# from secrets/configmaps in Kubernetes make the containing directory read-only.
 symlink_config_to_site
 
 java -jar /var/gerrit/bin/gerrit.war reindex \
diff --git a/container-images/git-gc/Dockerfile b/container-images/git-gc/Dockerfile
index 4638176..1c469fa 100644
--- a/container-images/git-gc/Dockerfile
+++ b/container-images/git-gc/Dockerfile
@@ -5,6 +5,8 @@
 RUN mkdir -p /var/log/git && \
     chown gerrit:users /var/log/git
 
+USER gerrit
+
 VOLUME ["/var/gerrit/git"]
 
 ENTRYPOINT ["/var/tools/gc-all.sh"]
diff --git a/container-images/publish_list b/container-images/publish_list
new file mode 100644
index 0000000..7f58473
--- /dev/null
+++ b/container-images/publish_list
@@ -0,0 +1,7 @@
+get_image_list(){
+  echo  "apache-git-http-backend" \
+        "gerrit-init" \
+        "gerrit" \
+        "gerrit-replica" \
+        "git-gc"
+}
diff --git a/helm-charts/gerrit-replica/README.md b/helm-charts/gerrit-replica/README.md
index df0ca91..246ddce 100644
--- a/helm-charts/gerrit-replica/README.md
+++ b/helm-charts/gerrit-replica/README.md
@@ -125,11 +125,92 @@
 | `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`               |
 
+### Workaround for NFS
+
+Kubernetes will not be able to adapt the ownership of the files within NFS
+volumes. Thus, a workaround exists that will add init-containers and jobs to
+adapt file ownership. 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.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.size` | Size of the volume storing the Git repositories | `5Gi`   |
+| 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`             |
+
+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`                           |
+
+### 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)
 
@@ -143,9 +224,9 @@
 |                                            |                                                                                    | `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.logging.persistence.enabled`   | Whether to persist logs                                                            | `true`                                                                    |
-| `gitBackend.logging.persistence.size`      | Storage size for persisted logs                                                    | `1Gi`                                                                     |
 | `gitBackend.tls.secret.create`             | Whether to create a TLS-secret                                                     | `true`                                                                    |
 | `gitBackend.tls.secret.name`               | Name of an external secret that will be used as a TLS-secret                       | `nil`                                                                     |
 | `gitBackend.tls.cert`                      | Public SSL server certificate                                                      | `-----BEGIN CERTIFICATE-----`                                             |
@@ -175,8 +256,6 @@
 |                                     |                                                                  | `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`                    |
 
 ### Gerrit replica
 
@@ -193,43 +272,49 @@
 is mandatory, if access to the Gerrit replica is required!
 ***
 
-| Parameter                                     | Description                                                                                              | Default                           |
-|-----------------------------------------------|----------------------------------------------------------------------------------------------------------|-----------------------------------|
-| `gerritReplica.images.gerritInit`             | Image name of the Gerrit init container image                                                            | `k8s-gerrit/gerrit-init`          |
-| `gerritReplica.images.gerritReplica`          | Image name of the Gerrit replica container image                                                         | `k8s-gerrit/gerrit-replica`       |
-| `gerritReplica.replicas`                      | Number of pod replicas to deploy                                                                         | `1`                               |
-| `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.initializeTestSite.enabled`    | Enable the initialization of a site. USE ONLY for testing, if you do not plan to replicate repositories. | `true`                            |
-| `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.persistence.enabled`           | Whether to persist the Gerrit site                                                                       | `true`                            |
-| `gerritReplica.persistence.size`              | Storage size for persisted Gerrit site                                                                   | `10Gi`                            |
-| `gerritReplica.service.type`                  | Which kind of Service to deploy                                                                          | `NodePort`                        |
-| `gerritReplica.service.http.port`             | Port over which to expose HTTP                                                                           | `80`                              |
-| `gerritReplica.ingress.host`                  | REQUIRED: Host name to use for the Ingress (required for Ingress)                                        | `nil`                             |
-| `gerritReplica.ingress.additionalAnnotations` | Additional annotations for the Ingress                                                                   | `nil`                             |
-| `gerritReplica.ingress.tls.enabled`           | Whether to enable TLS termination in the Ingress                                                         | `false`                           |
-| `gerritReplica.ingress.tls.secret.create`     | Whether to create a TLS-secret                                                                           | `true`                            |
-| `gerritReplica.ingress.tls.secret.name`       | Name of an external secret that will be used as a TLS-secret                                             | `nil`                             |
-| `gerritReplica.ingress.tls.secret.cert`       | Public SSL server certificate                                                                            | `-----BEGIN CERTIFICATE-----`     |
-| `gerritReplica.ingress.tls.secret.key`        | Private SSL server certificate                                                                           | `-----BEGIN RSA PRIVATE KEY-----` |
-| `gerritReplica.keystore`                      | base64-encoded Java keystore (`cat keystore.jks | base64`) to be used by Gerrit, when using SSL          | `nil`                             |
-| `gerritReplica.config.gerrit`                 | The contents of the gerrit.config                                                                        | [see here](#Gerrit-config-files)  |
-| `gerritReplica.config.secure`                 | The contents of the secure.config                                                                        | [see here](#Gerrit-config-files)  |
+| Parameter                                     | Description                                                                                         | Default                                                                         |
+|-----------------------------------------------|-----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
+| `gerritReplica.images.gerritInit`             | Image name of the Gerrit init container image                                                       | `k8s-gerrit/gerrit-init`                                                        |
+| `gerritReplica.images.gerritReplica`          | Image name of the Gerrit replica container image                                                    | `k8s-gerrit/gerrit-replica`                                                     |
+| `gerritReplica.replicas`                      | Number of pod replicas to deploy                                                                    | `1`                                                                             |
+| `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.readinessProbe`                | Configuration of the readiness probe timings                                                        | `{initialDelaySeconds: 10, periodSeconds: 10}`                                  |
+| `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.service.type`                  | Which kind of Service to deploy                                                                     | `NodePort`                                                                      |
+| `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.service.ssh.rsaKey`            | Private SSH key in RSA format                                                                       | `-----BEGIN RSA PRIVATE KEY-----`                                               |
+| `gerritReplica.ingress.host`                  | REQUIRED: Host name to use for the Ingress (required for Ingress)                                   | `nil`                                                                           |
+| `gerritReplica.ingress.additionalAnnotations` | Additional annotations for the Ingress                                                              | `nil`                                                                           |
+| `gerritReplica.ingress.tls.enabled`           | Whether to enable TLS termination in the Ingress                                                    | `false`                                                                         |
+| `gerritReplica.ingress.tls.secret.create`     | Whether to create a TLS-secret                                                                      | `true`                                                                          |
+| `gerritReplica.ingress.tls.secret.name`       | Name of an external secret that will be used as a TLS-secret                                        | `nil`                                                                           |
+| `gerritReplica.ingress.tls.secret.cert`       | Public SSL server certificate                                                                       | `-----BEGIN CERTIFICATE-----`                                                   |
+| `gerritReplica.ingress.tls.secret.key`        | Private SSL server certificate                                                                      | `-----BEGIN RSA PRIVATE KEY-----`                                               |
+| `gerritReplica.keystore`                      | base64-encoded Java keystore (`cat keystore.jks | base64`) to be used by Gerrit, when using SSL     | `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)                         |
 
 ### Gerrit config files
 
-The gerrit-replica chart provides a ConfigMap containing the `gerrit.config` and a
-Secret containing the `secure.config` to configure the Gerrit installation in the
-Gerrit replica component. The content of the `gerrit.config` and `secure.config`
-can be set in the `values.yaml` under the keys `gerritReplica.config.gerrit` and
-`gerritReplica.config.secure` respectively. All configuration options 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 the Gerrit replica to
-work as intended:
+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`
 
@@ -275,6 +360,16 @@
     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.
+
 ## Upgrading the Chart
 
 To upgrade an existing installation of the gerrit-replica chart, e.g. to install
diff --git a/helm-charts/gerrit-replica/templates/NOTES.txt b/helm-charts/gerrit-replica/templates/NOTES.txt
index 8872a88..288a971 100644
--- a/helm-charts/gerrit-replica/templates/NOTES.txt
+++ b/helm-charts/gerrit-replica/templates/NOTES.txt
@@ -5,7 +5,9 @@
 primary Gerrit. Please configure the replication plugin of the primary Gerrit to
 push the repositories to:
 
-{{ if .Values.gitBackend.ingress.enabled -}}
+{{ if .Values.istio.enabled -}}
+  http {{- if .Values.istio.tls.enabled -}} s {{- end -}} :// {{- .Values.istio.host -}} /receiver/git/${name}.git
+{{ else if .Values.gitBackend.ingress.enabled -}}
   http {{- if .Values.gitBackend.ingress.tls.enabled -}} s {{- end -}} :// {{- .Values.gitBackend.ingress.host -}} /git/${name}.git
 {{- else }}
   {{ if .Values.gitBackend.service.https.enabled -}}
@@ -17,7 +19,8 @@
   kubectl get svc git-backend-service
 {{- end }}
 
-Requests to create new repositories have to be directed to the route /new/${name}.git
+Requests to create new repositories have to be directed to the route
+{{ if .Values.istio.enabled -}} /receiver {{- end -}} /new/${name}.git
 over HTTP(S). A detailed guide of how to configure Gerrit's replication plugin
 can be found here:
 
@@ -28,4 +31,8 @@
 The initialization process may take some time. Afterwards the git repositories
 will be available under:
 
-http {{- if .Values.gerritReplica.ingress.tls.enabled -}} s {{- end -}} :// {{- .Values.gerritReplica.ingress.host -}} /<repository-name>.git
+{{ if .Values.istio.enabled -}}
+  http {{- if .Values.istio.tls.enabled -}} s {{- end -}} :// {{- .Values.istio.host -}} /gerrit/<repository-name>.git
+{{- else }}
+  http {{- if .Values.gerritReplica.ingress.tls.enabled -}} s {{- end -}} :// {{- .Values.gerritReplica.ingress.host -}} /<repository-name>.git
+{{- end }}
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.configmap.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.configmap.yaml
index 0397cd9..10962c1 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.configmap.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.configmap.yaml
@@ -8,8 +8,19 @@
     heritage: {{ .Release.Service }}
     release: {{ .Release.Name }}
 data:
-  gerrit.config: |-
-{{ .Values.gerritReplica.config.gerrit | indent 4 }}
+  {{- 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
@@ -22,5 +33,13 @@
     release: {{ .Release.Name }}
 data:
   gerrit-init.yaml: |-
+    pluginCache: {{ .Values.gerritReplica.plugins.cache.enabled }}
+    pluginCacheDir: /var/mnt/plugins
+    {{- if .Values.gerritReplica.plugins.packaged }}
     packagedPlugins:
-      - singleusergroup
+{{ toYaml .Values.gerritReplica.plugins.packaged | indent 6}}
+    {{- end }}
+    {{- if .Values.gerritReplica.plugins.downloaded }}
+    downloadedPlugins:
+{{ toYaml .Values.gerritReplica.plugins.downloaded | indent 6 }}
+    {{- end }}
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml
index 8e8f1a8..163eb47 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.deployment.yaml
@@ -20,6 +20,9 @@
     metadata:
       labels:
         app: gerrit-replica
+        chart: {{ template "gerrit-replica.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
       annotations:
         chartRevision: "{{ .Release.Revision }}"
     spec:
@@ -30,6 +33,28 @@
       - name: {{ .Values.images.registry.ImagePullSecret.name }}
       {{- end }}
       initContainers:
+      {{- if .Values.nfsWorkaround.enabled }}
+      - name: nfs-init
+        image: busybox
+        command:
+        - sh
+        - -c
+        args:
+        - |
+          chown -R 1000:100 /var/mnt/logs
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+      {{- end }}
       - name: site-cleanup
         image: busybox
         securityContext:
@@ -43,11 +68,11 @@
           # Remove directories that should be mounted rather than exist with the
           # rest of the site
           [ ! -L /var/gerrit/git ] && rm -rf /var/gerrit/git
+          [ ! -L /var/gerrit/logs ] && rm -rf /var/gerrit/logs
           rm -f /var/gerrit/logs/gerrit.pid
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
-      {{ if not .Values.gerritReplica.initializeTestSite.enabled -}}
       # Initialize the volume containing the whole Gerrit-site with defaults
       # Not needed, when running in test mode, since then the configured site will
       # be initialized
@@ -63,15 +88,18 @@
             -c /var/config/gerrit-init.yaml \
             -s /var/gerrit
 
-          # The git repositories will be mounted from a volume
+          # The git repositories and logs will be mounted from a volume
           [ -L /var/gerrit/git ] || rm -rf /var/gerrit/git
+          [ -L /var/gerrit/logs ] || rm -rf /var/gerrit/logs
+          {{ if .Values.gerritReplica.service.ssh.enabled -}}
+          rm -f /var/gerrit/etc/ssh_host*key*
+          {{- end }}
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
         - name: gerrit-init-config
           mountPath: "/var/config/gerrit-init.yaml"
           subPath: gerrit-init.yaml
-      {{- end }}
       # If configured, run initialization taking the given Gerrit configuration
       # and persisted volumes into account.
       - name: gerrit-init
@@ -83,11 +111,9 @@
         args:
         - |
           symlink_config_to_site(){
-            {{ if .Values.gerritReplica.keystore -}}
-            ln -s /var/config/keystore /var/gerrit/etc/keystore
-            {{- end }}
-            ln -sf /var/config/gerrit.config /var/gerrit/etc/gerrit.config
-            ln -sf /var/config/secure.config /var/gerrit/etc/secure.config
+            for file in /var/mnt/etc/config/* /var/mnt/etc/secret/*; do
+              ln -sf $file /var/gerrit/etc/$(basename $file)
+            done
           }
 
           mkdir -p /var/gerrit/etc
@@ -97,69 +123,159 @@
             ln -sf /var/mnt/git /var/gerrit/
           fi
 
-          {{ if .Values.gerritReplica.initializeTestSite.enabled -}}
-          /var/tools/gerrit_init.py \
-            -c /var/config/gerrit-init.yaml \
-            -s /var/gerrit
-
-          symlink_config_to_site
-          {{- end }}
+          if [ ! -d /var/gerrit/logs ]; then
+            ln -sf /var/mnt/logs /var/gerrit/
+          fi
 
           /var/tools/validate_notedb.py -s /var/gerrit
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
-        - name: git-filesystem
+        - name: git-repositories
           mountPath: "/var/mnt/git"
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        {{- if .Values.nfsWorkaround.enabled }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
         - name: gerrit-init-config
           mountPath: "/var/config/gerrit-init.yaml"
           subPath: gerrit-init.yaml
-        - name: gerrit-config
-          mountPath: "/var/config/gerrit.config"
-          subPath: gerrit.config
-        - name: gerrit-replica-secure-config
-          mountPath: "/var/config/secure.config"
-          subPath: secure.config
-        {{ if .Values.gerritReplica.keystore -}}
-        - name: gerrit-replica-secure-config
-          mountPath: "/var/config/keystore"
-          subPath: keystore
+        {{- if and .Values.gerritReplica.plugins.cache.enabled .Values.gerritReplica.plugins.downloaded }}
+        - 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"
       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
         ports:
-        - containerPort: 8080
+        - name: http
+          containerPort: 8080
+        {{ if .Values.gerritReplica.service.ssh -}}
+        - name: ssh
+          containerPort: 29418
+        {{- end }}
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
-        - name: git-filesystem
+        - name: git-repositories
           mountPath: "/var/mnt/git"
-        - name: gerrit-config
-          mountPath: "/var/config/gerrit.config"
-          subPath: gerrit.config
-        - name: gerrit-replica-secure-config
-          mountPath: "/var/config/secure.config"
-          subPath: secure.config
-        {{ if .Values.gerritReplica.keystore -}}
-        - name: gerrit-replica-secure-config
-          mountPath: "/var/config/keystore"
-          subPath: keystore
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        {{- if .Values.nfsWorkaround.enabled }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
         {{- end }}
+        {{- if and .Values.gerritReplica.plugins.cache.enabled .Values.gerritReplica.plugins.downloaded }}
+        - 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"
+        livenessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: http
+{{ toYaml .Values.gerritReplica.livenessProbe | indent 10 }}
+        readinessProbe:
+          httpGet:
+            path: /config/server/healthcheck~status
+            port: http
+{{ toYaml .Values.gerritReplica.readinessProbe | indent 10 }}
         resources:
 {{ toYaml .Values.gerritReplica.resources | indent 10 }}
+      {{ 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
+        - name: promtail-secret
+          mountPath: /etc/promtail/promtail.ca.crt
+          subPath: promtail.ca.crt
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/gerrit/logs"
+        {{- if .Values.nfsWorkaround.enabled }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
+      {{- end }}
       volumes:
       - name: gerrit-site
-        {{ if .Values.gerritReplica.persistence.enabled -}}
+        emptyDir: {}
+      - name: git-repositories
         persistentVolumeClaim:
-          claimName: {{ .Release.Name }}-gerrit-replica-pvc
+          {{- 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: git-filesystem
+      {{- if and .Values.gerritReplica.plugins.cache.enabled .Values.gerritReplica.plugins.downloaded }}
+      - name: gerrit-plugin-cache
         persistentVolumeClaim:
-          claimName: {{ .Release.Name }}-git-filesystem-pvc
+          claimName: {{ .Release.Name }}-plugin-cache-pvc
+      {{- end }}
+      {{- if .Values.nfsWorkaround.enabled }}
+      - name: nfs-config
+        configMap:
+          name: {{ .Release.Name }}-nfs-configmap
+      {{- end }}
       - name: gerrit-init-config
         configMap:
           name: {{ .Release.Name }}-gerrit-init-configmap
@@ -169,3 +285,16 @@
       - name: gerrit-replica-secure-config
         secret:
           secretName: {{ .Release.Name }}-gerrit-replica-secure-config
+      {{ if .Values.gerritReplica.service.ssh.enabled -}}
+      - name: gerrit-replica-ssh
+        secret:
+          secretName: {{ .Release.Name }}-gerrit-replica-ssh-secret
+      {{- 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 }}
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.ingress.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.ingress.yaml
index 61331dc..161a0df 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.ingress.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.ingress.yaml
@@ -1,3 +1,4 @@
+{{ if and .Values.gerritReplica.ingress.enabled (not .Values.istio.enabled) -}}
 apiVersion: extensions/v1beta1
 kind: Ingress
 metadata:
@@ -29,3 +30,4 @@
       - backend:
           serviceName: {{ .Release.Name }}-gerrit-replica-service
           servicePort: {{ .Values.gerritReplica.service.http.port }}
+{{- end }}
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.secrets.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.secrets.yaml
index 2ac0586..85ae449 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.secrets.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.secrets.yaml
@@ -11,10 +11,15 @@
   {{ if .Values.gerritReplica.keystore -}}
   keystore: {{ .Values.gerritReplica.keystore }}
   {{- end }}
-  secure.config: {{ .Values.gerritReplica.config.secure | b64enc }}
+  {{ if .Values.gerritReplica.service.ssh.enabled -}}
+  ssh_host_rsa_key: {{ .Values.gerritReplica.service.ssh.rsaKey | b64enc }}
+  {{- end }}
+  {{- range $key, $value := .Values.gerritReplica.etc.secret }}
+  {{ $key }}: {{ $value | b64enc }}
+  {{- end }}
 type: Opaque
 ---
-{{ if and .Values.gerritReplica.ingress.tls.enabled .Values.gerritReplica.ingress.tls.secret.create -}}
+{{ if and (and .Values.gerritReplica.ingress.tls.enabled .Values.gerritReplica.ingress.tls.secret.create) (not .Values.istio.enabled) -}}
 apiVersion: v1
 kind: Secret
 metadata:
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.service.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.service.yaml
index 8798667..dc6460c 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.service.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.service.yaml
@@ -13,6 +13,11 @@
   - name: http
     port: {{ .http.port }}
     targetPort: 8080
+  {{ if .ssh.enabled -}}
+  - name: ssh
+    port: {{ .ssh.port }}
+    targetPort: 29418
+  {{- end }}
   selector:
     app: gerrit-replica
   type: {{ .type }}
diff --git a/helm-charts/gerrit-replica/templates/gerrit-replica.storage.yaml b/helm-charts/gerrit-replica/templates/gerrit-replica.storage.yaml
index 50fc503..d6ed00c 100644
--- a/helm-charts/gerrit-replica/templates/gerrit-replica.storage.yaml
+++ b/helm-charts/gerrit-replica/templates/gerrit-replica.storage.yaml
@@ -1,8 +1,8 @@
-{{ if .Values.gerritReplica.persistence.enabled -}}
+{{- if and .Values.gerritReplica.plugins.cache.enabled .Values.gerritReplica.plugins.downloaded }}
 kind: PersistentVolumeClaim
 apiVersion: v1
 metadata:
-  name: {{ .Release.Name }}-gerrit-replica-pvc
+  name: {{ .Release.Name }}-plugin-cache-pvc
   labels:
     app: gerrit-replica
     chart: {{ template "gerrit-replica.chart" . }}
@@ -10,9 +10,9 @@
     release: {{ .Release.Name }}
 spec:
   accessModes:
-  - ReadWriteOnce
+  - ReadWriteMany
   resources:
     requests:
-      storage: {{ .Values.gerritReplica.persistence.size }}
-  storageClassName: {{ .Values.storageClasses.default.name }}
+      storage: {{ .Values.gerritReplica.plugins.cache.size }}
+  storageClassName: {{ .Values.storageClasses.shared.name }}
 {{- end }}
diff --git a/helm-charts/gerrit-replica/templates/git-backend.deployment.yaml b/helm-charts/gerrit-replica/templates/git-backend.deployment.yaml
index 9d3e323..78906a4 100644
--- a/helm-charts/gerrit-replica/templates/git-backend.deployment.yaml
+++ b/helm-charts/gerrit-replica/templates/git-backend.deployment.yaml
@@ -20,6 +20,9 @@
     metadata:
       labels:
         app: git-backend
+        chart: {{ template "gerrit-replica.chart" . }}
+        heritage: {{ .Release.Service }}
+        release: {{ .Release.Name }}
       annotations:
         chartRevision: "{{ .Release.Revision }}"
     spec:
@@ -29,6 +32,29 @@
       imagePullSecrets:
       - name: {{ .Values.images.registry.ImagePullSecret.name }}
       {{- end }}
+      initContainers:
+      {{- if .Values.nfsWorkaround.enabled }}
+      - name: nfs-init
+        image: busybox
+        command:
+        - sh
+        - -c
+        args:
+        - |
+          chown -R 1000:100 /var/mnt/logs
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        volumeMounts:
+        - name: logs
+          subPathExpr: "gerrit-replica/$(POD_NAME)"
+          mountPath: "/var/mnt/logs"
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+      {{- end }}
       containers:
       - name: apache-git-http-backend
         imagePullPolicy: {{ .Values.images.imagePullPolicy }}
@@ -42,14 +68,50 @@
         - name: DISABLE_HTTP
           value: "true"
         {{- end }}
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
         ports:
-        - containerPort: 80
-        - containerPort: 443
+        {{ if eq .Values.gitBackend.service.http.enabled true -}}
+        - name: http-port
+          containerPort: 80
+        {{- end }}
+        {{ if eq .Values.gitBackend.service.https.enabled true -}}
+        - name: https-port
+          containerPort: 443
+        {{- end }}
         resources:
 {{ toYaml .Values.gitBackend.resources | indent 10 }}
+        livenessProbe:
+          httpGet:
+            path: /
+            {{ if eq .Values.gitBackend.service.http.enabled true -}}
+            port: http-port
+            {{- else }}
+            port: https-port
+            {{- end }}
+{{ toYaml .Values.gitBackend.livenessProbe | indent 10 }}
+        readinessProbe:
+          httpGet:
+            path: /
+            {{ if eq .Values.gitBackend.service.http.enabled true -}}
+            port: http-port
+            {{- else }}
+            port: https-port
+            {{- end }}
+{{ toYaml .Values.gitBackend.readinessProbe | indent 10 }}
         volumeMounts:
-        - name: git-filesystem
+        - name: git-repositories
           mountPath: "/var/gerrit/git"
+        - name: logs
+          subPathExpr: "apache-git-http-backend/$(POD_NAME)"
+          mountPath: "/var/log/apache2"
+        {{- if .Values.nfsWorkaround.enabled }}
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+        {{- end }}
         - name: git-backend-secret
           readOnly: true
           subPath: .htpasswd
@@ -64,12 +126,14 @@
           subPath: tls.crt
           mountPath: "/var/apache/credentials/server.crt"
         {{ end }}
-        - name: apache-logs
-          mountPath: "/var/log/apache2"
       volumes:
-      - name: git-filesystem
+      - name: git-repositories
         persistentVolumeClaim:
-          claimName: {{ .Release.Name }}-git-filesystem-pvc
+          {{- 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
@@ -82,10 +146,19 @@
           secretName: {{ .Values.gitBackend.tls.secret.name }}
           {{- end }}
       {{ end }}
-      - name: apache-logs
-        {{ if .Values.gitBackend.logging.persistence.enabled -}}
+      - name: logs
+        {{ if .Values.logStorage.enabled -}}
         persistentVolumeClaim:
-          claimName: {{ .Release.Name }}-apache-logs-pvc
+          {{- if .Values.logStorage.externalPVC.use }}
+          claimName: {{ .Values.logStorage.externalPVC.name }}
+          {{- else }}
+          claimName: {{ .Release.Name }}-log-pvc
+          {{- end }}
         {{ else -}}
         emptyDir: {}
         {{- end }}
+      {{- if .Values.nfsWorkaround.enabled }}
+      - name: nfs-config
+        configMap:
+          name: {{ .Release.Name }}-nfs-configmap
+      {{- end }}
diff --git a/helm-charts/gerrit-replica/templates/git-backend.ingress.yaml b/helm-charts/gerrit-replica/templates/git-backend.ingress.yaml
index 6c98102..87d64bd 100644
--- a/helm-charts/gerrit-replica/templates/git-backend.ingress.yaml
+++ b/helm-charts/gerrit-replica/templates/git-backend.ingress.yaml
@@ -1,4 +1,4 @@
-{{ if .Values.gitBackend.ingress.enabled -}}
+{{ if and .Values.gitBackend.ingress.enabled (not .Values.istio.enabled) -}}
 apiVersion: extensions/v1beta1
 kind: Ingress
 metadata:
diff --git a/helm-charts/gerrit-replica/templates/git-backend.secrets.yaml b/helm-charts/gerrit-replica/templates/git-backend.secrets.yaml
index cac30f7..370a902 100644
--- a/helm-charts/gerrit-replica/templates/git-backend.secrets.yaml
+++ b/helm-charts/gerrit-replica/templates/git-backend.secrets.yaml
@@ -11,7 +11,7 @@
   .htpasswd: {{ required "A .htpasswd-file is required for the git backend." .Values.gitBackend.credentials.htpasswd | b64enc }}
 type: Opaque
 ---
-{{ if and .Values.gitBackend.tls.secret.create (or .Values.gitBackend.ingress.tls.enabled .Values.gitBackend.service.https.enabled) -}}
+{{ if and (and .Values.gitBackend.tls.secret.create (or .Values.gitBackend.ingress.tls.enabled .Values.gitBackend.service.https.enabled)) (not .Values.istio.enabled) -}}
 apiVersion: v1
 kind: Secret
 metadata:
diff --git a/helm-charts/gerrit-replica/templates/git-backend.storage.yaml b/helm-charts/gerrit-replica/templates/git-backend.storage.yaml
deleted file mode 100644
index 99848ee..0000000
--- a/helm-charts/gerrit-replica/templates/git-backend.storage.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-{{ if .Values.gitBackend.logging.persistence.enabled -}}
-kind: PersistentVolumeClaim
-apiVersion: v1
-metadata:
-  name: {{ .Release.Name }}-apache-logs-pvc
-  labels:
-    app: git-backend
-    chart: {{ template "gerrit-replica.chart" . }}
-    heritage: {{ .Release.Service }}
-    release: {{ .Release.Name }}
-spec:
-  accessModes:
-  - ReadWriteOnce
-  resources:
-    requests:
-      storage: {{ .Values.gitBackend.logging.persistence.size }}
-  storageClassName: {{ .Values.storageClasses.default.name }}
-{{- end }}
diff --git a/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml b/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml
index c608f6c..3cf609b 100644
--- a/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml
+++ b/helm-charts/gerrit-replica/templates/git-gc.cronjob.yaml
@@ -13,34 +13,85 @@
   jobTemplate:
     spec:
       template:
+        {{ if .Values.istio.enabled -}}
+        metadata:
+          annotations:
+            sidecar.istio.io/inject: "false"
+        {{- end }}
         spec:
           restartPolicy: OnFailure
           securityContext:
-            runAsUser: 1000
             fsGroup: 100
           {{ if .Values.images.registry.ImagePullSecret.name -}}
           imagePullSecrets:
           - name: {{ .Values.images.registry.ImagePullSecret.name }}
           {{- end }}
+          initContainers:
+          {{- if .Values.nfsWorkaround.enabled }}
+          - name: nfs-init
+            image: busybox
+            command:
+            - sh
+            - -c
+            args:
+            - |
+              chown -R 1000:100 /var/mnt/logs
+            env:
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            volumeMounts:
+            - name: logs
+              subPathExpr: "git-gc/$(POD_NAME)"
+              mountPath: "/var/mnt/logs"
+            - name: nfs-config
+              mountPath: "/etc/idmapd.conf"
+              subPath: idmapd.conf
+          {{- 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-filesystem
+            - name: git-repositories
               mountPath: "/var/gerrit/git"
-            - name: git-gc-logs
+            - name: logs
+              subPathExpr: "git-gc/$(POD_NAME)"
               mountPath: "/var/log/git"
+            {{- if .Values.nfsWorkaround.enabled }}
+            - name: nfs-config
+              mountPath: "/etc/idmapd.conf"
+              subPath: idmapd.conf
+            {{- end }}
           volumes:
-          - name: git-filesystem
+          - name: git-repositories
             persistentVolumeClaim:
-              claimName: {{ .Release.Name }}-git-filesystem-pvc
-          - name: git-gc-logs
-            {{ if .Values.gitGC.logging.persistence.enabled -}}
+              {{- 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:
-              claimName: {{ .Release.Name }}-git-gc-logs-pvc
+              {{- if .Values.logStorage.externalPVC.use }}
+              claimName: {{ .Values.logStorage.externalPVC.name }}
+              {{- else }}
+              claimName: {{ .Release.Name }}-log-pvc
+              {{- end }}
             {{ else -}}
             emptyDir: {}
             {{- end }}
+          {{- if .Values.nfsWorkaround.enabled }}
+          - name: nfs-config
+            configMap:
+              name: {{ .Release.Name }}-nfs-configmap
+          {{- end }}
diff --git a/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml b/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml
new file mode 100644
index 0000000..9478b18
--- /dev/null
+++ b/helm-charts/gerrit-replica/templates/git-repositories-init.job.yaml
@@ -0,0 +1,116 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ .Release.Name }}-git-repositories-init
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  template:
+    {{ if .Values.istio.enabled -}}
+    metadata:
+      annotations:
+        sidecar.istio.io/inject: "false"
+    {{- end }}
+    spec:
+      securityContext:
+        fsGroup: 100
+      {{ if .Values.images.registry.ImagePullSecret.name -}}
+      imagePullSecrets:
+      - name: {{ .Values.images.registry.ImagePullSecret.name }}
+      {{- end }}
+      {{- if .Values.nfsWorkaround.enabled }}
+      initContainers:
+      - name: nfs-init
+        image: busybox
+        command:
+        - sh
+        - -c
+        args:
+        - |
+          chown -R 1000:100 /var/mnt
+        volumeMounts:
+        - name: git-repositories
+          mountPath: "/var/mnt/git"
+        - name: logs
+          mountPath: "/var/mnt/logs"
+        - name: nfs-config
+          mountPath: "/etc/idmapd.conf"
+          subPath: idmapd.conf
+      {{- end }}
+      containers:
+      - name: create-repositories
+        image: {{ template "registry" . }}{{ .Values.gerritReplica.images.gerritInit }}:{{ .Values.images.version }}
+        imagePullPolicy: {{ .Values.images.imagePullPolicy }}
+        command:
+        - /bin/ash
+        - -ce
+        args:
+        - |
+          if test -d /var/mnt/git/All-Projects.git && \
+              test -d /var/mnt/git/All-Users.git; then
+            echo "Repositories already exist. Won't perform initial creation."
+            exit 0
+          fi
+
+          mkdir -p /var/gerrit/etc
+          ln -sf /var/config/gerrit.config /var/gerrit/etc/gerrit.config
+          ln -sf /var/mnt/git /var/gerrit/
+
+          /var/tools/gerrit_init.py \
+            -c /var/config/gerrit-init.yaml \
+            -s /var/gerrit
+        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/gerrit/logs"
+        - name: gerrit-init-config
+          mountPath: "/var/config/gerrit-init.yaml"
+          subPath: gerrit-init.yaml
+        - name: gerrit-config
+          mountPath: "/var/config/gerrit.config"
+          subPath: gerrit.config
+      volumes:
+      - name: gerrit-site
+        emptyDir: {}
+      - 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
+      {{- if .Values.nfsWorkaround.enabled }}
+      - name: nfs-config
+        configMap:
+          name: {{ .Release.Name }}-nfs-configmap
+      {{- end }}
+      restartPolicy: Never
diff --git a/helm-charts/gerrit-replica/templates/git-repositories.storage.yaml b/helm-charts/gerrit-replica/templates/git-repositories.storage.yaml
deleted file mode 100644
index bb786b2..0000000
--- a/helm-charts/gerrit-replica/templates/git-repositories.storage.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-kind: PersistentVolumeClaim
-apiVersion: v1
-metadata:
-  name: {{ .Release.Name }}-git-filesystem-pvc
-spec:
-  accessModes:
-  - ReadWriteMany
-  resources:
-    requests:
-      storage: {{ .Values.gitRepositoryStorage.size }}
-  storageClassName: {{ .Values.storageClasses.shared.name }}
diff --git a/helm-charts/gerrit-replica/templates/istio.ingressgateway.yaml b/helm-charts/gerrit-replica/templates/istio.ingressgateway.yaml
new file mode 100644
index 0000000..1b8a631
--- /dev/null
+++ b/helm-charts/gerrit-replica/templates/istio.ingressgateway.yaml
@@ -0,0 +1,128 @@
+{{ 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: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+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: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+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: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  hosts:
+  - {{ .Values.istio.host }}
+  gateways:
+  - {{ .Release.Name }}-istio-gateway
+  http:
+  - match:
+    - uri:
+        prefix: /receiver/
+    rewrite:
+      uri: /
+    route:
+    - destination:
+        host: {{ .Release.Name }}-git-backend-service.{{ .Release.Namespace }}.svc.cluster.local
+        port:
+          number: 80
+  - match:
+    - uri:
+        prefix: /gerrit/
+    - uri:
+        prefix: /gerrit
+    rewrite:
+      uri: /
+    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: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  host: {{ .Release.Name }}-gerrit-replica-service.{{ .Release.Namespace }}.svc.cluster.local
+  trafficPolicy:
+    loadBalancer:
+      simple: LEAST_CONN
+{{- end }}
diff --git a/helm-charts/gerrit-replica/templates/nfs.configmap.yaml b/helm-charts/gerrit-replica/templates/nfs.configmap.yaml
new file mode 100644
index 0000000..238bcbc
--- /dev/null
+++ b/helm-charts/gerrit-replica/templates/nfs.configmap.yaml
@@ -0,0 +1,24 @@
+{{- if .Values.nfsWorkaround.enabled -}}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-nfs-configmap
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+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/helm-charts/gerrit-replica/templates/promtail.configmap.yaml b/helm-charts/gerrit-replica/templates/promtail.configmap.yaml
new file mode 100644
index 0000000..4ccd869
--- /dev/null
+++ b/helm-charts/gerrit-replica/templates/promtail.configmap.yaml
@@ -0,0 +1,91 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-promtail-gerrit-configmap
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+data:
+  promtail.yaml: |-
+    positions:
+      filename: /var/gerrit/logs/promtail-positions.yaml
+
+    clients:
+      - url: {{ .Values.promtailSidecar.loki.url }}/loki/api/v1/push
+        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/helm-charts/gerrit-replica/templates/promtail.secret.yaml b/helm-charts/gerrit-replica/templates/promtail.secret.yaml
new file mode 100644
index 0000000..ae05c2a
--- /dev/null
+++ b/helm-charts/gerrit-replica/templates/promtail.secret.yaml
@@ -0,0 +1,17 @@
+{{ if .Values.promtailSidecar.enabled -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name:  {{ .Release.Name }}-promtail-secret
+  labels:
+    app: gerrit-replica
+    chart: {{ template "gerrit-replica.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+type: Opaque
+data:
+  promtail.secret: {{ .Values.promtailSidecar.loki.password | b64enc }}
+  {{- if not .Values.promtailSidecar.tls.skipVerify }}
+  promtail.ca.crt: {{ .Values.promtailSidecar.tls.caCert | b64enc }}
+  {{- end }}
+{{- end }}
diff --git a/helm-charts/gerrit-replica/templates/storage.pvc.yaml b/helm-charts/gerrit-replica/templates/storage.pvc.yaml
new file mode 100644
index 0000000..5f8974e
--- /dev/null
+++ b/helm-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/helm-charts/gerrit-replica/values.yaml b/helm-charts/gerrit-replica/values.yaml
index 5564ceb..d2df1e0 100644
--- a/helm-charts/gerrit-replica/values.yaml
+++ b/helm-charts/gerrit-replica/values.yaml
@@ -41,11 +41,76 @@
     parameters:
       mountOptions: vers=4.1
 
+nfsWorkaround:
+  enabled: false
+  idDomain: localdomain.com
+
 
 gitRepositoryStorage:
+  externalPVC:
+    use: false
+    name: git-repositories-pvc
   size: 5Gi
 
 
+logStorage:
+  enabled: false
+  externalPVC:
+    use: false
+    name: gerrit-logs-pvc
+  size: 5Gi
+
+
+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
+
+
+promtailSidecar:
+  enabled: false
+  image: grafana/promtail
+  version: 1.3.0
+  resources:
+    requests:
+      cpu: 100m
+      memory: 128Mi
+    limits:
+      cpu: 200m
+      memory: 128Mi
+  tls:
+    skipVerify: true
+    caCert: |-
+      -----BEGIN CERTIFICATE-----
+
+      -----END CERTIFICATE-----
+  loki:
+    url: loki.example.com
+    user: admin
+    password: secret
+
+
 gitBackend:
   image: k8sgerrit/apache-git-http-backend
 
@@ -63,10 +128,13 @@
       cpu: 100m
       memory: 256Mi
 
-  logging:
-    persistence:
-      enabled: true
-      size: 1Gi
+  livenessProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 5
+
+  readinessProbe:
+    initialDelaySeconds: 5
+    periodSeconds: 1
 
   tls:
     secret:
@@ -133,11 +201,6 @@
       cpu: 100m
       memory: 256Mi
 
-  logging:
-    persistence:
-      enabled: true
-      size: 1Gi
-
 
 gerritReplica:
   images:
@@ -150,11 +213,13 @@
   # work.
   maxUnavailable: 100%
 
-  # If you only intend to test the Gerrit replica and do not wish to actually
-  # replicate repositories, activate this option to initialize a new site,
-  # including a notedb.
-  initializeTestSite:
-    enabled: true
+  livenessProbe:
+    initialDelaySeconds: 60
+    periodSeconds: 5
+
+  readinessProbe:
+    initialDelaySeconds: 10
+    periodSeconds: 10
 
   # The memory limit has to be higher than the configures heap-size for Java!
   resources:
@@ -165,14 +230,17 @@
       cpu: 1
       memory: 6Gi
 
-  persistence:
-    enabled: true
-    size: 10Gi
-
   service:
     type: NodePort
     http:
       port: 80
+    ssh:
+      enabled: false
+      port: 29418
+      rsaKey: |-
+        -----BEGIN RSA PRIVATE KEY-----
+
+        -----END RSA PRIVATE KEY-----
 
   ingress:
     host:
@@ -203,50 +271,67 @@
   # automatic encoding using helm does not work here.
   keystore:
 
-  config:
+  plugins:
+    packaged:
+    - singleusergroup
+    downloaded:
+    # - name: delete-project
+    #   url: https://example.com/gerrit-plugins/delete-project.jar
+    #   sha1:
+
+    # Only downloaded plugins will be cached. This will be ignored, if no plugins
+    # are downloaded.
+    cache:
+      enabled: false
+      size: 1Gi
+
+  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!
-    gerrit: |-
-      [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
-      [auth]
-        type = DEVELOPMENT_BECOME_ANY_ACCOUNT
-      [httpd]
-        # If using an ingress use proxy-http or proxy-https
-        listenUrl = proxy-http://*:8080/
-      [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
-        replica = true # FIXED
-        javaHome = /usr/lib/jvm/java-1.8-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
+    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
+        [auth]
+          type = DEVELOPMENT_BECOME_ANY_ACCOUNT
+        [httpd]
+          # If using an ingress use proxy-http or proxy-https
+          listenUrl = proxy-http://*:8080/
+          requestLog = true
+        [sshd]
+          listenAddress = *:29418
+        [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-1.8-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
 
-    secure: |-
-      # Password for the keystore added as value for 'gerritReplica.keystore'
-      # Only needed, if SSL is enabled.
-      #[httpd]
-      #  sslKeyPassword = gerrit
+    secret:
+      secure.config: |-
+        # Password for the keystore added as value for 'gerritReplica.keystore'
+        # Only needed, if SSL is enabled.
+        #[httpd]
+        #  sslKeyPassword = gerrit
diff --git a/helm-charts/gerrit/README.md b/helm-charts/gerrit/README.md
index f843f1b..0cb0264 100644
--- a/helm-charts/gerrit/README.md
+++ b/helm-charts/gerrit/README.md
@@ -106,11 +106,11 @@
 
 ### 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-filesystem-pvc` |
-| `gitRepositoryStorage.size`             | Size of the volume storing the Git repositories | `5Gi`                |
+| 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,
@@ -146,47 +146,51 @@
 is mandatory, if access to Gerrit is required!
 ***
 
-| Parameter                              | Description                                                                                     | Default                                                                                  |
-|----------------------------------------|-------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
-| `gerrit.images.gerritInit`             | Image name of the Gerrit init container image                                                   | `k8s-gerrit/gerrit-init`                                                                 |
-| `gerrit.images.gerrit`                 | Image name of the Gerrit container image                                                        | `k8s-gerrit/gerrit`                                                                      |
-| `gerrit.replicas`                      | Number of replica pods to deploy                                                                | `1`                                                                                      |
-| `gerrit.updatePartition`               | Number of pods to update simultaneously                                                         | `1`                                                                                      |
-| `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.service.type`                  | Which kind of Service to deploy                                                                 | `NodePort`                                                                               |
-| `gerrit.service.http.port`             | Port over which to expose HTTP                                                                  | `80`                                                                                     |
-| `gerrit.ingress.host`                  | REQUIRED: Host name to use for the Ingress (required for Ingress)                               | `nil`                                                                                    |
-| `gerrit.ingress.additionalAnnotations` | Additional annotations for the Ingress                                                          | `nil`                                                                                    |
-| `gerrit.ingress.tls.enabled`           | Whether to enable TLS termination in the Ingress                                                | `false`                                                                                  |
-| `gerrit.ingress.tls.secret.create`     | Whether to create a TLS-secret                                                                  | `true`                                                                                   |
-| `gerrit.ingress.tls.secret.name`       | Name of an external secret that will be used as a TLS-secret                                    | `nil`                                                                                    |
-| `gerrit.ingress.tls.secret.cert`       | Public SSL server certificate                                                                   | `-----BEGIN CERTIFICATE-----`                                                            |
-| `gerrit.ingress.tls.secret.key`        | Private SSL server certificate                                                                  | `-----BEGIN RSA PRIVATE KEY-----`                                                        |
-| `gerrit.keystore`                      | base64-encoded Java keystore (`cat keystore.jks | base64`) to be used by Gerrit, when using SSL | `nil`                                                                                    |
-| `gerrit.plugins.packaged`              | List of Gerrit plugins that are packaged into the Gerrit-war-file to install                    | `["commit-message-length-validator", "download-commands", "replication", "reviewnotes"]` |
-| `gerrit.plugins.downloaded`            | List of Gerrit plugins that will be downloaded                                                  | `nil`                                                                                    |
-| `gerrit.plugins.downloaded[0].name`    | Name of plugin                                                                                  | `nil`                                                                                    |
-| `gerrit.plugins.downloaded[0].url`     | Download url of plugin                                                                          | `nil`                                                                                    |
-| `gerrit.plugins.downloaded[0].sha1`    | SHA1 sum of plugin jar used to ensure file integrity and version (optional)                     | `nil`                                                                                    |
-| `gerrit.plugins.cache.enabled`         | Whether to cache downloaded plugins                                                             | `false`                                                                                  |
-| `gerrit.plugins.cache.size`            | Size of the volume used to store cached plugins                                                 | `1Gi`                                                                                    |
-| `gerrit.config.gerrit`                 | The contents of the gerrit.config                                                               | [see here](#Gerrit-config-files)                                                         |
-| `gerrit.config.secure`                 | The contents of the secure.config                                                               | [see here](#Gerrit-config-files)                                                         |
-| `gerrit.config.replication`            | The contents of the replication.config                                                          | [see here](#Gerrit-config-files)                                                         |
+| Parameter                              | Description                                                                                         | Default                                                                                  |
+|----------------------------------------|-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
+| `gerrit.images.gerritInit`             | Image name of the Gerrit init container image                                                       | `k8s-gerrit/gerrit-init`                                                                 |
+| `gerrit.images.gerrit`                 | Image name of the Gerrit container image                                                            | `k8s-gerrit/gerrit`                                                                      |
+| `gerrit.replicas`                      | Number of replica pods to deploy                                                                    | `1`                                                                                      |
+| `gerrit.updatePartition`               | Number of pods to update simultaneously                                                             | `1`                                                                                      |
+| `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.livenessProbe`                 | Configuration of the liveness probe timings                                                         | `{initialDelaySeconds: 30, periodSeconds: 5}`                                            |
+| `gerrit.readinessProbe`                | Configuration of the readiness probe timings                                                        | `{initialDelaySeconds: 5, periodSeconds: 1}`                                             |
+| `gerrit.service.type`                  | Which kind of Service to deploy                                                                     | `NodePort`                                                                               |
+| `gerrit.service.http.port`             | Port over which to expose HTTP                                                                      | `80`                                                                                     |
+| `gerrit.ingress.host`                  | REQUIRED: Host name to use for the Ingress (required for Ingress)                                   | `nil`                                                                                    |
+| `gerrit.ingress.additionalAnnotations` | Additional annotations for the Ingress                                                              | `nil`                                                                                    |
+| `gerrit.ingress.tls.enabled`           | Whether to enable TLS termination in the Ingress                                                    | `false`                                                                                  |
+| `gerrit.ingress.tls.secret.create`     | Whether to create a TLS-secret                                                                      | `true`                                                                                   |
+| `gerrit.ingress.tls.secret.name`       | Name of an external secret that will be used as a TLS-secret                                        | `nil`                                                                                    |
+| `gerrit.ingress.tls.secret.cert`       | Public SSL server certificate                                                                       | `-----BEGIN CERTIFICATE-----`                                                            |
+| `gerrit.ingress.tls.secret.key`        | Private SSL server certificate                                                                      | `-----BEGIN RSA PRIVATE KEY-----`                                                        |
+| `gerrit.keystore`                      | base64-encoded Java keystore (`cat keystore.jks | base64`) to be used by Gerrit, when using SSL     | `nil`                                                                                    |
+| `gerrit.plugins.packaged`              | List of Gerrit plugins that are packaged into the Gerrit-war-file to install                        | `["commit-message-length-validator", "download-commands", "replication", "reviewnotes"]` |
+| `gerrit.plugins.downloaded`            | List of Gerrit plugins that will be downloaded                                                      | `nil`                                                                                    |
+| `gerrit.plugins.downloaded[0].name`    | Name of plugin                                                                                      | `nil`                                                                                    |
+| `gerrit.plugins.downloaded[0].url`     | Download url of plugin                                                                              | `nil`                                                                                    |
+| `gerrit.plugins.downloaded[0].sha1`    | SHA1 sum of plugin jar used to ensure file integrity and version (optional)                         | `nil`                                                                                    |
+| `gerrit.plugins.cache.enabled`         | Whether to cache downloaded plugins                                                                 | `false`                                                                                  |
+| `gerrit.plugins.cache.size`            | Size of the volume used to store cached plugins                                                     | `1Gi`                                                                                    |
+| `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 config files
 
-The gerrit chart provides a ConfigMap containing the `gerrit.config` as well
-as `replication.config` and a Secret containing 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.config.gerrit`,
-`gerrit.config.replication` and `gerrit.config.secure` respectively.
-All configuration options are described in detail in the
+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:
@@ -230,6 +234,14 @@
     memory resource limit set for the container (e.g. `-Xmx4g`). In your calculation,
     allow memory for other components running in the container.
 
+To enable liveness- and readiness probes, the healthcheck plugin will be installed
+by default. Note, that by configuring to use a packaged or downloaded version of
+the healthcheck plugin, the configured version will take precedence over the default
+version. The plugin is by default configured to disable the `querychanges` and
+`auth` healthchecks, since these would not work on a new and empty Gerrit server.
+The default configuration can be overwritten by adding the `healthcheck.config`
+file as a key-value pair to `gerrit.etc.config` as for every other configuration.
+
 ### Installing Gerrit plugins
 
 There are several different ways to install plugins for Gerrit:
diff --git a/helm-charts/gerrit/templates/gerrit.configmap.yaml b/helm-charts/gerrit/templates/gerrit.configmap.yaml
index b14bd30..4048d50 100644
--- a/helm-charts/gerrit/templates/gerrit.configmap.yaml
+++ b/helm-charts/gerrit/templates/gerrit.configmap.yaml
@@ -8,10 +8,19 @@
     heritage: {{ .Release.Service }}
     release: {{ .Release.Name }}
 data:
-  gerrit.config: |-
-{{ .Values.gerrit.config.gerrit | indent 4 }}
-  replication.config: |-
-{{ .Values.gerrit.config.replication | indent 4 }}
+  {{- 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
diff --git a/helm-charts/gerrit/templates/gerrit.secrets.yaml b/helm-charts/gerrit/templates/gerrit.secrets.yaml
index 897c8a9..77c0445 100644
--- a/helm-charts/gerrit/templates/gerrit.secrets.yaml
+++ b/helm-charts/gerrit/templates/gerrit.secrets.yaml
@@ -11,7 +11,9 @@
   {{ if .Values.gerrit.keystore -}}
   keystore: {{ .Values.gerrit.keystore }}
   {{- end }}
-  secure.config: {{ .Values.gerrit.config.secure | b64enc }}
+  {{- range $key, $value := .Values.gerrit.etc.secret }}
+  {{ $key }}: {{ $value | b64enc }}
+  {{- end }}
 type: Opaque
 ---
 {{ if and .Values.gerrit.ingress.tls.enabled .Values.gerrit.ingress.tls.secret.create -}}
diff --git a/helm-charts/gerrit/templates/gerrit.stateful-set.yaml b/helm-charts/gerrit/templates/gerrit.stateful-set.yaml
index 432330f..c3c04a6 100644
--- a/helm-charts/gerrit/templates/gerrit.stateful-set.yaml
+++ b/helm-charts/gerrit/templates/gerrit.stateful-set.yaml
@@ -59,11 +59,9 @@
         args:
         - |
           symlink_config_to_site(){
-            {{ if .Values.gerrit.keystore -}}
-            ln -s /var/config/keystore /var/gerrit/etc/keystore
-            {{- end }}
-            ln -sf /var/config/gerrit.config /var/gerrit/etc/gerrit.config
-            ln -sf /var/config/secure.config /var/gerrit/etc/secure.config
+            for file in /var/mnt/etc/config/* /var/mnt/etc/secret/*; do
+              ln -sf $file /var/gerrit/etc/$(basename $file)
+            done
           }
 
           mkdir -p /var/gerrit/etc
@@ -81,7 +79,7 @@
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
-        - name: git-filesystem
+        - name: git-repositories
           mountPath: "/var/mnt/git"
         - name: gerrit-init-config
           mountPath: "/var/config/gerrit-init.yaml"
@@ -91,16 +89,9 @@
           mountPath: "/var/mnt/plugins"
         {{- end }}
         - name: gerrit-config
-          mountPath: "/var/config/gerrit.config"
-          subPath: gerrit.config
+          mountPath: "/var/mnt/etc/config"
         - name: gerrit-secure-config
-          mountPath: "/var/config/secure.config"
-          subPath: secure.config
-        {{ if .Values.gerrit.keystore -}}
-        - name: gerrit--secure-config
-          mountPath: "/var/config/keystore"
-          subPath: keystore
-        {{- end }}
+          mountPath: "/var/mnt/etc/secret"
       containers:
       - name: gerrit
         image: {{ template "registry" . }}{{ .Values.gerrit.images.gerrit }}:{{ .Values.images.version }}
@@ -111,32 +102,22 @@
         volumeMounts:
         - name: gerrit-site
           mountPath: "/var/gerrit"
-        - name: git-filesystem
+        - name: git-repositories
           mountPath: "/var/mnt/git"
         - name: gerrit-config
-          mountPath: "/var/config/gerrit.config"
-          subPath: gerrit.config
-        - name: gerrit-config
-          mountPath: "/var/config/replication.config"
-          subPath: replication.config
+          mountPath: "/var/mnt/etc/config"
         - name: gerrit-secure-config
-          mountPath: "/var/config/secure.config"
-          subPath: secure.config
-        {{ if .Values.gerrit.keystore -}}
-        - name: gerrit-secure-config
-          mountPath: "/var/config/keystore"
-          subPath: keystore
-        {{- end }}
+          mountPath: "/var/mnt/etc/secret"
         resources:
 {{ toYaml .Values.gerrit.resources | indent 10 }}
         livenessProbe:
           httpGet:
-            path: /config/server/version
+            path: /config/server/healthcheck~status
             port: gerrit-port
 {{ toYaml .Values.gerrit.livenessProbe | indent 10 }}
         readinessProbe:
           httpGet:
-            path: /config/server/version
+            path: /config/server/healthcheck~status
             port: gerrit-port
 {{ toYaml .Values.gerrit.readinessProbe | indent 10 }}
       volumes:
@@ -149,12 +130,12 @@
         persistentVolumeClaim:
           claimName: {{ .Release.Name }}-plugin-cache-pvc
       {{- end }}
-      - name: git-filesystem
+      - name: git-repositories
         persistentVolumeClaim:
           {{- if .Values.gitRepositoryStorage.externalPVC.use }}
           claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
           {{- else }}
-          claimName: {{ .Release.Name }}-git-filesystem-pvc
+          claimName: {{ .Release.Name }}-git-repositories-pvc
           {{- end }}
       - name: gerrit-init-config
         configMap:
diff --git a/helm-charts/gerrit/templates/git-gc.cronjob.yaml b/helm-charts/gerrit/templates/git-gc.cronjob.yaml
index 403735d..fa5292c 100644
--- a/helm-charts/gerrit/templates/git-gc.cronjob.yaml
+++ b/helm-charts/gerrit/templates/git-gc.cronjob.yaml
@@ -29,17 +29,17 @@
             resources:
 {{ toYaml .Values.gitGC.resources | indent 14 }}
             volumeMounts:
-            - name: git-filesystem
+            - name: git-repositories
               mountPath: "/var/gerrit/git"
             - name: git-gc-logs
               mountPath: "/var/log/git"
           volumes:
-          - name: git-filesystem
+          - name: git-repositories
             persistentVolumeClaim:
               {{- if .Values.gitRepositoryStorage.externalPVC.use }}
               claimName: {{ .Values.gitRepositoryStorage.externalPVC.name }}
               {{- else }}
-              claimName: {{ .Release.Name }}-git-filesystem-pvc
+              claimName: {{ .Release.Name }}-git-repositories-pvc
               {{- end }}
           - name: git-gc-logs
             {{ if .Values.gitGC.logging.persistence.enabled -}}
diff --git a/helm-charts/gerrit/templates/git-repositories.storage.yaml b/helm-charts/gerrit/templates/git-repositories.storage.yaml
index 64a93d8..503acf4 100644
--- a/helm-charts/gerrit/templates/git-repositories.storage.yaml
+++ b/helm-charts/gerrit/templates/git-repositories.storage.yaml
@@ -2,7 +2,7 @@
 kind: PersistentVolumeClaim
 apiVersion: v1
 metadata:
-  name: {{ .Release.Name }}-git-filesystem-pvc
+  name: {{ .Release.Name }}-git-repositories-pvc
   labels:
     app: gerrit
     chart: {{ template "gerrit.chart" . }}
diff --git a/helm-charts/gerrit/values.yaml b/helm-charts/gerrit/values.yaml
index 5504833..f033fbf 100644
--- a/helm-charts/gerrit/values.yaml
+++ b/helm-charts/gerrit/values.yaml
@@ -45,7 +45,7 @@
 gitRepositoryStorage:
   externalPVC:
     use: false
-    name: git-filesystem-pvc
+    name: git-repositories-pvc
   size: 5Gi
 
 
@@ -151,65 +151,68 @@
       enabled: false
       size: 1Gi
 
-  config:
+  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!
-    gerrit: |-
-      [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/
-      [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-1.8-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
+    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
+        [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-1.8-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
 
-    secure: |-
-      # Password for the keystore added as value for 'gerritReplica.keystore'
-      # Only needed, if SSL is enabled.
-      #[httpd]
-      #  sslKeyPassword = gerrit
+      replication.config: |-
+        [gerrit]
+          autoReload = false
+          replicateOnStartup = true
+          defaultForceUpdate = true
 
-      # Credentials for replication targets
-      # [remote "replica"]
-      # username = git
-      # password = secret
+        # [remote "replica"]
+        # url = http://gerrit-replica.example.com/git/${name}.git
+        # replicationDelay = 0
+        # timeout = 30
 
-    replication: |-
-      [gerrit]
-        autoReload = false
-        replicateOnStartup = true
-        defaultForceUpdate = true
+    secret:
+      secure.config: |-
+        # Password for the keystore added as value for 'gerritReplica.keystore'
+        # Only needed, if SSL is enabled.
+        #[httpd]
+        #  sslKeyPassword = gerrit
 
-      # [remote "replica"]
-      # url = http://gerrit-replica.example.com/git/${name}.git
-      # replicationDelay = 0
-      # timeout = 30
+        # Credentials for replication targets
+        # [remote "replica"]
+        # username = git
+        # password = secret
diff --git a/istio/gerrit.profile.yaml b/istio/gerrit.profile.yaml
new file mode 100644
index 0000000..4574621
--- /dev/null
+++ b/istio/gerrit.profile.yaml
@@ -0,0 +1,577 @@
+apiVersion: install.istio.io/v1alpha1
+kind: IstioOperator
+spec:
+  addonComponents:
+    grafana:
+      enabled: false
+      k8s:
+        replicaCount: 1
+    istiocoredns:
+      enabled: false
+    # Dashboard to monitor service mesh. Requires at least prometheus to be
+    # enabled (see below) and a secret defining the user credentials.
+    kiali:
+      enabled: true
+      k8s:
+        replicaCount: 1
+    # Required for the kiali dashboard.
+    # TODO: Try to use Prometheus from gerrit-monitoring setup.
+    prometheus:
+      enabled: true
+      k8s:
+        replicaCount: 1
+    tracing:
+      enabled: false
+  components:
+    base:
+      enabled: true
+    citadel:
+      enabled: false
+      k8s:
+        strategy:
+          rollingUpdate:
+            maxSurge: 100%
+            maxUnavailable: 25%
+    cni:
+      enabled: false
+    egressGateways:
+    - enabled: false
+      k8s:
+        env:
+        - name: ISTIO_META_ROUTER_MODE
+          value: sni-dnat
+        hpaSpec:
+          maxReplicas: 5
+          metrics:
+          - resource:
+              name: cpu
+              targetAverageUtilization: 80
+            type: Resource
+          minReplicas: 1
+          scaleTargetRef:
+            apiVersion: apps/v1
+            kind: Deployment
+            name: istio-egressgateway
+        resources:
+          limits:
+            cpu: 2000m
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 128Mi
+        service:
+          ports:
+          - name: http2
+            port: 80
+          - name: https
+            port: 443
+          - name: tls
+            port: 15443
+            targetPort: 15443
+        strategy:
+          rollingUpdate:
+            maxSurge: 100%
+            maxUnavailable: 25%
+      name: istio-egressgateway
+    ingressGateways:
+    - enabled: true
+      k8s:
+        env:
+        - name: ISTIO_META_ROUTER_MODE
+          value: sni-dnat
+        hpaSpec:
+          maxReplicas: 5
+          metrics:
+          - resource:
+              name: cpu
+              targetAverageUtilization: 80
+            type: Resource
+          minReplicas: 1
+          scaleTargetRef:
+            apiVersion: apps/v1
+            kind: Deployment
+            name: istio-ingressgateway
+        resources:
+          limits:
+            cpu: 2000m
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 128Mi
+        service:
+          ports:
+          - name: status-port
+            port: 15021
+            targetPort: 15021
+          - name: http2
+            port: 80
+            targetPort: 8080
+          - name: https
+            port: 443
+            targetPort: 8443
+          # - name: tls
+          #   port: 15443
+          #   targetPort: 15443
+          - name: ssh
+            port: 29418
+        strategy:
+          rollingUpdate:
+            maxSurge: 100%
+            maxUnavailable: 25%
+      name: istio-ingressgateway
+    istiodRemote:
+      enabled: false
+    pilot:
+      enabled: true
+      k8s:
+        env:
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.name
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        readinessProbe:
+          httpGet:
+            path: /ready
+            port: 8080
+          initialDelaySeconds: 1
+          periodSeconds: 3
+          timeoutSeconds: 5
+        strategy:
+          rollingUpdate:
+            maxSurge: 100%
+            maxUnavailable: 25%
+    policy:
+      enabled: false
+      k8s:
+        env:
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        hpaSpec:
+          maxReplicas: 5
+          metrics:
+          - resource:
+              name: cpu
+              targetAverageUtilization: 80
+            type: Resource
+          minReplicas: 1
+          scaleTargetRef:
+            apiVersion: apps/v1
+            kind: Deployment
+            name: istio-policy
+        strategy:
+          rollingUpdate:
+            maxSurge: 100%
+            maxUnavailable: 25%
+    telemetry:
+      enabled: false
+      k8s:
+        env:
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: GOMAXPROCS
+          value: "6"
+        hpaSpec:
+          maxReplicas: 5
+          metrics:
+          - resource:
+              name: cpu
+              targetAverageUtilization: 80
+            type: Resource
+          minReplicas: 1
+          scaleTargetRef:
+            apiVersion: apps/v1
+            kind: Deployment
+            name: istio-telemetry
+        replicaCount: 1
+        resources:
+          limits:
+            cpu: 4800m
+            memory: 4G
+          requests:
+            cpu: 1000m
+            memory: 1G
+        strategy:
+          rollingUpdate:
+            maxSurge: 100%
+            maxUnavailable: 25%
+  hub: docker.io/istio
+  profile: default
+  meshConfig:
+    defaultConfig:
+      proxyMetadata: {}
+    enablePrometheusMerge: false
+    # Log access logs to stdout in istio-proxy sidecars.
+    # TODO: This should probably be changed in the future, as soon as a more
+    # production ready logging solution is used.
+    accessLogFile: "/dev/stdout"
+  tag: 1.6.3
+  values:
+    base:
+      validationURL: ""
+    clusterResources: true
+    gateways:
+      istio-egressgateway:
+        autoscaleEnabled: true
+        env: {}
+        name: istio-egressgateway
+        secretVolumes:
+        - mountPath: /etc/istio/egressgateway-certs
+          name: egressgateway-certs
+          secretName: istio-egressgateway-certs
+        - mountPath: /etc/istio/egressgateway-ca-certs
+          name: egressgateway-ca-certs
+          secretName: istio-egressgateway-ca-certs
+        type: ClusterIP
+        zvpn: {}
+      istio-ingressgateway:
+        applicationPorts: ""
+        autoscaleEnabled: true
+        debug: info
+        domain: ""
+        env: {}
+        meshExpansionPorts:
+        - name: tcp-pilot-grpc-tls
+          port: 15011
+          targetPort: 15011
+        - name: tcp-istiod
+          port: 15012
+          targetPort: 15012
+        - name: tcp-citadel-grpc-tls
+          port: 8060
+          targetPort: 8060
+        - name: tcp-dns-tls
+          port: 853
+          targetPort: 8853
+        name: istio-ingressgateway
+        secretVolumes:
+        - mountPath: /etc/istio/ingressgateway-certs
+          name: ingressgateway-certs
+          secretName: istio-ingressgateway-certs
+        - mountPath: /etc/istio/ingressgateway-ca-certs
+          name: ingressgateway-ca-certs
+          secretName: istio-ingressgateway-ca-certs
+        type: LoadBalancer
+        zvpn: {}
+    global:
+      arch:
+        amd64: 2
+        ppc64le: 2
+        s390x: 2
+      configValidation: true
+      controlPlaneSecurityEnabled: true
+      defaultNodeSelector: {}
+      defaultPodDisruptionBudget:
+        enabled: true
+      defaultResources:
+        requests:
+          cpu: 10m
+      enableHelmTest: false
+      imagePullPolicy: ""
+      imagePullSecrets: []
+      istioNamespace: istio-system
+      istiod:
+        enableAnalysis: false
+        enabled: true
+      # Gardener does not support the third-party-jwt policy.
+      jwtPolicy: first-party-jwt
+      logAsJson: false
+      logging:
+        level: default:info
+      meshExpansion:
+        enabled: false
+        useILB: false
+      meshNetworks: {}
+      mountMtlsCerts: false
+      multiCluster:
+        clusterName: ""
+        enabled: false
+      network: ""
+      omitSidecarInjectorConfigMap: false
+      oneNamespace: false
+      operatorManageWebhooks: false
+      pilotCertProvider: istiod
+      priorityClassName: ""
+      proxy:
+        autoInject: enabled
+        clusterDomain: cluster.local
+        componentLogLevel: misc:error
+        enableCoreDump: false
+        envoyStatsd:
+          enabled: false
+        excludeIPRanges: ""
+        excludeInboundPorts: ""
+        excludeOutboundPorts: ""
+        image: proxyv2
+        includeIPRanges: '*'
+        # Use this value, if more detailed logging output is needed, e.g. for
+        # debugging.
+        logLevel: warning
+        privileged: false
+        readinessFailureThreshold: 30
+        readinessInitialDelaySeconds: 1
+        readinessPeriodSeconds: 2
+        resources:
+          limits:
+            cpu: 2000m
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 128Mi
+        statusPort: 15020
+        tracer: zipkin
+      proxy_init:
+        image: proxyv2
+        resources:
+          limits:
+            cpu: 100m
+            memory: 50Mi
+          requests:
+            cpu: 10m
+            memory: 10Mi
+      sds:
+        token:
+          aud: istio-ca
+      sts:
+        servicePort: 0
+      tracer:
+        datadog:
+          address: $(HOST_IP):8126
+        lightstep:
+          accessToken: ""
+          address: ""
+        stackdriver:
+          debug: false
+          maxNumberOfAnnotations: 200
+          maxNumberOfAttributes: 200
+          maxNumberOfMessageEvents: 200
+        zipkin:
+          address: ""
+      trustDomain: cluster.local
+      useMCP: false
+    grafana:
+      accessMode: ReadWriteMany
+      contextPath: /grafana
+      dashboardProviders:
+        dashboardproviders.yaml:
+          apiVersion: 1
+          providers:
+          - disableDeletion: false
+            folder: istio
+            name: istio
+            options:
+              path: /var/lib/grafana/dashboards/istio
+            orgId: 1
+            type: file
+      datasources:
+        datasources.yaml:
+          apiVersion: 1
+      env: {}
+      envSecrets: {}
+      image:
+        repository: grafana/grafana
+        tag: 6.7.4
+      nodeSelector: {}
+      persist: false
+      podAntiAffinityLabelSelector: []
+      podAntiAffinityTermLabelSelector: []
+      security:
+        enabled: false
+        passphraseKey: passphrase
+        secretName: grafana
+        usernameKey: username
+      service:
+        annotations: {}
+        externalPort: 3000
+        name: http
+        type: ClusterIP
+      storageClassName: ""
+      tolerations: []
+    istiocoredns:
+      coreDNSImage: coredns/coredns
+      coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1
+      coreDNSTag: 1.6.2
+    istiodRemote:
+      injectionURL: ""
+    kiali:
+      contextPath: /kiali
+      createDemoSecret: false
+      dashboard:
+        auth:
+          strategy: login
+        grafanaInClusterURL: http://grafana:3000
+        jaegerInClusterURL: http://tracing/jaeger
+        passphraseKey: passphrase
+        secretName: kiali
+        usernameKey: username
+        viewOnlyMode: false
+      hub: quay.io/kiali
+      nodeSelector: {}
+      podAntiAffinityLabelSelector: []
+      podAntiAffinityTermLabelSelector: []
+      security:
+        cert_file: /kiali-cert/cert-chain.pem
+        enabled: false
+        private_key_file: /kiali-cert/key.pem
+      service:
+        annotations: {}
+      tag: v1.18
+    mixer:
+      adapters:
+        kubernetesenv:
+          enabled: true
+        prometheus:
+          enabled: true
+          metricsExpiryDuration: 10m
+        stackdriver:
+          auth:
+            apiKey: ""
+            appCredentials: false
+            serviceAccountPath: ""
+          enabled: false
+          tracer:
+            enabled: false
+            sampleProbability: 1
+        stdio:
+          enabled: false
+          outputAsJson: false
+        useAdapterCRDs: false
+      policy:
+        adapters:
+          kubernetesenv:
+            enabled: true
+          useAdapterCRDs: false
+        autoscaleEnabled: true
+        image: mixer
+        sessionAffinityEnabled: false
+      telemetry:
+        autoscaleEnabled: true
+        env:
+          GOMAXPROCS: "6"
+        image: mixer
+        loadshedding:
+          latencyThreshold: 100ms
+          mode: enforce
+        nodeSelector: {}
+        podAntiAffinityLabelSelector: []
+        podAntiAffinityTermLabelSelector: []
+        replicaCount: 1
+        sessionAffinityEnabled: false
+        tolerations: []
+    pilot:
+      appNamespaces: []
+      autoscaleEnabled: true
+      autoscaleMax: 5
+      autoscaleMin: 1
+      configMap: true
+      configNamespace: istio-config
+      cpu:
+        targetAverageUtilization: 80
+      enableProtocolSniffingForInbound: true
+      enableProtocolSniffingForOutbound: true
+      env: {}
+      image: pilot
+      keepaliveMaxServerConnectionAge: 30m
+      nodeSelector: {}
+      podAntiAffinityLabelSelector: []
+      podAntiAffinityTermLabelSelector: []
+      policy:
+        enabled: false
+      replicaCount: 1
+      tolerations: []
+      traceSampling: 1
+    prometheus:
+      contextPath: /prometheus
+      hub: docker.io/prom
+      nodeSelector: {}
+      podAntiAffinityLabelSelector: []
+      podAntiAffinityTermLabelSelector: []
+      provisionPrometheusCert: true
+      retention: 6h
+      scrapeInterval: 15s
+      security:
+        enabled: true
+      tag: v2.15.1
+      tolerations: []
+    sidecarInjectorWebhook:
+      enableNamespacesByDefault: false
+      injectLabel: istio-injection
+      objectSelector:
+        autoInject: true
+        enabled: false
+      rewriteAppHTTPProbe: false
+    telemetry:
+      enabled: true
+      v1:
+        enabled: false
+      v2:
+        enabled: true
+        metadataExchange: {}
+        prometheus:
+          enabled: true
+        stackdriver:
+          configOverride: {}
+          enabled: false
+          logging: false
+          monitoring: false
+          topology: false
+    tracing:
+      jaeger:
+        accessMode: ReadWriteMany
+        hub: docker.io/jaegertracing
+        memory:
+          max_traces: 50000
+        persist: false
+        spanStorageType: badger
+        storageClassName: ""
+        tag: "1.16"
+      nodeSelector: {}
+      opencensus:
+        exporters:
+          stackdriver:
+            enable_tracing: true
+        hub: docker.io/omnition
+        resources:
+          limits:
+            cpu: "1"
+            memory: 2Gi
+          requests:
+            cpu: 200m
+            memory: 400Mi
+        tag: 0.1.9
+      podAntiAffinityLabelSelector: []
+      podAntiAffinityTermLabelSelector: []
+      provider: jaeger
+      service:
+        annotations: {}
+        externalPort: 9411
+        name: http-query
+        type: ClusterIP
+      zipkin:
+        hub: docker.io/openzipkin
+        javaOptsHeap: 700
+        maxSpans: 500000
+        node:
+          cpus: 2
+        probeStartupDelay: 10
+        queryPort: 9411
+        resources:
+          limits:
+            cpu: 1000m
+            memory: 2048Mi
+          requests:
+            cpu: 150m
+            memory: 900Mi
+        tag: 2.20.0
+    version: ""
diff --git a/istio/kiali.secret.yaml b/istio/kiali.secret.yaml
new file mode 100644
index 0000000..68a2f89
--- /dev/null
+++ b/istio/kiali.secret.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: kiali
+  namespace: istio-system
+  labels:
+    app: kiali
+type: Opaque
+data:
+  username: YWRtaW4=
+  passphrase: c2VjcmV0
diff --git a/istio/namespace.yaml b/istio/namespace.yaml
new file mode 100644
index 0000000..6e9fb38
--- /dev/null
+++ b/istio/namespace.yaml
@@ -0,0 +1,6 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: gerrit-replica
+  labels:
+    istio-injection: enabled
diff --git a/publish b/publish
index ce6f36b..b70e8c0 100755
--- a/publish
+++ b/publish
@@ -2,7 +2,7 @@
 
 usage() {
     me=`basename "$0"`
-    echo >&2 "Usage: $me [--update-latest] [--tag TAG] [--registry REGISTRY] component"
+    echo >&2 "Usage: $me [--help] [--update-latest] [--registry REGISTRY] --tag TAG [IMAGE]"
     exit 1
 }
 
@@ -10,6 +10,9 @@
 
 while test $# -gt 0 ; do
   case "$1" in
+  --help)
+    usage
+    ;;
   --update-latest)
     UPDATE_LATEST=true
     shift
@@ -32,18 +35,33 @@
 if test -z "$TAG"; then
   echo "No tag was provided."
   echo "Use either the --tag option or provide a TAG-environment variable."
-  exit 1
+  usage
 fi
 
+#Get list of images
+source container-images/publish_list
+IMAGES=$(get_image_list)
+
 test -n "$REGISTRY" && [[ "$REGISTRY" != */ ]] && REGISTRY="$REGISTRY/"
 
-test $# -eq 1 || usage
-IMAGE=$1
+publish_image(){
+  IMAGE=$1
+  if test "$UPDATE_LATEST" = "true" ; then
+    docker image tag k8sgerrit/$IMAGE:$TAG ${REGISTRY}k8sgerrit/$IMAGE:latest
+    docker push ${REGISTRY}k8sgerrit/$IMAGE:latest
+  fi
 
-if test "$UPDATE_LATEST" = "true" ; then
-  docker image tag k8sgerrit/$IMAGE:$TAG ${REGISTRY}k8sgerrit/$IMAGE:latest
-  docker push ${REGISTRY}k8sgerrit/$IMAGE:latest
+  docker image tag k8sgerrit/$IMAGE:$TAG ${REGISTRY}k8sgerrit/$IMAGE:$TAG
+  docker push ${REGISTRY}k8sgerrit/$IMAGE:$TAG
+}
+
+if test $# -eq 0 ; then
+  for IMAGE in $IMAGES; do
+    publish_image $IMAGE
+  done
+else
+  while test $# -gt 0 ; do
+    publish_image $1
+    shift
+  done
 fi
-
-docker image tag k8sgerrit/$IMAGE:$TAG ${REGISTRY}k8sgerrit/$IMAGE:$TAG
-docker push ${REGISTRY}k8sgerrit/$IMAGE:$TAG
\ No newline at end of file
diff --git a/tests/conftest.py b/tests/conftest.py
index c429b33..ed8c041 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -357,3 +357,8 @@
     if request.config.getoption("--push"):
         docker_push("gerrit-init")
     return gerrit_init_image
+
+
+@pytest.fixture(scope="session")
+def required_plugins(request):
+    return ["healthcheck"]
diff --git a/tests/container-images/conftest.py b/tests/container-images/conftest.py
index 88f4151..2290565 100644
--- a/tests/container-images/conftest.py
+++ b/tests/container-images/conftest.py
@@ -42,7 +42,7 @@
 
     def _define_volume_mounts(self):
         volumes = {
-            v: {"bind": "/var/config/%s" % k, "mode": "rw"}
+            v: {"bind": "/var/mnt/etc/config/%s" % k, "mode": "rw"}
             for (k, v) in self._create_config_files().items()
         }
         volumes[os.path.join(self.tmp_dir, "lib")] = {
diff --git a/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py b/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py
index c20144e..52a2f35 100755
--- a/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py
+++ b/tests/container-images/gerrit-base/test_container_structure_gerrit_base.py
@@ -79,6 +79,14 @@
 
 @pytest.mark.docker
 @pytest.mark.structure
+def test_gerrit_base_contains_required_plugins(container_run, required_plugins):
+    for plugin in required_plugins:
+        exit_code, _ = container_run.exec_run("test -f /var/plugins/%s.jar" % plugin)
+        assert exit_code == 0
+
+
+@pytest.mark.docker
+@pytest.mark.structure
 def test_gerrit_base_site_permissions(container_run):
     exit_code, _ = container_run.exec_run("test -O /var/gerrit")
     assert exit_code == 0
diff --git a/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py b/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
index 082ffa7..287dac7 100644
--- a/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
+++ b/tests/container-images/gerrit-init/test_container_integration_gerrit_init.py
@@ -126,7 +126,12 @@
             yaml.dump({"packagedPlugins": plugins}, f, default_flow_style=False)
 
     def test_gerrit_init_plugins_are_installed(
-        self, container_run_endless, init_config_dir, plugins_to_install, tmp_site_dir
+        self,
+        container_run_endless,
+        init_config_dir,
+        plugins_to_install,
+        tmp_site_dir,
+        required_plugins,
     ):
         self._configure_packaged_plugins(
             os.path.join(init_config_dir, "init.yaml"), plugins_to_install
@@ -143,5 +148,23 @@
             assert os.path.exists(os.path.join(plugins_path, "%s.jar" % plugin))
 
         installed_plugins = os.listdir(plugins_path)
+        expected_plugins = plugins_to_install + required_plugins
         for plugin in installed_plugins:
-            assert os.path.splitext(plugin)[0] in plugins_to_install
+            assert os.path.splitext(plugin)[0] in expected_plugins
+
+    def test_required_plugins_are_installed(
+        self, container_run_endless, init_config_dir, tmp_site_dir, required_plugins
+    ):
+        self._configure_packaged_plugins(
+            os.path.join(init_config_dir, "init.yaml"), ["hooks"]
+        )
+
+        exit_code, _ = container_run_endless.exec_run(
+            "/var/tools/gerrit_init.py -s /var/gerrit -c /var/config/init.yaml"
+        )
+        assert exit_code == 0
+
+        for plugin in required_plugins:
+            assert os.path.exists(
+                os.path.join(tmp_site_dir, "plugins", "%s.jar" % plugin)
+            )