A container image for garbd, the MariaDB Galera arbitrator. It joins a cluster
as a voting member that stores no data.
docker run --network host ghcr.io/wouter0100/galera-arbitrator:v0.1.0 \
--address "gcomm://10.0.0.1,10.0.0.2" \
--group "My Production cluster" \
--name arbitrator \
--log /dev/stdout
garbd ships in galera-arbitrator-4, which the official mariadb image does not
install — it has galera-4, the replication provider, and nothing else. The images
on Docker Hub are all personal namespaces with no provenance, which is not what you
want holding a vote in a production cluster. So this builds garbd from the same
mariadb.org repository the database hosts install from.
A two-node Galera cluster has no fault tolerance. Losing either node leaves one of two members, which is not a majority, so the survivor drops out of the primary component and goes read-only — precisely when you needed it to keep serving. An arbitrator is a third vote, so the survivor holds two of three and stays writable. It participates in group communication and certification but keeps no dataset, so it can run somewhere far cheaper than a database node.
It cannot be a donor for a state transfer, and it does not reduce the need for backups: three votes, two copies of the data.
GALERA_VERSION is pinned to the galera-4 version on the data nodes, because all
members of a cluster speak one group communication protocol. Build a matching
image when the data nodes are upgraded:
docker build --build-arg GALERA_VERSION=26.4.28-ubu2404 -t galera-arbitrator:test .
MARIADB_SERIES selects the repository the package comes from (default 11.4),
and MARIADB_MIRROR the mirror.
Galera is a full mesh: every member must be able to open a TCP connection to every
other on 4567. That is the constraint that decides how this is deployed. In
Kubernetes, whether a pod address is enough depends on the CNI: with Cilium in
native routing mode and masquerading off, members outside the cluster can route to
a pod address and see it as the source, so ordinary pod networking works. Where pod
addresses are not routable from the other members, or egress is masqueraded, the
pod needs hostNetwork: true instead. Test both directions before assuming
either.
For the GoodMoovs production cluster this runs as
custom-database-arbitrator.yaml in the gitops repository under
cap/gm/clusters/production.