sql >> Base de Datos >  >> RDS >> MariaDB

Ejecución de un clúster Galera de MariaDB sin herramientas de orquestación:administración de contenedores de base de datos:segunda parte

Como vimos en la primera parte de este blog, un clúster de base de datos fuertemente consistente como Galera no funciona bien con herramientas de orquestación de contenedores como Kubernetes o Swarm. Le mostramos cómo implementar Galera y configurar la administración de procesos para Docker, para que mantenga el control total del comportamiento. Esta publicación de blog es la continuación de eso, vamos a analizar la operación y el mantenimiento del clúster.

Para recapitular algunos de los puntos principales de la parte 1 de este blog, implementamos un clúster de Galera de tres nodos, con ProxySQL y Keepalived en tres hosts de Docker diferentes, donde todas las instancias de MariaDB se ejecutan como contenedores de Docker. El siguiente diagrama ilustra el despliegue final:

Apagado ordenado

Para realizar un apagado correcto de MySQL, la mejor manera es enviar SIGTERM (señal 15) al contenedor:

$ docker kill -s 15 {db_container_name}

Si desea apagar el clúster, repita el comando anterior en todos los contenedores de la base de datos, un nodo a la vez. Lo anterior es similar a realizar "systemctl stop mysql" en el servicio systemd para MariaDB. Usar el comando "docker stop" es bastante arriesgado para el servicio de la base de datos porque espera 10 segundos de tiempo de espera y Docker forzará SIGKILL si se excede esta duración (a menos que use un --timeout adecuado valor).

El último nodo que se apague correctamente tendrá el seqno no es igual a -1 y safe_to_bootstrap el indicador se establece en 1 en /{datadir volume}/grastate.dat del host Docker, por ejemplo, en host2:

$ cat /containers/mariadb2/datadir/grastate.dat
# GALERA saved state
version: 2.1
uuid:    e70b7437-645f-11e8-9f44-5b204e58220b
seqno:   7099
safe_to_bootstrap: 1

Detectar el nodo más avanzado

Si el clúster no se cerró correctamente, o si el nodo que estaba tratando de iniciar no fue el último nodo en abandonar el clúster, probablemente no podrá iniciar uno de los nodos de Galera y podría encontrar el siguiente error :

2016-11-07 01:49:19 5572 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node.
It was not the last one to leave the cluster and may not contain all the updates.
To force cluster bootstrap with this node, edit the grastate.dat file manually and set safe_to_bootstrap to 1 .

Galera honra el nodo que tiene safe_to_bootstrap bandera establecida en 1 como el primer nodo de referencia. Esta es la forma más segura de evitar la pérdida de datos y garantizar que siempre se arranque el nodo correcto.

Si recibió el error, primero debemos encontrar el nodo más avanzado antes de seleccionar el nodo como el primero en ser arrancado. Cree un contenedor transitorio (con --rm flag), asígnelo al mismo datadir y directorio de configuración del contenedor de la base de datos real con dos indicadores de comando MySQL, --wsrep_recover y --wsrep_cluster_address . Por ejemplo, si queremos saber el último número confirmado de mariadb1, debemos ejecutar:

$ docker run --rm --name mariadb-recover \
        --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
        --volume /containers/mariadb1/datadir:/var/lib/mysql \
        --volume /containers/mariadb1/conf.d:/etc/mysql/conf.d \
        mariadb:10.2.15 \
        --wsrep_recover \
        --wsrep_cluster_address=gcomm://
2018-06-12  4:46:35 139993094592384 [Note] mysqld (mysqld 10.2.15-MariaDB-10.2.15+maria~jessie) starting as process 1 ...
2018-06-12  4:46:35 139993094592384 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
...
2018-06-12  4:46:35 139993094592384 [Note] Plugin 'FEEDBACK' is disabled.
2018-06-12  4:46:35 139993094592384 [Note] Server socket created on IP: '::'.
2018-06-12  4:46:35 139993094592384 [Note] WSREP: Recovered position: e70b7437-645f-11e8-9f44-5b204e58220b:7099

La última línea es lo que estamos buscando. MariaDB imprime el UUID del clúster y el número de secuencia de la transacción confirmada más recientemente. El nodo que contiene el número más alto se considera el nodo más avanzado. Dado que especificamos --rm , el contenedor se eliminará automáticamente una vez que salga. Repita el paso anterior en cada host de Docker reemplazando el --volume ruta a los respectivos volúmenes del contenedor de la base de datos.

Una vez que haya comparado el valor informado por todos los contenedores de la base de datos y haya decidido qué contenedor es el nodo más actualizado, cambie el safe_to_bootstrap marca a 1 dentro de /{datadir volume}/grastate.dat manualmente. Digamos que todos los nodos informan el mismo número de secuencia exacto, podemos elegir mariadb3 para que se arranque cambiando el safe_to_bootstrap valor a 1:

$ vim /containers/mariadb3/datadir/grasate.dat
...
safe_to_bootstrap: 1

Guarde el archivo y comience a arrancar el clúster desde ese nodo, como se describe en el siguiente capítulo.

Arranque del clúster

Arrancar el clúster es similar al primer comando de ejecución de docker que usamos al iniciar el clúster por primera vez. Si mariadb1 es el nodo de arranque elegido, simplemente podemos volver a ejecutar el contenedor de arranque creado:

$ docker start mariadb0 # on host1

De lo contrario, si el contenedor de arranque no existe en el nodo elegido, digamos en host2, ejecute el comando del contenedor de arranque y asigne los volúmenes de mariadb2 existentes. Estamos usando mariadb0 como el nombre del contenedor en host2 para indicar que es un contenedor de arranque:

$ docker run -d \
        --name mariadb0 \
        --hostname mariadb0.weave.local \
        --net weave \
        --publish "3306" \
        --publish "4444" \
        --publish "4567" \
        --publish "4568" \
        $(weave dns-args) \
        --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
        --volume /containers/mariadb2/datadir:/var/lib/mysql \
        --volume /containers/mariadb2/conf.d:/etc/mysql/mariadb.conf.d \
        mariadb:10.2.15 \
        --wsrep_cluster_address=gcomm:// \
        --wsrep_sst_auth="root:PM7%[email protected]^1" \
        --wsrep_node_address=mariadb0.weave.local

Puede notar que este comando es un poco más corto en comparación con el comando de arranque anterior descrito en esta guía. Dado que ya tenemos el usuario proxysql creado en nuestro primer comando de arranque, podemos omitir estas dos variables de entorno:

  • --env MYSQL_USER=proxysql
  • --env MYSQL_PASSWORD=contraseña de proxy sql

Luego, inicie los contenedores de MariaDB restantes, elimine el contenedor de arranque e inicie el contenedor de MariaDB existente en el host de arranque. Básicamente, el orden de los comandos sería:

$ docker start mariadb1 # on host1
$ docker start mariadb3 # on host3
$ docker stop mariadb0 # on host2
$ docker start mariadb2 # on host2

En este punto, el clúster se inicia y se ejecuta a plena capacidad.

Control de recursos

La memoria es un recurso muy importante en MySQL. Aquí es donde se almacenan los búferes y cachés, y es fundamental para MySQL reducir el impacto de golpear el disco con demasiada frecuencia. Por otro lado, el intercambio es malo para el rendimiento de MySQL. De forma predeterminada, no habrá restricciones de recursos en los contenedores en ejecución. Los contenedores usan tanto de un recurso dado como lo permita el kernel del host. Otra cosa importante es el límite del descriptor de archivo. Puede aumentar el límite del descriptor de archivo abierto, o "nofile" a algo más alto para atender la cantidad de archivos que el servidor MySQL puede abrir simultáneamente. Establecer esto en un valor alto no hará daño.

Para limitar la asignación de memoria y aumentar el límite del descriptor de archivo a nuestro contenedor de base de datos, uno agregaría --memory , --intercambio de memoria y --ulimit parámetros en el comando "docker run":

$ docker kill -s 15 mariadb1
$ docker rm -f mariadb1
$ docker run -d \
        --name mariadb1 \
        --hostname mariadb1.weave.local \
        --net weave \
        --publish "3306:3306" \
        --publish "4444" \
        --publish "4567" \
        --publish "4568" \
        $(weave dns-args) \
        --memory 16g \
        --memory-swap 16g \
        --ulimit nofile:16000:16000 \
        --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
        --volume /containers/mariadb1/datadir:/var/lib/mysql \
        --volume /containers/mariadb1/conf.d:/etc/mysql/mariadb.conf.d \
        mariadb:10.2.15 \
        --wsrep_cluster_address=gcomm://mariadb0.weave.local,mariadb1.weave.local,mariadb2.weave.local,mariadb3.weave.local \
        --wsrep_sst_auth="root:PM7%[email protected]^1" \
        --wsrep_node_address=mariadb1.weave.local

Tenga en cuenta que si --memory-swap se establece en el mismo valor que --memory y --memoria se establece en un número entero positivo, el contenedor no tendrá acceso al intercambio. Si --intercambio de memoria no está configurado, el intercambio de contenedores se establecerá de forma predeterminada en --memory multiplicar por 2. Si --memoria y --intercambio de memoria se establecen en el mismo valor, esto evitará que los contenedores utilicen cualquier intercambio. Esto se debe a que --intercambio de memoria es la cantidad combinada de memoria e intercambio que se puede usar, mientras que --memory es solo la cantidad de memoria física que se puede usar.

Algunos de los recursos del contenedor, como la memoria y la CPU, se pueden controlar dinámicamente a través del comando "docker update", como se muestra en el siguiente ejemplo para actualizar la memoria del contenedor mariadb1 a 32G sobre la marcha:

$ docker update \
    --memory 32g \
    --memory-swap 32g \
    mariadb1

No olvide ajustar my.cnf en consecuencia para adaptarse a las nuevas especificaciones. La gestión de la configuración se explica en la siguiente sección.

Gestión de la configuración

La mayoría de los parámetros de configuración de MySQL/MariaDB se pueden cambiar durante el tiempo de ejecución, lo que significa que no necesita reiniciar para aplicar los cambios. Consulte la página de documentación de MariaDB para obtener más detalles. El parámetro enumerado con "Dinámico:Sí" significa que la variable se carga inmediatamente después de cambiar sin necesidad de reiniciar el servidor MariaDB. De lo contrario, establezca los parámetros dentro del archivo de configuración personalizado en el host de Docker. Por ejemplo, en mariadb3, realice los cambios en el siguiente archivo:

$ vim /containers/mariadb3/conf.d/my.cnf

Y luego reinicie el contenedor de la base de datos para aplicar el cambio:

$ docker restart mariadb3

Verifique que el contenedor inicie el proceso mirando los registros de la ventana acoplable. Realice esta operación en un nodo a la vez si desea realizar cambios en todo el clúster.

Copia de seguridad

Hacer una copia de seguridad lógica es bastante sencillo porque la imagen de MariaDB también viene con el binario mysqldump. Simplemente use el comando "docker exec" para ejecutar mysqldump y enviar la salida a un archivo relativo a la ruta del host. El siguiente comando realiza una copia de seguridad de mysqldump en mariadb2 y la guarda en /backups/mariadb2 dentro de host2:

$ docker exec -it mariadb2 mysqldump -uroot -p --single-transaction > /backups/mariadb2/dump.sql

La copia de seguridad binaria como Percona Xtrabackup o MariaDB Backup requiere el proceso para acceder directamente al directorio de datos de MariaDB. Debe instalar esta herramienta dentro del contenedor, a través del host de la máquina o usar una imagen dedicada para este propósito, como la imagen "perconalab/percona-xtrabackup" para crear la copia de seguridad y almacenarla dentro de /tmp/backup en el host Docker:

$ docker run --rm -it \
    -v /containers/mariadb2/datadir:/var/lib/mysql \
    -v /tmp/backup:/xtrabackup_backupfiles \
    perconalab/percona-xtrabackup \
    --backup --host=mariadb2 --user=root --password=mypassword

También puede detener el contenedor con innodb_fast_shutdown establezca en 0 y copie el volumen datadir a otra ubicación en el host físico:

$ docker exec -it mariadb2 mysql -uroot -p -e 'SET GLOBAL innodb_fast_shutdown = 0'
$ docker kill -s 15 mariadb2
$ cp -Rf /containers/mariadb2/datadir /backups/mariadb2/datadir_copied
$ docker start mariadb2

Restaurar

La restauración es bastante sencilla para mysqldump. Simplemente puede redirigir la entrada estándar al contenedor desde el host físico:

$ docker exec -it mariadb2 mysql -uroot -p < /backups/mariadb2/dump.sql

También puede usar la línea de comando estándar del cliente mysql de forma remota con el nombre de host y el valor de puerto adecuados en lugar de usar este comando "docker exec":

$ mysql -uroot -p -h127.0.0.1 -P3306 < /backups/mariadb2/dump.sql

Para Percona Xtrabackup y MariaDB Backup, tenemos que preparar la copia de seguridad de antemano. Esto avanzará la copia de seguridad hasta el momento en que finalizó. Digamos que nuestros archivos Xtrabackup están ubicados en /tmp/backup del host Docker, para prepararlo, simplemente:

$ docker run --rm -it \
    -v mysql-datadir:/var/lib/mysql \
    -v /tmp/backup:/xtrabackup_backupfiles \
    perconalab/percona-xtrabackup \
    --prepare --target-dir /xtrabackup_backupfiles

La copia de seguridad preparada en /tmp/backup del host de Docker se puede usar como directorio de datos de MariaDB para un nuevo contenedor o clúster. Digamos que solo queremos verificar la restauración en un contenedor MariaDB independiente, ejecutaríamos:

$ docker run -d \
    --name mariadb-restored \
    --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
    -v /tmp/backup:/var/lib/mysql \
    mariadb:10.2.15

Si realizó una copia de seguridad utilizando el enfoque de detención y copia, simplemente puede duplicar el directorio de datos y usar el directorio duplicado como un volumen que se asigna al directorio de datos de MariaDB para ejecutarlo en otro contenedor. Digamos que la copia de seguridad se copió en /backups/mariadb2/datadir_copied, podemos ejecutar un nuevo contenedor ejecutando:

$ mkdir -p /containers/mariadb-restored/datadir
$ cp -Rf /backups/mariadb2/datadir_copied /containers/mariadb-restored/datadir
$ docker run -d \
    --name mariadb-restored \
    --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
    -v /containers/mariadb-restored/datadir:/var/lib/mysql \
    mariadb:10.2.15

MYSQL_ROOT_PASSWORD debe coincidir con la contraseña raíz real para esa copia de seguridad en particular.

Varios nueves MySQL en Docker:cómo contenerizar su base de datosDescubra todo lo que necesita saber al considerar ejecutar un servicio MySQL sobre la virtualización de contenedores de DockerDescargar el Whitepaper

Actualización de la versión de la base de datos

Hay dos tipos de actualización:actualización en el lugar o actualización lógica.

La actualización en el lugar implica apagar el servidor MariaDB, reemplazar los archivos binarios antiguos con los nuevos y luego iniciar el servidor en el directorio de datos anterior. Una vez iniciado, debe ejecutar mysql_upgrade secuencia de comandos para comprobar y actualizar todas las tablas del sistema y también para comprobar las tablas de usuario.

La actualización lógica implica exportar SQL desde la versión actual utilizando una utilidad de copia de seguridad lógica como mysqldump, ejecutar el nuevo contenedor con los archivos binarios de la versión actualizada y luego aplicar SQL a la nueva versión de MySQL/MariaDB. Es similar al enfoque de copia de seguridad y restauración descrito en la sección anterior.

Sin embargo, siempre es un buen enfoque hacer una copia de seguridad de su base de datos antes de realizar cualquier operación destructiva. Se requieren los siguientes pasos al actualizar de la imagen actual, MariaDB 10.1.33 a otra versión principal, MariaDB 10.2.15 en mariadb3 reside en host3:

  1. Copia de seguridad de la base de datos. No importa la copia de seguridad física o lógica, pero se recomienda esta última usando mysqldump.

  2. Descargue la imagen más reciente a la que nos gustaría actualizar:

    $ docker pull mariadb:10.2.15
  3. Establezca innodb_fast_shutdown en 0 para nuestro contenedor de base de datos:

    $ docker exec -it mariadb3 mysql -uroot -p -e 'SET GLOBAL innodb_fast_shutdown = 0'
  4. Cierra correctamente el contenedor de la base de datos:

    $ docker kill --signal=TERM mariadb3
  5. Cree un nuevo contenedor con la nueva imagen para nuestro contenedor de base de datos. Mantenga el resto de los parámetros intactos, excepto usar el nuevo nombre del contenedor (de lo contrario, entraría en conflicto):

    $ docker run -d \
            --name mariadb3-new \
            --hostname mariadb3.weave.local \
            --net weave \
            --publish "3306:3306" \
            --publish "4444" \
            --publish "4567" \
            --publish "4568" \
            $(weave dns-args) \
            --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
            --volume /containers/mariadb3/datadir:/var/lib/mysql \
            --volume /containers/mariadb3/conf.d:/etc/mysql/mariadb.conf.d \
            mariadb:10.2.15 \
            --wsrep_cluster_address=gcomm://mariadb0.weave.local,mariadb1.weave.local,mariadb2.weave.local,mariadb3.weave.local \
            --wsrep_sst_auth="root:PM7%[email protected]^1" \
            --wsrep_node_address=mariadb3.weave.local
  6. Ejecute el script mysql_upgrade:

    $ docker exec -it mariadb3-new mysql_upgrade -uroot -p
  7. Si no se produjeron errores, elimine el contenedor anterior, mariadb3 (el nuevo es mariadb3-new):

    $ docker rm -f mariadb3
  8. De lo contrario, si el proceso de actualización falla en el medio, podemos recurrir al contenedor anterior:

    $ docker stop mariadb3-new
    $ docker start mariadb3

La actualización de la versión principal se puede realizar de manera similar a la actualización de la versión secundaria, excepto que debe tener en cuenta que MySQL/MariaDB solo admite la actualización principal de la versión anterior. Si está en MariaDB 10.0 y desea actualizar a 10.2, primero debe actualizar a MariaDB 10.1, seguido de otro paso de actualización a MariaDB 10.2.

Tome nota de los cambios de configuración que se están introduciendo y obsoletos entre las versiones principales.

Conmutación por error

En Galera, todos los nodos son maestros y tienen el mismo rol. Con ProxySQL en la imagen, las conexiones que pasan a través de esta puerta de enlace se conmutarán por error automáticamente siempre que haya un componente principal ejecutándose para Galera Cluster (es decir, la mayoría de los nodos están activos). La aplicación no notará ninguna diferencia si un nodo de la base de datos deja de funcionar porque ProxySQL simplemente redirigirá las conexiones a los otros nodos disponibles.

Si la aplicación se conecta directamente a MariaDB sin pasar por ProxySQL, la conmutación por error debe realizarse en el lado de la aplicación apuntando al siguiente nodo disponible, siempre que el nodo de la base de datos cumpla con las siguientes condiciones:

  • Estado wsrep_local_state_comment está sincronizado (el estado "Desincronizado/Donante" también es posible, solo si wsrep_sst_method es xtrabackup, xtrabackup-v2 o mariabackup).
  • Estado wsrep_cluster_status es principal.

En Galera, un nodo disponible no significa que esté en buen estado hasta que se verifique el estado anterior.

Escalamiento horizontal

Para escalar horizontalmente, podemos crear un nuevo contenedor en la misma red y usar el mismo archivo de configuración personalizado para el contenedor existente en ese host en particular. Por ejemplo, digamos que queremos agregar el cuarto contenedor de MariaDB en host3, podemos usar el mismo archivo de configuración montado para mariadb3, como se ilustra en el siguiente diagrama:

Ejecute el siguiente comando en host3 para escalar horizontalmente:

$ docker run -d \
        --name mariadb4 \
        --hostname mariadb4.weave.local \
        --net weave \
        --publish "3306:3307" \
        --publish "4444" \
        --publish "4567" \
        --publish "4568" \
        $(weave dns-args) \
        --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
        --volume /containers/mariadb4/datadir:/var/lib/mysql \
        --volume /containers/mariadb3/conf.d:/etc/mysql/mariadb.conf.d \
        mariadb:10.2.15 \
        --wsrep_cluster_address=gcomm://mariadb1.weave.local,mariadb2.weave.local,mariadb3.weave.local,mariadb4.weave.local \
        --wsrep_sst_auth="root:PM7%[email protected]^1" \
        --wsrep_node_address=mariadb4.weave.local

Una vez que se crea el contenedor, se unirá al clúster y realizará SST. Se puede acceder a él en el puerto 3307 de forma externa o fuera de la red de Weave, o en el puerto 3306 dentro del host o dentro de la red de Weave. Ya no es necesario incluir mariadb0.weave.local en la dirección del clúster. Una vez que se haya escalado horizontalmente el clúster, debemos agregar el nuevo contenedor de MariaDB al conjunto de equilibrio de carga de ProxySQL a través de la consola de administración:

$ docker exec -it proxysql1 mysql -uadmin -padmin -P6032
mysql> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'mariadb4.weave.local',3306);
mysql> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (20,'mariadb4.weave.local',3306);
mysql> LOAD MYSQL SERVERS TO RUNTIME;
mysql> SAVE MYSQL SERVERS TO DISK;

Repita los comandos anteriores en la segunda instancia de ProxySQL.

Finalmente, para el último paso (puede omitir esta parte si ya ejecutó la instrucción "SAVE .. TO DISK" en ProxySQL), agregue la siguiente línea en proxysql.cnf para que sea persistente en el reinicio del contenedor en host1 y host2:

$ vim /containers/proxysql1/proxysql.cnf # host1
$ vim /containers/proxysql2/proxysql.cnf # host2

Y añada líneas relacionadas con mariadb4 bajo la directiva mysql_server:

mysql_servers =
(
        { address="mariadb1.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
        { address="mariadb2.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
        { address="mariadb3.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
        { address="mariadb4.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
        { address="mariadb1.weave.local" , port=3306 , hostgroup=20, max_connections=100 },
        { address="mariadb2.weave.local" , port=3306 , hostgroup=20, max_connections=100 },
        { address="mariadb3.weave.local" , port=3306 , hostgroup=20, max_connections=100 },
        { address="mariadb4.weave.local" , port=3306 , hostgroup=20, max_connections=100 }
)

Guarde el archivo y deberíamos estar bien en el próximo reinicio del contenedor.

Reducción de escala

Para reducir la escala, simplemente cierra el contenedor con gracia. El mejor comando sería:

$ docker kill -s 15 mariadb4
$ docker rm -f mariadb4

Recuerde, si el nodo de la base de datos dejó el clúster de manera incorrecta, no fue parte de la reducción y afectaría el cálculo del quórum.

Para eliminar el contenedor de ProxySQL, ejecute los siguientes comandos en ambos contenedores de ProxySQL. Por ejemplo, en proxysql1:

$ docker exec -it proxysql1 mysql -uadmin -padmin -P6032
mysql> DELETE FROM mysql_servers WHERE hostname="mariadb4.weave.local";
mysql> LOAD MYSQL SERVERS TO RUNTIME;
mysql> SAVE MYSQL SERVERS TO DISK;

Luego puede eliminar la entrada correspondiente dentro de proxysql.cnf o simplemente dejarlo así. Se detectará como SIN CONEXIÓN desde el punto de vista de ProxySQL de todos modos.

Resumen

Con Docker, las cosas se vuelven un poco diferentes de la forma convencional de manejar servidores MySQL o MariaDB. Manejar servicios con estado como Galera Cluster no es tan fácil como las aplicaciones sin estado y requiere pruebas y planificación adecuadas.

En nuestro próximo blog sobre este tema, evaluaremos las ventajas y desventajas de ejecutar Galera Cluster en Docker sin ninguna herramienta de orquestación.