Skip to content

Commit 5fbf4c6

Browse files
tymonxgrooverdan
authored andcommitted
Support Galera Replication
This patch add support for Galera replication. Features: - It detects if Galera replication was enabled wsrep_on=ON - By default it enables cluster auto bootstrap feature - By default the first cluster node is used for cluster auto bootstrapping based on the wsrep_cluster_address parameter 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 MariaDB configuration file `galera.cnf`: ```plaintext [galera] wsrep_on = ON wsrep_sst_method = mariabackup wsrep_provider = /usr/lib/libgalera_smm.so binlog_format = row default_storage_engine = InnoDB innodb_doublewrite = 1 innodb_autoinc_lock_mode = 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:-}" MARIADB_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 MariaDB configuration file: ```plaintext docker-compose --project-name db up --scale node="$(grep -i wsrep_cluster_address <name>.cnf | tr -d ' ' | tr ',' ' ' | wc -w)" ``` Closes: #28
1 parent 3805a68 commit 5fbf4c6

8 files changed

+608
-0
lines changed

10.2/docker-entrypoint.sh

+76
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() {
449449
return 1
450450
}
451451

452+
# usage: docker_hostname_match <hostname>
453+
# ie: docker_hostname_match node1.cluster.local
454+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
455+
docker_hostname_match() {
456+
for hostname in $(hostname --all-fqdns) $(hostname --alias); do
457+
if [ "$hostname" = "$1" ]; then
458+
return 0
459+
fi
460+
done
461+
462+
return 1
463+
}
464+
465+
# usage: docker_ip_match <ip>
466+
# ie: docker_ip_match 192.168.1.13
467+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
468+
docker_ip_match() {
469+
for ip in $(hostname --all-ip-addresses); do
470+
if [ "$ip" = "$1" ]; then
471+
return 0
472+
fi
473+
done
474+
475+
return 1
476+
}
477+
478+
# usage: docker_address_match <ip|hostname>
479+
# ie: docker_address_match node1
480+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
481+
docker_address_match() {
482+
local resolved
483+
resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
484+
485+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
486+
}
487+
488+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
489+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
490+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
491+
wsrep_enable_new_cluster() {
492+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"
493+
shift
494+
local wsrepdir
495+
wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
496+
497+
# it removes URI schemes like gcomm://
498+
address="${address#[[:graph:]]*://}"
499+
# Removing trailing options after literal "?"
500+
address="${address%%\?*}"
501+
502+
# it replaces commas ',' with spaces ' ' and converts it to array
503+
IFS=" ," read -r -a address <<< "$address"
504+
505+
(( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
506+
}
507+
452508
# check arguments for an option that would cause mysqld to stop
453509
# return true if there is one
454510
_mysql_want_help() {
@@ -513,6 +569,26 @@ _main() {
513569
elif _check_if_upgrade_is_needed; then
514570
docker_mariadb_upgrade "$@"
515571
fi
572+
573+
# check if Galera replication is enabled from configuration files or command line arguments
574+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
575+
mysql_note "Galera replication is enabled"
576+
577+
# determine cluster nodes addresses
578+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
579+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
580+
else
581+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
582+
fi
583+
584+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
585+
586+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
587+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
588+
mysql_note "Enabled Galera cluster bootstrapping for this node"
589+
set -- "$@" --wsrep-new-cluster
590+
fi
591+
fi
516592
fi
517593
exec "$@"
518594
}

10.3/docker-entrypoint.sh

+76
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() {
449449
return 1
450450
}
451451

452+
# usage: docker_hostname_match <hostname>
453+
# ie: docker_hostname_match node1.cluster.local
454+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
455+
docker_hostname_match() {
456+
for hostname in $(hostname --all-fqdns) $(hostname --alias); do
457+
if [ "$hostname" = "$1" ]; then
458+
return 0
459+
fi
460+
done
461+
462+
return 1
463+
}
464+
465+
# usage: docker_ip_match <ip>
466+
# ie: docker_ip_match 192.168.1.13
467+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
468+
docker_ip_match() {
469+
for ip in $(hostname --all-ip-addresses); do
470+
if [ "$ip" = "$1" ]; then
471+
return 0
472+
fi
473+
done
474+
475+
return 1
476+
}
477+
478+
# usage: docker_address_match <ip|hostname>
479+
# ie: docker_address_match node1
480+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
481+
docker_address_match() {
482+
local resolved
483+
resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
484+
485+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
486+
}
487+
488+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
489+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
490+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
491+
wsrep_enable_new_cluster() {
492+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"
493+
shift
494+
local wsrepdir
495+
wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
496+
497+
# it removes URI schemes like gcomm://
498+
address="${address#[[:graph:]]*://}"
499+
# Removing trailing options after literal "?"
500+
address="${address%%\?*}"
501+
502+
# it replaces commas ',' with spaces ' ' and converts it to array
503+
IFS=" ," read -r -a address <<< "$address"
504+
505+
(( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
506+
}
507+
452508
# check arguments for an option that would cause mysqld to stop
453509
# return true if there is one
454510
_mysql_want_help() {
@@ -513,6 +569,26 @@ _main() {
513569
elif _check_if_upgrade_is_needed; then
514570
docker_mariadb_upgrade "$@"
515571
fi
572+
573+
# check if Galera replication is enabled from configuration files or command line arguments
574+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
575+
mysql_note "Galera replication is enabled"
576+
577+
# determine cluster nodes addresses
578+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
579+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
580+
else
581+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
582+
fi
583+
584+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
585+
586+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
587+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
588+
mysql_note "Enabled Galera cluster bootstrapping for this node"
589+
set -- "$@" --wsrep-new-cluster
590+
fi
591+
fi
516592
fi
517593
exec "$@"
518594
}

10.4/docker-entrypoint.sh

+76
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() {
449449
return 1
450450
}
451451

452+
# usage: docker_hostname_match <hostname>
453+
# ie: docker_hostname_match node1.cluster.local
454+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
455+
docker_hostname_match() {
456+
for hostname in $(hostname --all-fqdns) $(hostname --alias); do
457+
if [ "$hostname" = "$1" ]; then
458+
return 0
459+
fi
460+
done
461+
462+
return 1
463+
}
464+
465+
# usage: docker_ip_match <ip>
466+
# ie: docker_ip_match 192.168.1.13
467+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
468+
docker_ip_match() {
469+
for ip in $(hostname --all-ip-addresses); do
470+
if [ "$ip" = "$1" ]; then
471+
return 0
472+
fi
473+
done
474+
475+
return 1
476+
}
477+
478+
# usage: docker_address_match <ip|hostname>
479+
# ie: docker_address_match node1
480+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
481+
docker_address_match() {
482+
local resolved
483+
resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
484+
485+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
486+
}
487+
488+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
489+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
490+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
491+
wsrep_enable_new_cluster() {
492+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"
493+
shift
494+
local wsrepdir
495+
wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
496+
497+
# it removes URI schemes like gcomm://
498+
address="${address#[[:graph:]]*://}"
499+
# Removing trailing options after literal "?"
500+
address="${address%%\?*}"
501+
502+
# it replaces commas ',' with spaces ' ' and converts it to array
503+
IFS=" ," read -r -a address <<< "$address"
504+
505+
(( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
506+
}
507+
452508
# check arguments for an option that would cause mysqld to stop
453509
# return true if there is one
454510
_mysql_want_help() {
@@ -513,6 +569,26 @@ _main() {
513569
elif _check_if_upgrade_is_needed; then
514570
docker_mariadb_upgrade "$@"
515571
fi
572+
573+
# check if Galera replication is enabled from configuration files or command line arguments
574+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
575+
mysql_note "Galera replication is enabled"
576+
577+
# determine cluster nodes addresses
578+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
579+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
580+
else
581+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
582+
fi
583+
584+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
585+
586+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
587+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
588+
mysql_note "Enabled Galera cluster bootstrapping for this node"
589+
set -- "$@" --wsrep-new-cluster
590+
fi
591+
fi
516592
fi
517593
exec "$@"
518594
}

10.5/docker-entrypoint.sh

+76
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() {
449449
return 1
450450
}
451451

452+
# usage: docker_hostname_match <hostname>
453+
# ie: docker_hostname_match node1.cluster.local
454+
# it returns true if provided hostname match with container hostname. Otherwise it returns false
455+
docker_hostname_match() {
456+
for hostname in $(hostname --all-fqdns) $(hostname --alias); do
457+
if [ "$hostname" = "$1" ]; then
458+
return 0
459+
fi
460+
done
461+
462+
return 1
463+
}
464+
465+
# usage: docker_ip_match <ip>
466+
# ie: docker_ip_match 192.168.1.13
467+
# it returns true if provided IP address match with container IP address. Otherwise it returns false
468+
docker_ip_match() {
469+
for ip in $(hostname --all-ip-addresses); do
470+
if [ "$ip" = "$1" ]; then
471+
return 0
472+
fi
473+
done
474+
475+
return 1
476+
}
477+
478+
# usage: docker_address_match <ip|hostname>
479+
# ie: docker_address_match node1
480+
# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false
481+
docker_address_match() {
482+
local resolved
483+
resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa
484+
485+
docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1"
486+
}
487+
488+
# usage: wsrep_enable_new_cluster <wsrep-cluster-address> [arg [arg [...]]]
489+
# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@"
490+
# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false
491+
wsrep_enable_new_cluster() {
492+
local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}"
493+
shift
494+
local wsrepdir
495+
wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")"
496+
497+
# it removes URI schemes like gcomm://
498+
address="${address#[[:graph:]]*://}"
499+
# Removing trailing options after literal "?"
500+
address="${address%%\?*}"
501+
502+
# it replaces commas ',' with spaces ' ' and converts it to array
503+
IFS=" ," read -r -a address <<< "$address"
504+
505+
(( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}"
506+
}
507+
452508
# check arguments for an option that would cause mysqld to stop
453509
# return true if there is one
454510
_mysql_want_help() {
@@ -513,6 +569,26 @@ _main() {
513569
elif _check_if_upgrade_is_needed; then
514570
docker_mariadb_upgrade "$@"
515571
fi
572+
573+
# check if Galera replication is enabled from configuration files or command line arguments
574+
if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then
575+
mysql_note "Galera replication is enabled"
576+
577+
# determine cluster nodes addresses
578+
if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then
579+
WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")"
580+
else
581+
set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}"
582+
fi
583+
584+
mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}"
585+
586+
# determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped
587+
if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then
588+
mysql_note "Enabled Galera cluster bootstrapping for this node"
589+
set -- "$@" --wsrep-new-cluster
590+
fi
591+
fi
516592
fi
517593
exec "$@"
518594
}

0 commit comments

Comments
 (0)