MariaDB Galera Cluster en Contenedores Docker
Introducción
Vamos a construir un Cluster de Galera de tres nodos, 1 Primario y 2 Nodos, usando contenedores Docker en una virtual machine de la Google Cloud Platform. Previamente habiamos instalado y configurado un MariaDB Galera Cluster en Instancias Virtuales, esta vez lo vamos a construir usando contenedores.
Prerrequisitos
Un anfitrión de Docker en cualquier Sistema Operativo. Nosotros estamos usando una virtual machine instance en Google Cloud Platform con Container Optimized OS
el cual ya incluye el Docker 19.03
.
Contenedores para Cluster de Galera
Crear un Red de Docker
Con el fin de facilitar la referencia entre los nodos del cluster vamos a usar nuestra propia red de docker tipo bridge
previamente creada para que cada uno de los contenedores puedan encontrarse a través de su nombre:
pato@patocontainer ~ $ docker network create --driver bridge pato-net
522c4b821356e3b574f9150653adc325d5cb680b6d4fc7f64121d8fc9aa97530
pato@patocontainer ~ $ docker network ls
NETWORK ID NAME DRIVER SCOPE
...
522c4b821356 pato-net bridge local
Generar el Contenedor Primario a partir de nuestra Imagen Customizada
Creemos nuestro contenedor con el comando docker run
usando nuestra imagen personalizada patomx/patomariadb
.
Para más información sobre esta imagen visita Mi Imagen y Volumen de MariaDB en Docker.
Usaremos la red previamente creada --network pato-net
y le asignaremos una etiqueta al volumen para el datadir -v patovolgm:/var/lib/mysql
.
pato@patocontainer ~ $ docker run -d --name patomariagm --network pato-net -v patovolgm:/var/lib/mysql patomx/patomariadb
7cb4db2c49a927404ebd26ed0a7c9cbbdae8aa07374bcc4de222249bbaa288c9
pato@patocontainer ~ $ docker stop patomariagm
patomariagm
Una vez creado replicaremos los datos de nuestra base de datos customizada hacia el volumen del nuevo contenedor:
pato@patocontainer ~ $ docker run --rm -i -t -v patovolmariadb:/origen -v patovolgm:/destino alpine sh -c "cp -avr /origen/* /destino"
'/origen/aria_log.00000001' -> '/destino/aria_log.00000001'
'/origen/aria_log_control' -> '/destino/aria_log_control'
...
Iniciemos el contenedor y validemos que esté en ejecución:
pato@patocontainer ~ $ docker start patomariagm
patomariagm
pato@patocontainer ~ $ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7cb4db2c49a9 patomx/patomariadb "docker-entrypoint.s…" 12 seconds ago Up 10 seconds 3306/tcp patomariagm
pato@patocontainer ~ $ docker volume ls
DRIVER VOLUME NAME
local patovolgm
local patovolmariadb
Crear Objetos y Datos
Se espera que el nodo Primario sea el origen de los datos que queremos replicar en el cluster así que creemos algunos objetos y datos para nuestra prueba.
Accede a nuestro recién creado contenedor con una sesión shell usando docker exec -it patomariagm bash
.
pato@patocontainer ~ $ docker exec -it patomariagm bash
y entonces conéctate a MariaDB para crear una base de datos, una tabla e insertar un registro con la identificación del hostname y la hora:
root@7cb4db2c49a9:/# mysql
MariaDB [(none)]> create database taller;
Query OK, 1 row affected (0.000 sec)
MariaDB [(none)]> use taller
Database changed
MariaDB [taller]> create table tg1 (i1 int auto_increment primary key, c2 varchar(20), d3 datetime) ;
Query OK, 0 rows affected (0.056 sec)
MariaDB [taller]> insert into tg1 (c2,d3) values (@@hostname,now());
Query OK, 1 row affected (0.005 sec)
Construir los Nodos Secundarios para el Cluster
Creemos otros dos contenedores a partir de la misma imagen y validemos que estén en ejecución y que los volúmenes fueron creados:
pato@patocontainer ~ $ docker run -d --name patomariag1 --network pato-net -v patovolg1:/var/lib/mysql patomx/patomariadb
5f9ce8bc16d24f59bc25633faf538d5fe5d4886824b51ced1fdc55b87f0c4c2a
pato@patocontainer ~ $ docker run -d --name patomariag2 --network pato-net -v patovolg2:/var/lib/mysql patomx/patomariadb
18dda3dabdf9d867ee0d0289edc8417518c9171ee4890f19f285aef56cc0dbc6
pato@patocontainer ~ $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
18dda3dabdf9 patomx/patomariadb "docker-entrypoint.s…" 12 seconds ago Up 7 seconds 3306/tcp patomariag2
5f9ce8bc16d2 patomx/patomariadb "docker-entrypoint.s…" 22 seconds ago Up 18 seconds 3306/tcp patomariag1
7cb4db2c49a9 patomx/patomariadb "docker-entrypoint.s…" 59 minutes ago Up 59 minutes 3306/tcp patomariagm
pato@patocontainer ~ $ docker volume ls
DRIVER VOLUME NAME
local patovolg1
local patovolg2
local patovolgm
Probar la Conectividad
Accede al contenedor Primario y haz ping a los otros usando el nombre asignado a cada contenedor:
pato@patocontainer ~ $ docker exec -it patomariagm bash
root@7cb4db2c49a9:/# ping patomariag1
PING patomariag1 (172.19.0.3) 56(84) bytes of data.
64 bytes from patomariag1.pato-net (172.19.0.3): icmp_seq=1 ttl=64 time=0.052 ms
...
root@7cb4db2c49a9:/# ping patomariag2
PING patomariag2 (172.19.0.4) 56(84) bytes of data.
64 bytes from patomariag2.pato-net (172.19.0.4): icmp_seq=1 ttl=64 time=0.079 ms
Detener los Contenedores
Envía docker stop
para detener las bases de datos y valida que ninguna está en ejecución:
pato@patocontainer ~ $ docker stop patomariagm patomariag1 patomariag2
patomariagm
patomariag1
patomariag2
pato@patocontainer ~ $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
pato@patocontainer ~ $
Configuración del Cluster de Galera
Ahora que tenemos nuestros 3 contenedores listos necesitamos configurarlos para la replicación de Galera.
Crear los Archivos de Configuración
Necesitamos crear un nuevo archivo de configuración de Galera para el nodo Primario:
pato@patocontainer ~/galera $ vi galera-init.cnf
y agregar las siguientes opciones:
- Activar la replicación y definir la librería
[mariadb]
# Galera Replication Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
- Definir el nombre del Cluster y listar las direcciones de los miembros
# Galera Cluster Name and Members
wsrep_cluster_name="patocluster"
wsrep_cluster_address="gcomm://"
# para el nodo primario la lista debe estar vacía para inicializar un nuevo cluster
- Identificar a este miembro del Cluster
# Galera Cluster Member
wsrep_node_name="patomain"
wsrep_node_address="patomariagm"
- Definir el método para la copia inicial de datos
# Galera State Snapshot Transfer Full Data Copy
wsrep_sst_method=rsync
- Habilitar el Identificador Global de Transacciones
# Galera GTID Configuration
wsrep_gtid_mode=ON
wsrep_gtid_domain_id=1
- Agregar la configuración para el Binary log y el Motor de Almacenamiento
# MariaDB Configuration
binlog_format=ROW
default-storage-engine=InnoDB
innodb_autoinc_lock_mode=2
log_slave_updates=ON
log_bin=galera-bin
Entonces crea otros 2 archivos de configuración para los otros nodos, con las mismas opciones del anterior pero cambiando los parámetros de identificación de este miembro:
pato@patocontainer ~/galera $ vi galera-node1.cnf
wsrep_cluster_address="gcomm://patomariagm,patomariag1,patomariag2"
# Galera Cluster Member
wsrep_node_name="patonode1"
wsrep_node_address="patomariag1"
pato@patocontainer ~/galera $ vi galera-node2.cnf
wsrep_cluster_address="gcomm://patomariagm,patomariag1,patomariag2"
# Galera Cluster Member
wsrep_node_name="patonode2"
wsrep_node_address="patomariag2"
Copiar los Archivos de Configuración hacia los Contenedores
Aún cuando los contenedores no estén corriendo podemos mover archivos adentro de ellos desde el anfitrión de Docker con el comando docker cp
.
Vamos a copiar los archivos de configuración creados a un directorio válido para la búsqueda de configuración de mysqld en esta imagen,
en nuestro caso usaremos !includedir /etc/mysql/mariadb.conf.d/
:
pato@patocontainer ~/galera $ docker cp galera-init.cnf patomariagm:/etc/mysql/mariadb.conf.d/galera.cnf
pato@patocontainer ~/galera $ docker cp galera-node1.cnf patomariag1:/etc/mysql/mariadb.conf.d/galera.cnf
pato@patocontainer ~/galera $ docker cp galera-node2.cnf patomariag2:/etc/mysql/mariadb.conf.d/galera.cnf
Levantar los Contenedores
En un Cluster de Galera el nodo Primario debe ser el primero en arrancar con el fin de inicializar el cluster.
Así que vamos a levantar cada nodo en orden y validaremos cuántos miembros están registrados en el cluster:
pato@patocontainer ~ $ docker start patomariagm
patomariagm
pato@patocontainer ~ $ docker exec -it patomariagm mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 1 |
+--------------------+-------+
pato@patocontainer ~ $ docker start patomariag1
patomariag1
pato@patocontainer ~ $ docker exec -it patomariag1 mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 2 |
+--------------------+-------+
pato@patocontainer ~ $ docker start patomariag2
patomariag2
pato@patocontainer ~ $ docker exec -it patomariag2 mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 3 |
+--------------------+-------+
pato@patocontainer ~ $
¡Perfecto, nuestro cluster de Galera está configurado y en ejecución y todos los miembros se han unido!
Modificar la Configuración para el Nodo Primario
Una vez que el cluster de Galera ha sido inicializado necesitamos modificar el parámetro wsrep_cluster_address
de estar vacío (bootstrap)
a tener la lista de miembros del cluster, igual que está configurado en los otros nodos:
pato@patocontainer ~/galera $ docker exec -it patomariagm bash
root@7cb4db2c49a9:/# nano /etc/mysql/mariadb.conf.d/galera.cnf
wsrep_cluster_address="gcomm://patomariagm,patomariag1,patomariag2"
Probar la Replicación en el Cluster de Galera
Ahora vamos a validar que la replicación esté funcionando.
Validar la Replicación Inicial
Primero queremos validar que los objetos y datos creados antes de la configuración del cluster se hayan replicado a los nuevos nodos:
pato@patocontainer ~ $ docker exec -it patomariag1 bash
root@5f9ce8bc16d2:/# mysql
MariaDB [(none)]> use taller
Database changed
MariaDB [taller]> select * from tg1;
+----+--------------+---------------------+
| i1 | c2 | d3 |
+----+--------------+---------------------+
| 1 | 7cb4db2c49a9 | 2020-05-29 19:44:42 |
+----+--------------+---------------------+
1 row in set (0.000 sec)
pato@patocontainer ~ $ docker exec -it patomariag2 bash
root@18dda3dabdf9:/# mysql
MariaDB [(none)]> use taller
Database changed
MariaDB [taller]> select * from tg1;
+----+--------------+---------------------+
| i1 | c2 | d3 |
+----+--------------+---------------------+
| 1 | 7cb4db2c49a9 | 2020-05-29 19:44:42 |
+----+--------------+---------------------+
1 row in set (0.088 sec)
Nuestros datos originales fueron replicados en cada nodo, entonces validemos la replicación futura de datos.
Validar la Replication Nodo a Nodo
Como un Cluster de Galera te permite actualizar desde todos los nodos, vamos a insertar un registro en cada nodo
identificando la instancia que hace la inserción con @@hostname
y el momento de la operación con now()
:
MariaDB [taller]> insert into tg1 (c2,d3) values (@@hostname,now());
Query OK, 1 row affected (0.398 sec)
y revisemos el resultado también en cada nodo:
pato@patocontainer ~/galera $ docker exec -it patomariagm mysql -e "select * from taller.tg1"
+----+--------------+---------------------+
| i1 | c2 | d3 |
+----+--------------+---------------------+
| 1 | 7cb4db2c49a9 | 2020-05-29 19:44:42 |
| 4 | 7cb4db2c49a9 | 2020-05-29 20:35:19 |
| 5 | 5f9ce8bc16d2 | 2020-05-29 20:36:25 |
| 6 | 18dda3dabdf9 | 2020-05-29 20:37:01 |
+----+--------------+---------------------+
pato@patocontainer ~/galera $ docker exec -it patomariag1 mysql -e "select * from taller.tg1"
+----+--------------+---------------------+
| i1 | c2 | d3 |
+----+--------------+---------------------+
| 1 | 7cb4db2c49a9 | 2020-05-29 19:44:42 |
| 4 | 7cb4db2c49a9 | 2020-05-29 20:35:19 |
| 5 | 5f9ce8bc16d2 | 2020-05-29 20:36:25 |
| 6 | 18dda3dabdf9 | 2020-05-29 20:37:01 |
+----+--------------+---------------------+
pato@patocontainer ~/galera $ docker exec -it patomariag2 mysql -e "select * from taller.tg1"
+----+--------------+---------------------+
| i1 | c2 | d3 |
+----+--------------+---------------------+
| 1 | 7cb4db2c49a9 | 2020-05-29 19:44:42 |
| 4 | 7cb4db2c49a9 | 2020-05-29 20:35:19 |
| 5 | 5f9ce8bc16d2 | 2020-05-29 20:36:25 |
| 6 | 18dda3dabdf9 | 2020-05-29 20:37:01 |
+----+--------------+---------------------+
¡Como podemos ver se insertó un registro en cada nodo y los datos fueron replicados en los demás!
Conclusión
Fuimos capaces de configurar un Cluster de Galera para MariaDB usando contenedores de Docker dentro de una máquina virtual en la Google Cloud Platform
y validamos que podemos actualizar cualquier tabla en cualquier nodo y esos cambios serán replicados a todos los nodos.
Esta es una manera fácil de construir un cluster multinodo cuando necesitas probar alguna configuración o replicar algún problema
sin tener que lidiar con una instalación más permanente.