Skip to content

Commit 1bc7b80

Browse files
committed
It fixes MariaDB#28 Support Galera Replication
This patch add support for Galera replication. Features: - it detects if Galera replication was enabled using `mysql` configuration files or provided `mysqld` command line arguments - on default it enables cluster auto bootstrap feature - on default the first cluster node is used for cluster auto bootstrapping based on the wsrep_cluster_address parameter from `mysql` configuration files, `mysqld` command line arguments or by setting the `WSREP_CLUSTER_ADDRESS` environment variable - cluster auto bootstrap feature can be disabled by setting the `WSREP_SKIP_AUTO_BOOTSTRAP` environment variable - use the `WSREP_AUTO_BOOTSTRAP_ADDRESS` environment variable to explicitly choice other node for cluster bootstrapping - cluster node hostnames or IP addresses must be valid to enable cluster auto bootstrapping How to use it. 1. Prepare `mysql` configuration file `galera.cnf`: ```plaintext [galera] wsrep_on = ON wsrep_sst_method = rsync wsrep_provider = /usr/lib/libgalera_smm.so bind-address = 0.0.0.0 binlog_format = row default_storage_engine = InnoDB innodb_doublewrite = 1 innodb_autoinc_lock_mode = 2 innodb_flush_log_at_trx_commit = 2 ``` 2. Make it read-only: ```plaintext chmod 444 galera.cnf ``` 3. Prepare Docker Compose file `docker-compose.yml`: ```yaml services: node: image: mariadb restart: always security_opt: - label=disable environment: WSREP_CLUSTER_ADDRESS: "${WSREP_CLUSTER_ADDRESS:-}" MYSQL_ROOT_PASSWORD: example volumes: - ./galera.cnf:/etc/mysql/conf.d/10-galera.cnf:ro command: - --wsrep-cluster-address=gcomm://db_node_1,db_node_2,db_node_3 deploy: replicas: 3 ``` 4. Start Docker Compose: ```plaintext docker-compose --project-name db up ``` To start N MariaDB instances using environment variable: ```plaintext WSREP_CLUSTER_ADDRESS="gcomm://db_node_1,db_node_2,db_node_3,db_node_4,db_node_5" docker-compose --project-name db up --scale node="$(echo "${WSREP_CLUSTER_ADDRESS}" | tr ',' ' ' | wc -w)" ``` To start N MariaDB instances using `mysql` configuration file: ```plaintext docker-compose --project-name db up --scale node="$(grep -i wsrep_cluster_address <name>.cnf | tr -d ' ' | tr ',' ' ' | wc -w)" ```
1 parent 6f5d272 commit 1bc7b80

6 files changed

+426
-0
lines changed

10.2/docker-entrypoint.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,57 @@ docker_setup_db() {
329329
fi
330330
}
331331

332+
# usage: docker_hostname_match <hostname>
333+
# ie: docker_hostname_match node1.cluster.local
334+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
335+
docker_hostname_match() {
336+
for hostname in $(hostname --all-fqdns); do
337+
if [ "$hostname" = "$1" ]; then
338+
return 0
339+
fi
340+
done
341+
342+
return 1
343+
}
344+
345+
# usage: docker_ip_match <ip>
346+
# ie: docker_ip_match 192.168.1.13
347+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
348+
docker_ip_match() {
349+
for ip in $(hostname --all-ip-addresses); do
350+
if [ "$ip" = "$1" ]; then
351+
return 0
352+
fi
353+
done
354+
355+
return 1
356+
}
357+
358+
# usage: docker_address_match <ip|hostname>
359+
# ie: docker_address_match node1
360+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
361+
docker_address_match() {
362+
local resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
363+
364+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
365+
}
366+
367+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
368+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
369+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
370+
wsrep_enable_new_cluster() {
371+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"; shift
372+
local wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
373+
374+
# it removes URI schemes like gcomm://
375+
address="${address#[[:graph:]]*://}"
376+
377+
# it replaces commas ',' with spaces ' ' and converts it to array
378+
address=( ${address//,/ } )
379+
380+
[ -n "$address" ] && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
381+
}
382+
332383
# check arguments for an option that would cause mysqld to stop
333384
# return true if there is one
334385
_mysql_want_help() {
@@ -388,6 +439,26 @@ _main() {
388439
mysql_note "MariaDB init process done. Ready for start up."
389440
echo
390441
fi
442+
443+
# check if Galera replication is enabled from configuration files or command line arguments
444+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
445+
mysql_note "Galera replication is enabled"
446+
447+
# determine cluster nodes addresses
448+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
449+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
450+
else
451+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
452+
fi
453+
454+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
455+
456+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
457+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
458+
mysql_note "Enabled Galera cluster bootstrapping for this node"
459+
set -- "$@" --wsrep-new-cluster
460+
fi
461+
fi
391462
fi
392463
exec "$@"
393464
}

10.3/docker-entrypoint.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,57 @@ docker_setup_db() {
329329
fi
330330
}
331331

332+
# usage: docker_hostname_match <hostname>
333+
# ie: docker_hostname_match node1.cluster.local
334+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
335+
docker_hostname_match() {
336+
for hostname in $(hostname --all-fqdns); do
337+
if [ "$hostname" = "$1" ]; then
338+
return 0
339+
fi
340+
done
341+
342+
return 1
343+
}
344+
345+
# usage: docker_ip_match <ip>
346+
# ie: docker_ip_match 192.168.1.13
347+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
348+
docker_ip_match() {
349+
for ip in $(hostname --all-ip-addresses); do
350+
if [ "$ip" = "$1" ]; then
351+
return 0
352+
fi
353+
done
354+
355+
return 1
356+
}
357+
358+
# usage: docker_address_match <ip|hostname>
359+
# ie: docker_address_match node1
360+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
361+
docker_address_match() {
362+
local resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
363+
364+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
365+
}
366+
367+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
368+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
369+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
370+
wsrep_enable_new_cluster() {
371+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"; shift
372+
local wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
373+
374+
# it removes URI schemes like gcomm://
375+
address="${address#[[:graph:]]*://}"
376+
377+
# it replaces commas ',' with spaces ' ' and converts it to array
378+
address=( ${address//,/ } )
379+
380+
[ -n "$address" ] && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
381+
}
382+
332383
# check arguments for an option that would cause mysqld to stop
333384
# return true if there is one
334385
_mysql_want_help() {
@@ -388,6 +439,26 @@ _main() {
388439
mysql_note "MariaDB init process done. Ready for start up."
389440
echo
390441
fi
442+
443+
# check if Galera replication is enabled from configuration files or command line arguments
444+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
445+
mysql_note "Galera replication is enabled"
446+
447+
# determine cluster nodes addresses
448+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
449+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
450+
else
451+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
452+
fi
453+
454+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
455+
456+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
457+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
458+
mysql_note "Enabled Galera cluster bootstrapping for this node"
459+
set -- "$@" --wsrep-new-cluster
460+
fi
461+
fi
391462
fi
392463
exec "$@"
393464
}

10.4/docker-entrypoint.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,57 @@ docker_setup_db() {
329329
fi
330330
}
331331

332+
# usage: docker_hostname_match <hostname>
333+
# ie: docker_hostname_match node1.cluster.local
334+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
335+
docker_hostname_match() {
336+
for hostname in $(hostname --all-fqdns); do
337+
if [ "$hostname" = "$1" ]; then
338+
return 0
339+
fi
340+
done
341+
342+
return 1
343+
}
344+
345+
# usage: docker_ip_match <ip>
346+
# ie: docker_ip_match 192.168.1.13
347+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
348+
docker_ip_match() {
349+
for ip in $(hostname --all-ip-addresses); do
350+
if [ "$ip" = "$1" ]; then
351+
return 0
352+
fi
353+
done
354+
355+
return 1
356+
}
357+
358+
# usage: docker_address_match <ip|hostname>
359+
# ie: docker_address_match node1
360+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
361+
docker_address_match() {
362+
local resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
363+
364+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
365+
}
366+
367+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
368+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
369+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
370+
wsrep_enable_new_cluster() {
371+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"; shift
372+
local wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
373+
374+
# it removes URI schemes like gcomm://
375+
address="${address#[[:graph:]]*://}"
376+
377+
# it replaces commas ',' with spaces ' ' and converts it to array
378+
address=( ${address//,/ } )
379+
380+
[ -n "$address" ] && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
381+
}
382+
332383
# check arguments for an option that would cause mysqld to stop
333384
# return true if there is one
334385
_mysql_want_help() {
@@ -388,6 +439,26 @@ _main() {
388439
mysql_note "MariaDB init process done. Ready for start up."
389440
echo
390441
fi
442+
443+
# check if Galera replication is enabled from configuration files or command line arguments
444+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
445+
mysql_note "Galera replication is enabled"
446+
447+
# determine cluster nodes addresses
448+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
449+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
450+
else
451+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
452+
fi
453+
454+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
455+
456+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
457+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
458+
mysql_note "Enabled Galera cluster bootstrapping for this node"
459+
set -- "$@" --wsrep-new-cluster
460+
fi
461+
fi
391462
fi
392463
exec "$@"
393464
}

10.5/docker-entrypoint.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,57 @@ docker_setup_db() {
329329
fi
330330
}
331331

332+
# usage: docker_hostname_match <hostname>
333+
# ie: docker_hostname_match node1.cluster.local
334+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
335+
docker_hostname_match() {
336+
for hostname in $(hostname --all-fqdns); do
337+
if [ "$hostname" = "$1" ]; then
338+
return 0
339+
fi
340+
done
341+
342+
return 1
343+
}
344+
345+
# usage: docker_ip_match <ip>
346+
# ie: docker_ip_match 192.168.1.13
347+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
348+
docker_ip_match() {
349+
for ip in $(hostname --all-ip-addresses); do
350+
if [ "$ip" = "$1" ]; then
351+
return 0
352+
fi
353+
done
354+
355+
return 1
356+
}
357+
358+
# usage: docker_address_match <ip|hostname>
359+
# ie: docker_address_match node1
360+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
361+
docker_address_match() {
362+
local resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
363+
364+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
365+
}
366+
367+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
368+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
369+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
370+
wsrep_enable_new_cluster() {
371+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"; shift
372+
local wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
373+
374+
# it removes URI schemes like gcomm://
375+
address="${address#[[:graph:]]*://}"
376+
377+
# it replaces commas ',' with spaces ' ' and converts it to array
378+
address=( ${address//,/ } )
379+
380+
[ -n "$address" ] && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
381+
}
382+
332383
# check arguments for an option that would cause mysqld to stop
333384
# return true if there is one
334385
_mysql_want_help() {
@@ -388,6 +439,26 @@ _main() {
388439
mysql_note "MariaDB init process done. Ready for start up."
389440
echo
390441
fi
442+
443+
# check if Galera replication is enabled from configuration files or command line arguments
444+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
445+
mysql_note "Galera replication is enabled"
446+
447+
# determine cluster nodes addresses
448+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
449+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
450+
else
451+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
452+
fi
453+
454+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
455+
456+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
457+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
458+
mysql_note "Enabled Galera cluster bootstrapping for this node"
459+
set -- "$@" --wsrep-new-cluster
460+
fi
461+
fi
391462
fi
392463
exec "$@"
393464
}

0 commit comments

Comments
 (0)