From 5fbf4c6f13813a271631fc1f8e3a3c28fe2943ba Mon Sep 17 00:00:00 2001 From: Tymoteusz Blazejczyk Date: Fri, 21 May 2021 13:20:34 +0200 Subject: [PATCH] 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 .cnf | tr -d ' ' | tr ',' ' ' | wc -w)" ``` Closes: #28 --- 10.2/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 10.3/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 10.4/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 10.5/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 10.6/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 10.7/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 10.8/docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ docker-entrypoint.sh | 76 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 608 insertions(+) diff --git a/10.2/docker-entrypoint.sh b/10.2/docker-entrypoint.sh index ea43470f..dbb59fee 100755 --- a/10.2/docker-entrypoint.sh +++ b/10.2/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mysqld to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/10.3/docker-entrypoint.sh b/10.3/docker-entrypoint.sh index ea43470f..dbb59fee 100755 --- a/10.3/docker-entrypoint.sh +++ b/10.3/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mysqld to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/10.4/docker-entrypoint.sh b/10.4/docker-entrypoint.sh index ea43470f..dbb59fee 100755 --- a/10.4/docker-entrypoint.sh +++ b/10.4/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mysqld to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/10.5/docker-entrypoint.sh b/10.5/docker-entrypoint.sh index ea43470f..dbb59fee 100755 --- a/10.5/docker-entrypoint.sh +++ b/10.5/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mysqld to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/10.6/docker-entrypoint.sh b/10.6/docker-entrypoint.sh index 1a7f4ca1..4451154f 100755 --- a/10.6/docker-entrypoint.sh +++ b/10.6/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mariadbd. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mariadbd to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/10.7/docker-entrypoint.sh b/10.7/docker-entrypoint.sh index 1a7f4ca1..4451154f 100755 --- a/10.7/docker-entrypoint.sh +++ b/10.7/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mariadbd. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mariadbd to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/10.8/docker-entrypoint.sh b/10.8/docker-entrypoint.sh index 1a7f4ca1..4451154f 100755 --- a/10.8/docker-entrypoint.sh +++ b/10.8/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mariadbd. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mariadbd to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" } diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index ea43470f..dbb59fee 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -449,6 +449,62 @@ _check_if_upgrade_is_needed() { return 1 } +# usage: docker_hostname_match +# ie: docker_hostname_match node1.cluster.local +# it returns true if provided hostname match with container hostname. Otherwise it returns false +docker_hostname_match() { + for hostname in $(hostname --all-fqdns) $(hostname --alias); do + if [ "$hostname" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_ip_match +# ie: docker_ip_match 192.168.1.13 +# it returns true if provided IP address match with container IP address. Otherwise it returns false +docker_ip_match() { + for ip in $(hostname --all-ip-addresses); do + if [ "$ip" = "$1" ]; then + return 0 + fi + done + + return 1 +} + +# usage: docker_address_match +# ie: docker_address_match node1 +# it returns true if provided value match with container IP address or container hostname. Otherwise it returns false +docker_address_match() { + local resolved + resolved="$(resolveip --silent "$1" 2>/dev/null)" # it converts hostname to ip or vice versa + + docker_ip_match "$resolved" || docker_ip_match "$1" || docker_hostname_match "$resolved" || docker_hostname_match "$1" +} + +# usage: wsrep_enable_new_cluster [arg [arg [...]]] +# ie: wsrep_enable_new_cluster gcomm://node1,node2,node3 "$@" +# it returns true if we need to set the --wsrep-new-cluster argument for the mysqld. Otherwise it returns false +wsrep_enable_new_cluster() { + local address="${WSREP_AUTO_BOOTSTRAP_ADDRESS:-$1}" + shift + local wsrepdir + wsrepdir="$(mysql_get_config 'wsrep-data-home-dir' "$@")" + + # it removes URI schemes like gcomm:// + address="${address#[[:graph:]]*://}" + # Removing trailing options after literal "?" + address="${address%%\?*}" + + # it replaces commas ',' with spaces ' ' and converts it to array + IFS=" ," read -r -a address <<< "$address" + + (( ${#address[@]} )) && [ -z "$WSREP_SKIP_AUTO_BOOTSTRAP" ] && [ ! -s "$wsrepdir/gvwstate.dat" ] && docker_address_match "${address[0]}" +} + # check arguments for an option that would cause mysqld to stop # return true if there is one _mysql_want_help() { @@ -513,6 +569,26 @@ _main() { elif _check_if_upgrade_is_needed; then docker_mariadb_upgrade "$@" fi + + # check if Galera replication is enabled from configuration files or command line arguments + if [ "$(mysql_get_config wsrep-on "$@")" = "TRUE" ]; then + mysql_note "Galera replication is enabled" + + # determine cluster nodes addresses + if [ -z "${WSREP_CLUSTER_ADDRESS}" ]; then + WSREP_CLUSTER_ADDRESS="$(mysql_get_config wsrep-cluster-address "$@")" + else + set -- "$@" --wsrep-cluster-address="${WSREP_CLUSTER_ADDRESS}" + fi + + mysql_note "Galera cluster addresses ${WSREP_CLUSTER_ADDRESS}" + + # determine if this node is used for cluster bootstrapping. Skip it when cluster was already bootstrapped + if wsrep_enable_new_cluster "${WSREP_CLUSTER_ADDRESS}" "$@"; then + mysql_note "Enabled Galera cluster bootstrapping for this node" + set -- "$@" --wsrep-new-cluster + fi + fi fi exec "$@" }