Galera Cluster: Docker Deployment¶
This walks through a 3-node MariaDB Galera cluster on a single Docker host, using a dedicated bridge network with static IPs so wsrep_cluster_address can be set explicitly. See Overview for the concepts referenced below (bootstrapping, quorum, GTID).
1. Create the Network¶
docker network create --driver=bridge --subnet 172.16.0.0/16 galera-net
2. Create the Volumes¶
for n in 1 2 3; do docker volume create galera-node$n-data; done
galera-node1-data
galera-node2-data
galera-node3-data
3. Configuration¶
Create the config directories¶
mkdir -p ~/containers/galera_cluster/galera-node{1,2,3}-conf
galera-node1 — initial bootstrap config¶
Node 1 starts with an empty wsrep_cluster_address — this is what tells Galera to found a new cluster rather than join one:
cat <<EOF > galera-node1-conf/60-galera.cnf
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name="galera_cluster"
wsrep_cluster_address="gcomm://"
wsrep_sst_method=rsync
wsrep_node_name="galera-node1"
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
EOF
galera-node2 and galera-node3 config¶
Both point at the full peer list from the start, since they're joining rather than bootstrapping:
cat <<EOF > galera-node2-conf/60-galera.cnf
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name="galera_cluster"
wsrep_cluster_address="gcomm://172.16.0.101,172.16.0.102,172.16.0.103"
wsrep_sst_method=rsync
wsrep_node_name="galera-node2"
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
EOF
cat <<EOF > galera-node3-conf/60-galera.cnf
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name="galera_cluster"
wsrep_cluster_address="gcomm://172.16.0.101,172.16.0.102,172.16.0.103"
wsrep_sst_method=rsync
wsrep_node_name="galera-node3"
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
EOF
4. Bootstrap the First Node¶
docker run -it -d --net galera-net --name galera-node1 -h galera-node1 --ip 172.16.0.101 \
-e MYSQL_ROOT_PASSWORD=rootpass -e GALERA_NEW_CLUSTER=1 -v galera-node1-data:/var/lib/mysql \
-v ~/containers/databases/galera_cluster/galera-node1-conf/60-galera.cnf:/etc/mysql/mariadb.conf.d/60-galera.cnf:Z \
docker.io/library/mariadb:11.4
Verify the cluster came up with itself as the only member:
docker exec -it galera-node1 mariadb -h 172.16.0.101 -uroot -prootpass -e "SHOW GLOBAL STATUS LIKE 'wsrep_cluster_size';"
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 1 |
+--------------------+-------+
5. Reconfigure Node 1 Out of Bootstrap Mode¶
Stop and remove the bootstrap container:
docker stop galera-node1
docker rm galera-node1
Edit galera-node1-conf/60-galera.cnf so it no longer self-bootstraps on every future start — comment out the empty gcomm:// and switch to the full peer list, matching nodes 2 and 3:
[galera]
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_name="galera_cluster"
# wsrep_cluster_address="gcomm://" # <- comment this line out
wsrep_cluster_address="gcomm://172.16.0.101,172.16.0.102,172.16.0.103" # <- add all node IPs
wsrep_sst_method=rsync
wsrep_node_name="galera-node1"
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
This step matters: if node 1 keeps an empty gcomm://, restarting it later will silently found a second, divergent cluster instead of rejoining the existing one.
6. Start All Three Nodes¶
docker run -it -d --net galera-net --name galera-node1 -h galera-node1 --ip 172.16.0.101 \
-e MYSQL_ROOT_PASSWORD=rootpass -e GALERA_NEW_CLUSTER=1 -v galera-node1-data:/var/lib/mysql \
-v ~/containers/databases/galera_cluster/galera-node1-conf/60-galera.cnf:/etc/mysql/mariadb.conf.d/60-galera.cnf:Z \
docker.io/library/mariadb:11.4
docker run -it -d --net galera-net --name galera-node2 -h galera-node2 --ip 172.16.0.102 \
-e MYSQL_ROOT_PASSWORD=rootpass -v galera-node2-data:/var/lib/mysql \
-v ~/containers/databases/galera_cluster/galera-node2-conf/60-galera.cnf:/etc/mysql/mariadb.conf.d/60-galera.cnf:Z \
docker.io/library/mariadb:11.4
docker run -it -d --net galera-net --name galera-node3 -h galera-node3 --ip 172.16.0.103 \
-e MYSQL_ROOT_PASSWORD=rootpass -v galera-node3-data:/var/lib/mysql \
-v ~/containers/databases/galera_cluster/galera-node3-conf/60-galera.cnf:/etc/mysql/mariadb.conf.d/60-galera.cnf:Z \
docker.io/library/mariadb:11.4
Note node 2 and node 3 don't pass GALERA_NEW_CLUSTER=1 — only the founding node does.
7. Check Cluster Status¶
docker exec -it galera-node1 mariadb -h 172.16.0.101 -uroot -prootpass -e "SHOW GLOBAL STATUS LIKE 'wsrep_%';"
docker exec -it galera-node1 mariadb -h 172.16.0.101 -uroot -prootpass -e "SHOW GLOBAL STATUS LIKE 'wsrep_cluster_size';"
Reference: Galera cluster monitoring docs. Full variable-by-variable detail lives on the Monitoring page.
Personal status script¶
A pre-built status checker that surfaces the important cluster variables in one call:
docker pull registry.gitlab.com/myteam/galera_status:latest
docker run -it --rm registry.gitlab.com/andrewmercer/galera_status:latest python galera_status.py -c all
docker run -it --rm registry.gitlab.com/andrewmercer/galera_status:latest python galera_status.py --check [ option ]
Cleanup¶
for container in galera-node1 galera-node2 galera-node3; do docker stop $container && docker rm $container; done
docker network rm galera-net
for volume in galera-node1-data galera-node2-data galera-node3-data; do docker volume rm $volume; done
Troubleshooting Cross-Reference¶
Docker-specific issues (e.g. It may not be safe to bootstrap the cluster from this node) are covered in Troubleshooting.