blob: 8e7ef2763cf5317214df347b9362eb51ce625b76 [file] [log] [blame] [view]
# Gerrit high-availability plugin
This plugin allows deploying a cluster of multiple Gerrit masters
on the same data-center sharing the same ReviewDb and Git repositories.
Requirements for the Gerrit masters are:
- Gerrit v2.14.20 or later
- Externally mounted filesystem shared among the cluster
- ReviewDb on an external DataBase Server
- Load-balancer (HAProxy or similar)
## License
This plugin is released under the same Apache 2.0 license and copyright holders
as of the Gerrit Code Review project.
## How to build
Refer to the [build instructions in the plugin documentation](src/main/resources/Documentation/build.md).
## Sample configuration for two Gerrit masters in high-availability
Assuming that the Gerrit masters in the clusters are `gerrit-01.mycompany.com` and
`gerrit-02.mycompany.com`, listening on the HTTP port 8080, with a shared volume
mounted under `/shared`, see below the minimal configuration steps.
1. Install one Gerrit master on the first node (e.g. `gerrit-01.mycompany.com`) using an external
ReviewDb on a DB server and the repositories location under the shared volume (e.g. `/shared/git`).
Init the site in order to create the DB Schema and the initial repositories.
2. Copy all the files of the first Gerrit master onto the second node (e.g. `gerrit-02.mycompany.com`)
so that it points to the same ReviewDb and the same repositories location.
3. Install the high-availability plugin into the `$GERRIT_SITE/plugins` directory of both
the Gerrit servers.
4. On `gerrit-01.mycompany.com`, create the `$GERRIT_SITE/etc/high-availability.config` with
the following settings:
```
[main]
sharedDirectory = /shared
[peerInfo]
strategy = static
[peerInfo "static"]
url = http://gerrit-02.mycompany.com:8080
```
5. On `gerrit-02.mycompany.com`, create the `$GERRIT_SITE/etc/high-availability.config` with
the following settings:
```
[main]
sharedDirectory = /shared
[peerInfo]
strategy = static
[peerInfo "static"]
url = http://gerrit-01.mycompany.com:8080
```
For more details on the configuration settings, please refer to the
[high-availability configuration documentation](src/main/resources/Documentation/config.md).
## Load-balancing configuration
It is possible to distribute the incoming traffic to both Gerrit nodes using any software that can
perform load-balancing of the incoming connections.
The load-balancing of the HTTP traffic is at L7 (Application) while the
SSH traffic is balanced at L4 (Transport) level.
### Active-passive configuration
It is the simplest and safest configuration, where only one Gerrit master at a
time serves the incoming requests.
In case of failure of the primary master, the traffic is forwarded to the backup.
Assuming a load-balancing implemented using [HAProxy](http://www.haproxy.org/)
associated with the domain name `gerrit.mycompany.com`, exposing Gerrit cluster nodes
on ports, 80 (HTTP) and 29418 (SSH), see below the minimal configuration
steps
Add to the `haproxy.cfg` the frontend configurations associated with the HTTP
and SSH services:
```
frontend gerrit_http
bind *:80
mode http
default_backend gerrit_http_nodes
frontend gerrit_ssh
bind *:29418
mode tcp
default_backend gerrit_ssh_nodes
```
Add to the `haproxy.cfg` the backend configurations pointing to the Gerrit cluster
nodes:
```
backend gerrit_http_nodes
mode http
balance source
option forwardfor
default-server inter 10s fall 3 rise 2
option httpchk GET /config/server/version HTTP/1.0
http-check expect status 200
server gerrit_http_01 gerrit-01.mycompany.com:8080 check inter 10s
server gerrit_http_02 gerrit-01.mycompany.com:8080 check inter 10s backup
ackend ssh
mode tcp
option httpchk GET /config/server/version HTTP/1.0
http-check expect status 200
balance source
timeout connect 10s
timeout server 5m
server gerrit_ssh_01 gerrit-01.mycompany.com:29418 check port 8080 inter 10s fall 3 rise 2
server gerrit-ssh_02 gerrit-02.mycompany.com:29418 check port 8080 inter 10s fall 3 rise 2 backup
```
### Active-active configuration
This is an evolution of the previous active-passive configuration, where only one Gerrit master at a
time serves the HTTP write operations (PUT,POST,DELETE) while the remaining HTTP traffic is sent
to both.
In case of failure of one of the nodes, all the traffic is forwarded to the other node.
With regards to the SSH traffic, it cannot be safely sent to both nodes because it is associated
with a stateful session that can host multiple commands of different nature.
Assuming an active-passive configuration using HAProxy, see below the changes needed to implement
an active-active scenario.
Add to the `haproxy.cfg` the extra acl settings into the `gerrit_http` frontend configurations
associated with the HTTP and SSH services:
```
frontend gerrit_http
bind *:80
mode http
acl http_writes method PUT POST DELETE PATCH
use_backend gerrit_http_nodes if http_writes
default_backend gerrit_http_nodes_balanced
```
Add to the `haproxy.cfg` a new backend for serving all read-only HTTP operations from both nodes:
```
backend gerrit_http_nodes_balanced
mode http
balance source
option forwardfor
default-server inter 10s fall 3 rise 2
option httpchk GET /config/server/version HTTP/1.0
http-check expect status 200
server gerrit_http_01 gerrit-01.mycompany.com:8080 check inter 10s
server gerrit_http_02 gerrit-01.mycompany.com:8080 check inter 10s
```
## Gerrit canonical URL and further adjustments
Both Gerrit masters are now part of the same cluster, accessible through the HAProxy load-balancer.
Set the `gerrit.canoncalWebUrl` on both Gerrit masters to the domain name of HAProxy so that any
location or URL generated by Gerrit would direct the traffic to the balancer and not to the instance
that served the incoming call.
Example:
```
[gerrit]
canonicalWebUrl = http://gerrit.mycompany.com
```
Secondly, adjust the HTTP listen configuration adding the `proxy-` prefix, to inform Gerrit that
the traffic is getting filtered through a reverse proxy.
Example:
```
[httpd]
listenUrl = proxy-http://*:8080/
```
Last adjustment is associated with the session cookies, because they would need to be bound to
the domain rather than the individual node.
Example:
```
[auth]
cookiedomain = .mycompany.com
```