blob: 93d9206eb767b78e193a58d3089d2aeb1f048b98 [file] [log] [blame] [view]
# Gerrit Operator
- [Gerrit Operator](#gerrit-operator)
- [Development](#development)
- [Prerequisites](#prerequisites)
- [Shared Storage (ReadWriteMany)](#shared-storage-readwritemany)
- [Ingress provider](#ingress-provider)
- [Deploy](#deploy)
- [Using helm charts](#using-helm-charts)
- [gerrit-operator-crds](#gerrit-operator-crds)
- [gerrit-operator](#gerrit-operator-1)
- [Without the helm charts](#without-the-helm-charts)
- [Updating](#updating)
- [CustomResources](#customresources)
- [GerritCluster](#gerritcluster)
- [Gerrit](#gerrit)
- [GitGarbageCollection](#gitgarbagecollection)
- [Receiver](#receiver)
- [GerritNetwork](#gerritnetwork)
- [IncomingReplicationTask](#incomingreplicationtask)
- [Configuration of Gerrit](#configuration-of-gerrit)
- [Feature toggles](#feature-toggles)
- [Cluster Mode](#cluster-mode)
- [With helm charts](#with-helm-charts)
- [Without helm charts](#without-helm-charts)
- [Minikube](#minikube)
- [Prerequisites](#prerequisites-1)
- [Starting Minikube](#starting-minikube)
- [Build images](#build-images)
- [Gerrit Operator](#gerrit-operator-2)
- [NFS](#nfs)
- [Primary Gerrit](#primary-gerrit)
- [Adding a Gerrit Replica](#adding-a-gerrit-replica)
- [Istio](#istio)
- [High Availability](#high-availability)
- [Minikube multisite](#minikube-multisite)
- [Prerequisites](#prerequisites-2)
- [Build images](#build-images-1)
- [Istio](#istio-1)
- [Gerrit Operator](#gerrit-operator-3)
- [Deploy multisite with three replicas](#deploy-multisite-with-three-replicas)
- [Multisite notes](#multisite-notes)
- [Istio](#istio-2)
- [Kafka](#kafka)
- [Zookeeper](#zookeeper)
- [Sync Gerrit sites](#sync-gerrit-sites)
- [Multisite monitoring](#multisite-monitoring)
- [Prerequisites](#prerequisites-3)
- [Access to Prometheus](#access-to-prometheus)
- [Access to Grafana](#access-to-grafana)
- [Access to AlertManager](#access-to-alertmanager)
## Development
Development processes are documented [here](./operator-dev.md).
## Prerequisites
Deploying Gerrit using the operator requires some additional prerequisites to be
fulfilled:
### Shared Storage (ReadWriteMany)
Gerrit instances share the repositories and other data using shared volumes. Thus,
a StorageClass and a suitable provisioner have to be available in the cluster.
An example for such a provisioner would be the
[NFS-subdir-external-provisioner](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner).
### Ingress provider
The Gerrit Operator will also set up network routing rules and an ingress point
for the Gerrit instances it manages. The network routing rules ensure that requests
will be routed to the intended GerritCluster component, e.g. in case a primary
Gerrit and a Gerrit Replica exist in the cluster, git fetch/clone requests will
be sent to the Gerrit Replica and all other requests to the primary Gerrit.
You may specify the ingress provider by setting the `INGRESS` environment
variable in the operator Deployment manifest. That is, the choice of an ingress
provider is an operator-level setting. However, you may specify some ingress
configuration options (host, tls, etc) at the `GerritCluster` level, via
[GerritClusterIngressConfig](operator-api-reference.md#gerritclusteringressconfig).
The Gerrit Operator currently supports the following Ingress providers:
- **NONE**
The operator will install no Ingress components. Services will still be available.
No prerequisites are required for this case.
If `spec.ingress.enabled` is set to `true` in GerritCluster, the operator will
still configure network related options like `http.listenUrl` in Gerrit based on
the other options in `spec.ingress`.
- **INGRESS**
The operator will install an Ingress. Currently only the
[Nginx-Ingress-Controller](https://docs.nginx.com/nginx-ingress-controller/) is
supported, which will have to be installed in the cluster and has to be configured
to [allow snippet configurations](https://docs.nginx.com/nginx-ingress-controller/configuration/ingress-resources/advanced-configuration-with-snippets/).
An example of a working deployment can be found [here](../supplements/test-cluster/ingress/).
SSH support is not fully managed by the operator, since it has to be enabled and
[configured in the nginx ingress controller itself](https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/).
- **ISTIO**
The operator supports the use of [Istio](https://istio.io/) as a service mesh.
An example on how to set up Istio can be found [here](../istio/gerrit.profile.yaml).
- **AMBASSADOR**
The operator also supports [Ambassador](https://www.getambassador.io/) for
setting up ingress to the Gerrits deployed by the operator. If you use
Ambassador's "Edge Stack" or "Emissary Ingress" to provide ingress to your k8s
services, you should set INGRESS=AMBASSADOR. Currently, SSH is not directly
supported when using INGRESS=AMBASSADOR.
## Deploy
You will need to have admin privileges for your k8s cluster in order to be able
to deploy the following resources.
You may choose to deploy the operator resources using helm, or directly via
`kubectl apply`.
### Using helm charts
Make sure you have [helm](https://helm.sh/) installed in your environment.
There are two relevant helm charts.
#### gerrit-operator-crds
This chart installs the CRDs (k8s API extensions) to your k8s cluster. No chart
values need to be modified. The build initiated by the `mvn install` command
from the [Publish](#publish) section includes a step that updates the CRDs in
this helm chart to reflect any changes made to them in the operator source code.
The CRDs installed are: GerritCluster, Gerrit, GitGarbageCollection, Receiver.
You do not need to manually `helm install` this chart; this chart is installed
as a dependency of the second `gerrit-operator` helm chart as described in the
next subheading.
#### gerrit-operator
This chart installs the `gerrit-operator-crds` chart as a dependency, and the
following k8s resources:
- Deployment
- ServiceAccount
- ClusterRole
- ClusterRoleBinding
The operator itself creates a Service resource and a
ValidationWebhookConfigurations resource behind the scenes.
You will need to modify the values in `helm-charts/gerrit-operator/values.yaml`
to point the chart to the registry/org that is hosting the Docker container
image for the operator (from the [Publish](#publish) step earlier). Now,
run:
```sh
# Create a namespace for the gerrit-operator
kubectl create ns gerrit-operator
# Build the gerrit-operator-crds chart and store it in the charts/ subdirectory
helm dependency build helm-charts/gerrit-operator/
# Install the gerrit-operator-crds chart and the gerrit-operator chart
helm -n gerrit-operator install gerrit-operator helm-charts/gerrit-operator/
```
The chart itself, and all the bundled namespaced resources, are installed in the
`gerrit-operator` namespace, as per the `-n` option in the helm command.
### Without the helm charts
First all CustomResourceDefinitions have to be deployed:
```sh
kubectl apply -f operator/target/classes/META-INF/fabric8/*-v1.yml
```
Note that these do not include the -v1beta1.yaml files, as those are for old
Kubernetes versions.
The operator requires a Java Keystore with a keypair inside to allow TLS
verification for Kubernetes Admission Webhooks. To create a keystore and
encode it with base64, run:
```sh
keytool \
-genkeypair \
-alias operator \
-keystore keystore \
-keyalg RSA \
-keysize 2048 \
-validity 3650
cat keystore | base64 -b 0
```
Add the result to the Secret in `k8s/operator.yaml` (see comments in the file)
and also add the base64-encoded password for the keystore to the secret.
Then the operator and associated RBAC rules can be deployed:
```sh
kubectl apply -f operator/k8s/rbac.yaml
kubectl apply -f operator/k8s/operator.yaml
```
`k8s/operator.yaml` contains a basic deployment of the operator. Resources,
docker image name etc. might have to be adapted. For example, the ingress
provider has to be configured by setting the `INGRESS` environment variable
in `operator/k8s/operator.yaml` to either `NONE`, `INGRESS`, `ISTIO`, or
`AMBASSADOR`.
### Updating
The Gerrit Operator helm chart can be updated by running:
```sh
# Rebuild the gerrit-operator-crds chart and store it in the charts/ subdirectory
helm dependency build helm-charts/gerrit-operator/
# Install the gerrit-operator-crds chart and the gerrit-operator chart
helm -n gerrit-operator upgrade gerrit-operator helm-charts/gerrit-operator/
```
The Gerrit Operator will automatically reconcile all CustomResources in the cluster
on startup.
The GerritOperator will always only support two versions of the CRDs. The newer
version will always be the one that will be stored in ETCD. Conversion will happen
automatically during the update. Note, that this means that updates over multiple
versions will not work, but updates that include CRD version updates have to be
done in sequence.
## CustomResources
The operator manages several CustomResources that are described in more detail
below.
The API reference for all CustomResources can be found [here](operator-api-reference.md).
### GerritCluster
The GerritCluster CustomResource installs one or multiple Gerrit instances. The
operator takes over managing the state of all Gerrit instances within the cluster
and ensures that the state stays in sync. To this end it manages additional
resources that are shared between Gerrit instances or are required to synchronize
the state between Gerrit instances. These additional resources include:
- storage
- network / service mesh
Installing Gerrit with the GerritCluster resource is highly recommended over using
the [Gerrit](#gerrit) CustomResource directly, even if only a single deployment is
installed, since this reduces the requirements that have to be managed manually.
The same holds true for the [Receiver](#receiver) CustomResource, which without
a Gerrit instance using the same site provides little value.
For now, only a single Gerrit CustomResource using each [mode](./operator-api-reference.md#gerritmode)
can be deployed in a GerritCluster, e.g. one primary Gerrit and one Gerrit Replica.
The reason for that is, that there is currently no sharding implemented and thus
multiple deployments don't bring any more value than just scaling the existing
deployment. Instead of a primary Gerrit also a Receiver can be installed.
### Gerrit
The Gerrit CustomResource deploys a Gerrit, which can run in multiple modes.
The Gerrit-CustomResource is mainly meant to be used by the GerritCluster-reconciler
to install Gerrit-instances managed by a GerritCluster. Gerrit-CustomResources
can however also be applied separately. Note, that the Gerrit operator will then
not create any storage resources or setup any network resources in addition to
the service.
### GitGarbageCollection
The GitGarbageCollection-CustomResource is used by the operator to set up CronJobs
that regularly run Git garbage collection on the git repositories that are served
by a GerritCluster.
A GitGarbageCollection can either handle all repositories, if no specific repository
is configured or a selected set of repositories. Multiple GitGarbageCollections
can exist as part of the same GerritCluster, but no two GitGarbageCollections
can work on the same project. This is prevented in three ways:
- ValidationWebhooks will prohibit the creation of a second GitGarbageCollection
that does not specify projects, i.e. that would work on all projects.
- Projects for which a GitGarbageCollections that specifically selects it exists
will be excluded from the GitGarbageCollection that works on all projects, if
it exists.
- ValidationWebhooks will prohibit the creation of a GitGarbageCollection that
specifies a project that was already specified by another GitGarbageCollection.
### Receiver
**NOTE:** A Receiver should never be installed for a GerritCluster that is already
managing a primary Gerrit to avoid conflicts when writing into repositories.
The Receiver-CustomResource installs a Deployment running Apache with a git-http-
backend that is meant to receive pushes performed by Gerrit's replication plugin.
It can only be installed into a GerritCluster that does not include a primary
Gerrit, but only Gerrit Replicas.
The Receiver-CustomResource is mainly meant to be used by the GerritCluster-reconciler
to install a Receiver-instance managed by a GerritCluster. Receiver-CustomResources
can however also be applied separately. Note, that the Gerrit operator will then
not create any storage resources or setup any network resources in addition to
the service.
### GerritNetwork
The GerritNetwork CustomResource deploys network components depending on the
configured ingress provider to enable ingress traffic to GerritCluster components.
The GerritNetwork CustomResource is not meant to be installed manually, but will
be created by the Gerrit Operator based on the GerritCluster CustomResource.
### IncomingReplicationTask
A regularly running task to fetch repositories from a different git server that
is not necessarily a Gerrit to the local Gerrit. This job can also be used to
fetch a subset of refs into an existing repository in Gerrit, e.g. branches from
a forked repository could be fetched into a ref namespace of the fork residing
in Gerrit.
Only fetching via HTTP(S) is supported at the moment. SSH can't be used for
fetches.
## Configuration of Gerrit
The operator takes care of all configuration in Gerrit that depends on the
infrastructure, i.e. Kubernetes and the GerritCluster. This avoids duplicated
configuration and misconfiguration.
This means that some options in the gerrit.config are not allowed to be changed.
If these values are set and are not matching the expected value, a ValidationWebhook
will reject the resource creation/update. Thus, it is best to not set these values
at all. To see which values the operator assigned check the ConfigMap created by
the operator for the respective Gerrit.
These options are:
- `cache.directory`
This should stay in the volume mounted to contain the Gerrit site and will
thus be set to `cache`.
- `container.javaHome`
This has to be set to `/usr/lib/jvm/java-11-openjdk-amd64`, since this is
the path of the Java installation in the container.
- `container.javaOptions = -Djavax.net.ssl.trustStore`
The keystore will be mounted to `/var/gerrit/etc/keystore`.
- `container.replica`
This has to be set in the Gerrit-CustomResource under `spec.isReplica`.
- `container.user`
The technical user in the Gerrit container is called `gerrit`.
- `gerrit.basePath`
The git repositories are mounted to `/var/gerrit/git` in the container.
- `gerrit.canonicalWebUrl`
The canonical web URL has to be set to the hostname used by the Ingress/Istio.
- `httpd.listenURL`
This has to be set to `proxy-http://*:8080/` or `proxy-https://*:8080`,
depending of TLS is enabled in the Ingress or not, otherwise the Jetty
servlet will run into an endless redirect loop.
- `sshd.advertisedAddress`
This is only enforced, if Istio is enabled. It can be configured otherwise.
- `sshd.listenAddress`
Since the container port for SSH is fixed, this will be set automatically.
If no SSH port is configured in the service, the SSHD is disabled.
## Feature toggles
This section is dedicated to explain what are the feature toggles and how to set each one of them.
### Cluster Mode
The introduction of this enumeration allows the provision of Gerrit in different modes.
It is defined by an environment variable called `CLUSTER_MODE`, that can have the values of:
* `HIGH_AVAILABILITY`
* `MULTISITE`
By default, the mode is set to `HIGH_AVAILABILITY`.
In case of provision Gerrit in `MULTISITE` mode, only `ISTIO` will be supported as ingress provider.
If the `MULTISITE` mode is used, the following plugins have to be available either
in the container image (not the case by default), in the gerrit.war file in the container image
or in the list of plugins to download as configured in the GerritCluster CustomResource:
- `events-kafka`
- `multisite`
- `pull-replication`
- `websession-broker`
The reason, they are not available in the container images is, that these plugins
are currently not actively maintained under the Apache 2 license. If that changes,
the plugins will be readded to the container images.
It can be configured either by:
#### With helm charts
The environment variable `CLUSTER_MODE` is set by the helm chart property `cluster.mode`.
#### Without helm charts
The environment variable `CLUSTER_MODE` is set in the Operator K8s Deployment Resource.
## Minikube
This chapter gives a short walkthrough in installing the Gerrit operator and a
minimal GerritCluster in minikube. It is meant as an entrypoint for new users and
developers to get familiar with deploying the setup.
### Prerequisites
The following tools are required for following the guide:
- [JDK 17](https://jdk.java.net/archive/)
- [maven](https://maven.apache.org/download.cgi)
- [yq](https://github.com/mikefarah/yq?tab=readme-ov-file#macos--linux-via-homebrew)
- [docker](https://docs.docker.com/get-docker/)
- [minikube](https://minikube.sigs.k8s.io/docs/start/)
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
- [helm](https://helm.sh/docs/intro/install/) (> 3.0)
During this guide a lot of components/pods will be started in Minikube. Consider
increasing the number of CPUs and RAM that Minikube is allowed to use. This can
either be done by configuring the limits in Docker or by using the `--cpus=10` and
`--memory=32000` options.
The guide was tested with 10 CPUs and 32G RAM, but should also work with less
resources. With the full setup running without load, 14G RAM and 0.5 CPUs are
being used, but during startup of Gerrit more resources are required.
### Starting Minikube
First start minikube:
```sh
minikube start
```
### Build images
It is highly recommended to build the images manually to ensure that it is
compatible with the example resources at the checked out commit:
```sh
eval $(minikube docker-env)
./build --tag latest
pushd operator
mvn clean install -Drevision=latest
docker image tag gerrit-operator:latest k8sgerrit/gerrit-operator:latest
popd
```
### Gerrit Operator
Then we can install the Gerrit Operator. This setup will use all the default values,
i.e. no ingress provider support will be installed and it will use the latest
version.
```sh
kubectl create ns gerrit-operator
helm dependency build --verify helm-charts/gerrit-operator
helm upgrade \
--install gerrit-operator \
helm-charts/gerrit-operator \
-n gerrit-operator \
--set=image.imagePullPolicy=IfNotPresent
```
### NFS
For a GerritCluster a volume with ReadWriteMany capabilities is required. Thus,
a NFS provisioner has to be deployed:
```sh
kubectl create ns nfs
helm repo add nfs-ganesha-server-and-external-provisioner \
https://kubernetes-sigs.github.io/nfs-ganesha-server-and-external-provisioner/
helm upgrade \
--install nfs \
nfs-ganesha-server-and-external-provisioner/nfs-server-provisioner \
-n nfs
```
### Primary Gerrit
The Gerrit Operator will not manage secrets itself, since secret data would be
exposed in the custom resources. Thus, Secrets have to be applied manually and
referenced by name in the GerritCluster CustomResource. To create a Secret
containing SSH keys for Gerrit, run:
```sh
kubectl create ns gerrit
kubectl apply -f Documentation/examples/gerrit.secret.yaml
```
Then a simple GerritCluster can be installed:
```sh
kubectl apply -f Documentation/examples/1-gerritcluster.yaml
```
This will install a single primary Gerrit instance without any networking, i.e.
it can only be accessed via port-forwarding.
### Adding a Gerrit Replica
Next, a Gerrit Replica can be added to the GerritCluster. It will access the
repositories from the same filesystem as the primary Gerrit:
```sh
diff Documentation/examples/1-gerritcluster.yaml Documentation/examples/2-gerritcluster-with-replica.yaml
kubectl apply -f Documentation/examples/2-gerritcluster-with-replica.yaml
```
### Istio
The Gerrit Operator can also manage network routing configuration in the
GerritCluster. To do that we need to install one of the supported Ingress
providers like Istio.
To install Istio with default configuration download istioctl:
```sh
export ISTIO_VERSION=1.20.3 && curl -L https://istio.io/downloadIstio | sh -
export PATH=$PWD/istio-$ISTIO_VERSION/bin:$PATH
```
Then install istio:
```sh
istioctl install -f istio/gerrit.profile.yaml
```
Enabling istio sidecar injection in the Gerrit namespace is required to add Gerrit
pods to the service mesh:
```sh
kubectl label namespace gerrit istio-injection=enabled
```
To make use of Istio, the operator has to be configured to support Istio as an
Ingress provider:
```sh
helm upgrade \
--install gerrit-operator \
helm-charts/gerrit-operator \
-n gerrit-operator \
--set=ingress.type=ISTIO
```
Next, the Ingress can be enabled in the GerritCluster:
```sh
diff Documentation/examples/2-gerritcluster-with-replica.yaml Documentation/examples/3-gerritcluster-istio.yaml
kubectl apply -f Documentation/examples/3-gerritcluster-istio.yaml
```
To access Gerrit, a tunnel has to be established to the Istio Ingressgateway
service and the host. This should be done in a separate shell session.
```sh
minikube tunnel
```
The connection data can be retrieved like this:
```sh
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
echo $GATEWAY_URL
```
Add the following line to `/etc/hosts` (This assumes that `$GATEWAY_URL` is
`127.0.0.1`):
```sh
127.0.0.1 gerrit.minikube
```
Gerrit can now be accessed using `http://gerrit.minikube`. Note, that since a
primary and a Gerrit Replica exist in the GerritCluster, the Gerrit Operator will
automatically configure Istio to route fetch and clone requests to the Gerrit
Replica.
### High Availability
As a next step Gerrit can be scaled to provide better availability. This is
straightforward for the Gerrit Replica, since it just requires to increase the
number of replicas in the Statefulset of Gerrit primaries in the GerritCluster
spec:
```sh
diff Documentation/examples/3-gerritcluster-istio.yaml Documentation/examples/4-gerritcluster-ha-replica.yaml
kubectl apply -f Documentation/examples/4-gerritcluster-ha-replica.yaml
```
For the primary Gerrit, the Gerrit Operator will automatically install and configure
the high-availability plugin, if the Primary Gerrit is scaled to 2 or more pod
replicas. However, there are some prerequisites.
First, a database to be used for the global refdb is required. In this example,
zookeeper will be used:
```sh
kubectl create ns zookeeper
kubectl label namespace zookeeper istio-injection=enabled
helm upgrade --install zookeeper oci://registry-1.docker.io/bitnamicharts/zookeeper -n zookeeper
```
Now, the GerritCluster can be configured to use the Global RefDB. Since the
zookeeper plugin is not maintained in the opensource project at the moment,
configure a URL from where to download the plugin in `Documentation/examples/5-gerritcluster-refdb.yaml`.
Then run:
```sh
diff Documentation/examples/4-gerritcluster-ha-replica.yaml Documentation/examples/5-gerritcluster-refdb.yaml
kubectl apply -f Documentation/examples/5-gerritcluster-refdb.yaml
```
This will configure Gerrit to install the global-refdb lib module and the plugin
with the configured implementation, in this example Zookeeper. The Gerrit Operator
will also set some basic authentication to enable the connection to the database.
For Gerrit to be able to discover its peers, it has to have permissions to get
the Gerrit pods deployed in its own namespace from the Kubernetes API server.
For that purpose, a ServiceAccount with the corresponding role needs to be created:
```sh
kubectl apply -f Documentation/examples/gerrit.rbac.yaml
```
Now, the primary Gerrit can be scaled up (Don't forget to also add the
zookeeper-refdb plugin URL). The ServiceAccount also has to be referenced:
```sh
diff Documentation/examples/5-gerritcluster-refdb.yaml Documentation/examples/6-gerritcluster-ha-primary.yaml
kubectl apply -f Documentation/examples/6-gerritcluster-ha-primary.yaml
```
Now, two primary Gerrit pods are available in the cluster.
## Minikube Multisite
This chapter gives a short walkthrough on installing the Gerrit operator and a
GerritCluster in minikube with three primary instances. The features currently
implemented are:
* Use pull-replication plugin.
* Each primary has its own file system for Gerrit site (no nfs).
* Number of primaries can change but auto scaling is not supported.
> **NOTE**: Gerrit multi-site is widely adopted and fully production-ready.
> However, the work is never complete as it can still be evolved and improved
> over time. Therefore, this implementation is still to be considered a
> _work-in-progress_ albeit fully working E2E for a production environment.
### Prerequisites
Prerequisites for this configuration are the same as [this section](#prerequisites-1),
bearing in mind that some of them may not be strictly relevant, plus:
* Kafka broker should be deployed or accessible from the cluster. The connection string must be
specified in the `events-kafka plugin` section of the `gerrit.config`, located within the
`spec.gerrits[0].spec.configFiles` object, i.e:
```
configFiles:
gerrit.config: |-
...
[plugin "events-kafka"]
bootstrapServers = kafka-service.kafka-zk.svc.cluster.local:9092
...
```
For additional context, please refer to the section `configFiles` in [GerritTemplateSpec](operator-api-reference.md#gerrittemplatespec)
and [events-kafka plugin documentation](https://gerrit.googlesource.com/plugins/events-kafka/+/refs/heads/master/src/main/resources/Documentation/config.md)
* Zookeeper should be deployed or accessible from the cluster. The connection string is defined
within the `spec.refdb` object, i.e:
```
refdb:
database: ZOOKEEPER
zookeeper:
connectString: zookeeper-service.kafka-zk.svc.cluster.local:2181
```
For additional context, please refer to the section [GlobalRefDbConfig](operator-api-reference.md#globalrefdbconfig).
### Build images
Please read the previous section [Build images](#build-images).
### Istio
Please read the previous section [Istio](#istio).
### Gerrit Operator
To install the operator in the 'multisite' cluster mode please note that the value of the property
`cluster.mode` in the file `helm-charts/gerrit-operator/values.yaml`
should be set to `MULTISITE`.
Deploy the operator:
```sh
kubectl create ns gerrit-operator
helm dependency build --verify helm-charts/gerrit-operator
helm upgrade \
--install gerrit-operator \
helm-charts/gerrit-operator \
-n gerrit-operator \
--set=ingress.type=ISTIO \
--set=cluster.mode=MULTISITE
```
### Deploy multisite with three replicas
Deploy GerritCluster custom resource that:
* Creates a StatefulSet with three nodes
* Configure networking and traffic management for Http and Ssh
* Set up pull replication configuration
```sh
kubectl create ns gerrit
kubectl label namespace gerrit istio-injection=enabled
kubectl apply -f Documentation/examples/gerritcluster-roles.yaml
kubectl apply -f Documentation/examples/gerritcluster-3-nodes-pr-kafka-multisite.yaml
```
To access Gerrit, a tunnel has to be established to the Istio Ingressgateway
service and the host. This should be done in a separate shell session.
```sh
minikube tunnel
```
Please note that in this example the host is defined as `gerrit.multisite.com` in the
property `spec.ingress.host`. That implies to modify the `/etc/hosts` as follow:
```
127.0.0.1 localhost gerrit.multisite.com
```
## Multisite notes
This chapter is intended as a collection of resources for the usage of the operator
with the the property `multisite.enabled` set to true, not necessarily in minikube.
### Istio
When using the operator in a proper kubernetes cluster (not minikube) with multiple nodes, please
make sure to patch the gatway as follow:
```sh
kubectl patch svc istio-ingressgateway -n istio-system -p '{"spec":{"externalTrafficPolicy":"Local"}}'
```
Please read more on how to preserve the original client source IP on the [istio ingress](https://istio.io/latest/docs/tasks/security/authorization/authz-ingress/)
### Kafka
An example of a kafka deployment can be found
[here](https://github.com/lydtechconsulting/kafka-kubernetes-demo/blob/v1.0.0/resources/kafka.yml).
When installing it, make sure to set the namespace as described in the [Prerequisites](#prerequisites-2).
To connect and excecute operations in kafka, please spin up an image as client:
```sh
kubectl \
run my-kafka \
--rm \
-i \
--tty \
--image confluentinc/cp-kafka /bin/bash \
--namespace gerrit
```
fter that it is possible to connect to the image to test consuming of the messages in a topic, i.e.
for the `gerrit` topic:
```sh
kubectl \
--namespace gerrit \
exec \
--stdin \
--tty \
my-kafka -- \
/bin/kafka-console-consumer \
--bootstrap-server kafka-service.kafka-zk.svc.cluster.local:9092 \
--from-beginning \
--topic gerrit
```
Or to list all the topics:
```sh
kubectl \
--namespace gerrit \
exec \
--stdin \
--tty \
my-kafka -- \
/bin/kafka-topics \
--bootstrap-server kafka-service.kafka-zk.svc.cluster.local:9092 \
--list
```
Or to list the group_ids:
```sh
kubectl \
--namespace gerrit \
exec \
--stdin \
--tty \
my-kafka -- \
/bin/kafka-consumer-groups --bootstrap-server kafka-service.kafka-zk.svc.cluster.local:9092 \
--list
```
### Zookeeper
An example of kafka deployment can be found
[here](https://github.com/lydtechconsulting/kafka-kubernetes-demo/blob/v1.0.0/resources/zookeeper.yml),
making sure to set the namespace as described in the [Prerequisites](#prerequisites-2).
To connect and excecute operations in zookeeper, for example to check the sha stored in globalrefdb
for the meta ref for the change 1, on the `poc-demo` project
`/gerrit/gerrit/poc-demo/refs/changes/01/1/meta` you can use this command:
```sh
kubectl \
--namespace gerrit \
exec \
--stdin \
--tty \
my-kafka -- \
zookeeper-shell \
zookeeper-service.kafka-zk.svc.cluster.local:2181 \
get /gerrit/gerrit/poc-demo/refs/changes/01/1/meta
```
### Sync Gerrit sites
Because in a multisite environment, each gerrit instance is initialized during the `gerrit-init`
phase, the status of the repositories, in particular, the `All-Users` and `All-Projects` is not
consistent across the nodes. To fix this, a manual operation to sync all the sites is required. We
can leverage pull replication to do this, i.e.:
* Forward port 8080 for Gerrit-1 (without passing by the ingress-gatway):
```sh
kubectl port-forward gerrit-1 8080:8080 -n gerrit
```
* Add the ssh key to gerrit-1
```sh
curl -v -X POST -H "Content-Type: text/plain" --user admin:secret --data "$(cat ~/.ssh/id_ed25519.pub)" http://localhost:8080/a/accounts/self/sshkeys
```
* Forward the port 29418 to gerrit-1
```sh
kubectl port-forward gerrit-1 29418:29418 -n gerrit
```
* Start pull replication for Gerrit-1 (pull from gerrit-0)
```sh
ssh -p 29418 admin@localhost pull-replication start --url gerrit-0 --all
```
And finally repeat the process for gerrit-2.
You can also log in to each gerrit node and make sure that all the refs have the same sha in the
`All-Projects` and `All-Users` repositories with the command `git show-ref`.
## Multisite monitoring
This chapter provides an example to provision the [Prometheus stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) in the Minikube cluster.
This stack allows to define [Grafana dashboards](https://grafana.com/grafana/dashboards/), and query
metrics via [Prometheus](https://prometheus.io/) using [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) and to define alerts via [AlerManager](https://prometheus.io/docs/alerting/latest/alertmanager/).
### Prerequisites
1. Install the `Prometheus stack Helm chart` locally:
```sh
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
```
2. Deploy the `Prometheus stack`:
```sh
kubectl create ns monitoring && \
helm install my-kubpromstack prometheus-community/kube-prometheus-stack -n monitoring \
--set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
--set prometheus.prometheusSpec.probeSelectorNilUsesHelmValues=false \
--set prometheus.prometheusSpec.ruleSelectorNilUsesHelmValues=false \
--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false \
--set defaultRules.create=false \
--set grafana.defaultDashboardsEnabled=false
```
3. Deploy `PodMonitor` Custom Resource to allow `Prometheus` to scrap Gerrit metrics from the
different Gerrit instnces:
```sh
apiVersion: v1
kind: Secret
metadata:
name: gerrit-metric-bearer-token
namespace: gerrit
type: Opaque
data:
bearer-token: Secret
---
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: gerrit-multisite
namespace: gerrit
labels:
team: devops
spec:
selector:
matchLabels:
app.kubernetes.io/component: gerrit-statefulset-gerrit
app.kubernetes.io/instance: gerrit
app.kubernetes.io/managed-by: gerrit-operator
app.kubernetes.io/name: gerrit
app.kubernetes.io/part-of: gerrit
podMetricsEndpoints:
- port: http
path: /plugins/metrics-reporter-prometheus/metrics
bearerTokenSecret:
name: gerrit-metric-bearer-token
key: bearer-token
```
### Access to Prometheus
```sh
kubectl port-forward prometheus-my-kubpromstack-kube-prome-prometheus-0 9090:9090 -n monitoring
```
### Access to Grafana
```sh
kubectl port-forward my-kubpromstack-grafana-5f8bcc9786-r6c8b 3000:3000 -n monitoring
```
Note: please check the `Grafana` pod name
### Access to AlertManager
```sh
kubectl port-forward alertmanager-my-kubpromstack-kube-prome-alertmanager-0 9093:9093 -n monitoring
```