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

Automatización de bases de datos con Puppet:implementación de la replicación de MySQL y MariaDB

Puppet es una herramienta de gestión de sistemas de código abierto para centralizar y automatizar la gestión de la configuración. Las herramientas de automatización ayudan a minimizar las tareas manuales y repetitivas y pueden ahorrar una gran cantidad de tiempo.

Puppet funciona de forma predeterminada en un modelo de servidor/agente. Los agentes obtienen su "catálogo" (estado deseado final) del maestro y lo aplican localmente. Luego informan al servidor. El catálogo se calcula según los "hechos" que la máquina envía al servidor, la entrada del usuario (parámetros) y los módulos (código fuente).

En este blog, le mostraremos cómo implementar y administrar instancias de MySQL/MariaDB a través de Puppet. Hay una serie de tecnologías en torno a MySQL/MariaDB, como la replicación (maestro-esclavo, Galera o replicación de grupo para MySQL), balanceadores de carga compatibles con SQL como ProxySQL y MariaDB MaxScale, herramientas de copia de seguridad y recuperación y muchas más que cubriremos en este serie de blogs También hay muchos módulos disponibles en Puppet Forge creados y mantenidos por la comunidad que pueden ayudarnos a simplificar el código y evitar reinventar la rueda. En este blog, nos vamos a centrar en la replicación de MySQL.

puppetlabs/mysql

Este es el módulo Puppet más popular para MySQL y MariaDB (y probablemente el mejor del mercado) en este momento. Este módulo gestiona tanto la instalación como la configuración de MySQL, así como la ampliación de Puppet para permitir la gestión de los recursos de MySQL, como bases de datos, usuarios y concesiones.

El equipo de Puppet mantiene oficialmente el módulo (a través del repositorio Github de puppetlabs) y es compatible con todas las versiones principales de Puppet Enterprise 2019.1.x, 2019.0.x, 2018.1.x, Puppet>=5.5.10 <7.0.0 en RedHat, Ubuntu, Plataformas Debian, SLES, Scientific, CentOS, OracleLinux. El usuario tiene opciones para instalar MySQL, MariaDB y Percona Server al personalizar el repositorio de paquetes

El siguiente ejemplo muestra cómo implementar un servidor MySQL. En el titiritero, instale el módulo MySQL y cree el archivo de manifiesto:

(puppet-master)$ puppet module install puppetlabs/mysql
(puppet-master)$ vim /etc/puppetlabs/code/environments/production/manifests/mysql.pp

Agregue las siguientes líneas:

node "db1.local" {
  class { '::mysql::server':
    root_password => 't5[sb^D[+rt8bBYu',
    remove_default_accounts => true,
    override_options => {
      'mysqld' => {
        'log_error' => '/var/log/mysql.log',
        'innodb_buffer_pool_size' => '512M'
      }
      'mysqld_safe' => {
        'log_error' => '/var/log/mysql.log'
      }
    }
  }
}

Luego, en el nodo del agente de marionetas, ejecute el siguiente comando para aplicar el catálogo de configuración:

(db1.local)$ puppet agent -t

En la primera ejecución, es posible que obtenga el siguiente error:

Info: Certificate for db1.local has not been signed yet

Simplemente ejecute el siguiente comando en Puppet master para firmar el certificado:

(puppet-master)$ puppetserver ca sign --certname=db1.local
Successfully signed certificate request for db1.local

Vuelva a intentarlo con el comando "puppet agent -t" para reiniciar la conexión con el certificado firmado.

La definición anterior instalará los paquetes estándar relacionados con MySQL disponibles en el repositorio de distribución del sistema operativo. Por ejemplo, en Ubuntu 18.04 (Bionic), tendría instalados los paquetes MySQL 5.7.26:

(db1.local) $ dpkg --list | grep -i mysql
ii  mysql-client-5.7                5.7.26-0ubuntu0.18.04.1           amd64        MySQL database client binaries
ii  mysql-client-core-5.7           5.7.26-0ubuntu0.18.04.1           amd64        MySQL database core client binaries
ii  mysql-common                    5.8+1.0.4                         all          MySQL database common files, e.g. /etc/mysql/my.cnf
ii  mysql-server                    5.7.26-0ubuntu0.18.04.1           all          MySQL database server (metapackage depending on the latest version)
ii  mysql-server-5.7                5.7.26-0ubuntu0.18.04.1           amd64        MySQL database server binaries and system database setup
ii  mysql-server-core-5.7           5.7.26-0ubuntu0.18.04.1           amd64        MySQL database server binaries

Puede optar por otros proveedores como Oracle, Percona o MariaDB con configuración adicional en el repositorio (consulte la sección LÉAME para obtener más detalles). La siguiente definición instalará los paquetes de MariaDB desde el repositorio apt de MariaDB (requiere el módulo apt Puppet):

$ puppet module install puppetlabs/apt
$ vim /etc/puppetlabs/code/environments/production/manifests/mariadb.pp
# include puppetlabs/apt module
include apt

# apt definition for MariaDB 10.3
apt::source { 'mariadb':
  location => 'http://sgp1.mirrors.digitalocean.com/mariadb/repo/10.3/ubuntu/',
  release  => $::lsbdistcodename,
  repos    => 'main',
  key      => {
    id     => 'A6E773A1812E4B8FD94024AAC0F47944DE8F6914',
    server => 'hkp://keyserver.ubuntu.com:80',
  },
  include => {
    src   => false,
    deb   => true,
  },
}

# MariaDB configuration
class {'::mysql::server':
  package_name     => 'mariadb-server',
  service_name     => 'mysql',
  root_password    => 't5[sb^D[+rt8bBYu',
  override_options => {
    mysqld => {
      'log-error' => '/var/log/mysql/mariadb.log',
      'pid-file'  => '/var/run/mysqld/mysqld.pid',
    },
    mysqld_safe => {
      'log-error' => '/var/log/mysql/mariadb.log',
    },
  }
}

# Deploy on db2.local
node "db2.local" {
Apt::Source['mariadb'] ->
Class['apt::update'] ->
Class['::mysql::server']
}

Tome nota del valor clave->id, donde hay una forma especial de recuperar la identificación de 40 caracteres como se muestra en este artículo:

$ sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
$ apt-key adv --list-public-keys --with-fingerprint --with-colons
uid:-::::1459359915::6DC53DD92B7A8C298D5E54F950371E2B8950D2F2::MariaDB Signing Key <[email protected]>::::::::::0:
sub:-:4096:1:C0F47944DE8F6914:1459359915::::::e::::::23:
fpr:::::::::A6E773A1812E4B8FD94024AAC0F47944DE8F6914:

Donde el valor de identificación está en la línea que comienza con "fpr", que es 'A6E773A1812E4B8FD94024AAC0F47944DE8F6914'.

Después de aplicar el catálogo de Puppet, puede acceder directamente a la consola de MySQL como root sin una contraseña explícita, ya que el módulo configura y administra ~/.my.cnf automáticamente. Si quisiéramos restablecer la contraseña de root a otra cosa, simplemente cambie el valor de root_password en la definición de Puppet y aplique el catálogo en el nodo del agente.

Implementación de replicación de MySQL

Para implementar una configuración de replicación de MySQL, se deben crear al menos dos tipos de configuración para separar la configuración maestra y la esclava. El maestro tendrá deshabilitado solo lectura para permitir lectura/escritura mientras que los esclavos se configurarán con solo lectura habilitado. En este ejemplo, vamos a utilizar la replicación basada en GTID para simplificar la configuración (ya que la configuración de todos los nodos sería muy similar). Querremos iniciar el enlace de replicación al maestro justo después de que el esclavo esté activo.

Supongamos que tenemos 3 nodos de replicación maestro-esclavo de MySQL:

  • db1.local - maestro
  • db2.local - esclavo #1
  • db3.local - esclavo #2

Para cumplir con los requisitos anteriores, podemos escribir nuestro manifiesto en algo como esto:

# Puppet manifest for MySQL GTID-based replication MySQL 5.7 on Ubuntu 18.04 (Puppet v6.4.2) 
# /etc/puppetlabs/code/environments/production/manifests/replication.pp

# node's configuration
class mysql {
  class {'::mysql::server':
    root_password           => '[email protected]#',
    create_root_my_cnf      => true,
    remove_default_accounts => true,
    manage_config_file      => true,
    override_options        => {
      'mysqld' => {
        'datadir'                 => '/var/lib/mysql',
        'bind_address'            => '0.0.0.0',
        'server-id'               => $mysql_server_id,
        'read_only'               => $mysql_read_only,
        'gtid-mode'               => 'ON',
        'enforce_gtid_consistency'=> 'ON',
        'log-slave-updates'       => 'ON',
        'sync_binlog'             => 1,
        'log-bin'                 => '/var/log/mysql-bin',
        'read_only'               => 'OFF',
        'binlog-format'           => 'ROW',
        'log-error'               => '/var/log/mysql/error.log',
        'report_host'             => ${fqdn},
        'innodb_buffer_pool_size' => '512M'
      },
      'mysqld_safe' => {
        'log-error'               => '/var/log/mysql/error.log'
      }
    }
  }
  
  # create slave user
  mysql_user { "${slave_user}@192.168.0.%":
      ensure        => 'present',
      password_hash => mysql_password("${slave_password}")
  }

  # grant privileges for slave user
  mysql_grant { "${slave_user}@192.168.0.%/*.*":
      ensure        => 'present',
      privileges    => ['REPLICATION SLAVE'],
      table         => '*.*',
      user          => "${slave_user}@192.168.0.%"
  }

  # /etc/hosts definition
  host {
    'db1.local': ip => '192.168.0.161';
    'db2.local': ip => '192.169.0.162';
    'db3.local': ip => '192.168.0.163';
  }

  # executes change master only if $master_host is defined
  if $master_host {
    exec { 'change master':
      path    => '/usr/bin:/usr/sbin:/bin',
      command => "mysql --defaults-extra-file=/root/.my.cnf -e \"CHANGE MASTER TO MASTER_HOST = '$master_host', MASTER_USER = '$slave_user', MASTER_PASSWORD = '$slave_password', MASTER_AUTO_POSITION = 1; START SLAVE;\"",
      unless  => "mysql --defaults-extra-file=/root/.my.cnf -e 'SHOW SLAVE STATUS\G' | grep 'Slave_SQL_Running: Yes'"
    }
  }
}

## node assignment

# global vars
$master_host = undef
$slave_user = 'slave'
$slave_password = 'Replicas123'

# master
node "db1.local" {
  $mysql_server_id = '1'
  $mysql_read_only = 'OFF'
  include mysql
}

# slave1
node "db2.local" {
  $mysql_server_id = '2'
  $mysql_read_only = 'ON'
  $master_host = 'db1.local'
  include mysql
}

# slave2
node "db3.local" {
  $mysql_server_id = '3'
  $mysql_read_only = 'ON'
  $master_host = 'db1.local'
  include mysql
}

Obligar al agente a aplicar el catálogo:

(all-mysql-nodes)$ puppet agent -t

En el maestro (db1.local), podemos verificar todos los esclavos conectados:

mysql> SHOW SLAVE HOSTS;
+-----------+-----------+------+-----------+--------------------------------------+
| Server_id | Host      | Port | Master_id | Slave_UUID                           |
+-----------+-----------+------+-----------+--------------------------------------+
|         3 | db3.local | 3306 |         1 | 2d0b14b6-8174-11e9-8bac-0273c38be33b |
|         2 | db2.local | 3306 |         1 | a9dfa4c7-8172-11e9-8000-0273c38be33b |
+-----------+-----------+------+-----------+--------------------------------------+

Preste especial atención a la sección "exec { 'change master':", donde significa que se ejecutará un comando MySQL para iniciar el enlace de replicación si se cumple la condición. Todos los recursos "ejecutivos" ejecutados por Puppet deben ser idempotentes, lo que significa que la operación tendrá el mismo efecto ya sea que la ejecute una o 10,001 veces. Hay una serie de atributos de condición que puede usar como "a menos que", "solo si" y "crear" para salvaguardar el estado correcto y evitar que Puppet altere su configuración. Puede eliminar/comentar esa sección si desea iniciar el enlace de replicación manualmente.

Administración de MySQL

Este módulo se puede utilizar para realizar una serie de tareas de gestión de MySQL:

  • opciones de configuración (modificar, aplicar, configuración personalizada)
  • recursos de la base de datos (base de datos, usuario, subvenciones)
  • copia de seguridad (crear, programar, usuario de copia de seguridad, almacenamiento)
  • restauración simple (solo mysqldump)
  • instalación/activación de complementos

Recurso de base de datos

Como puede ver en el manifiesto de ejemplo anterior, hemos definido dos recursos de MySQL, mysql_user y mysql_grant, para crear usuarios y otorgar privilegios para el usuario, respectivamente. También podemos usar la clase mysql::db para garantizar que esté presente una base de datos con usuarios y privilegios asociados, por ejemplo:

  # make sure the database and user exist with proper grant
  mysql::db { 'mynewdb':
    user          => 'mynewuser',
    password      => 'passw0rd',
    host          => '192.168.0.%',
    grant         => ['SELECT', 'UPDATE']
  } 

Tenga en cuenta que en la replicación de MySQL, todas las escrituras deben realizarse solo en el maestro. Por lo tanto, asegúrese de que el recurso anterior esté asignado al maestro. De lo contrario, podría ocurrir una transacción errada.

Copia de seguridad y restauración

Por lo general, solo se requiere un host de respaldo para todo el clúster (a menos que replique un subconjunto de datos). Podemos usar la clase mysql::server::backup para preparar los recursos de respaldo. Supongamos que tenemos la siguiente declaración en nuestro manifiesto:

  # Prepare the backup script, /usr/local/sbin/mysqlbackup.sh
  class { 'mysql::server::backup':
    backupuser     => 'backup',
    backuppassword => 'passw0rd',
    backupdir      => '/home/backup',
    backupdirowner => 'mysql',
    backupdirgroup => 'mysql',
    backupdirmode  => '755',
    backuprotate   => 15,
    time           => ['23','30'],   #backup starts at 11:30PM everyday
    include_routines  => true,
    include_triggers  => true,
    ignore_events     => false,
    maxallowedpacket  => '64M',
    optional_args     => ['--set-gtid-purged=OFF'] #extra argument if GTID is enabled
  }

Puppet configurará todos los requisitos previos antes de ejecutar una copia de seguridad:crear el usuario de copia de seguridad, preparar la ruta de destino, asignar la propiedad y el permiso, configurar el trabajo cron y configurar las opciones de comando de copia de seguridad para usar en el script de copia de seguridad proporcionado ubicado en /usr/local /sbin/mysqlbackup.sh. Luego depende del usuario ejecutar o programar el script. Para hacer una copia de seguridad inmediata, simplemente invoque:

$ mysqlbackup.sh

Si extraemos el comando mysqldump real basado en lo anterior, esto es lo que parece:

$ mysqldump --defaults-extra-file=/tmp/backup.NYg0TR --opt --flush-logs --single-transaction --events --set-gtid-purged=OFF --all-databases

Para aquellos que deseen utilizar otras herramientas de copia de seguridad como Percona Xtrabackup, MariaDB Backup (solo MariaDB) o MySQL Enterprise Backup, el módulo ofrece las siguientes clases privadas:

  • mysql::backup::xtrabackup (Percona Xtrabackup y MariaDB Backup)
  • mysql::backup::mysqlbackup (Copia de seguridad empresarial de MySQL)

Ejemplo de declaración con Percona Xtrabackup:

  class { 'mysql::backup::xtrabackup':
    xtrabackup_package_name => 'percona-xtrabackup',
    backupuser     => 'xtrabackup',
    backuppassword => 'passw0rd',
    backupdir      => '/home/xtrabackup',
    backupdirowner => 'mysql',
    backupdirgroup => 'mysql',
    backupdirmode  => '755',
    backupcompress => true,
    backuprotate   => 15,
    include_routines  => true,
    time              => ['23','30'], #backup starts at 11:30PM
    include_triggers  => true,
    maxallowedpacket  => '64M',
    incremental_backups => true
  }

Lo anterior programará dos copias de seguridad, una copia de seguridad completa todos los domingos a las 11:30 p. m. y una copia de seguridad incremental todos los días excepto los domingos a la misma hora, como se muestra en el resultado del trabajo cron después de aplicar el manifiesto anterior:

(db1.local)$ crontab -l
# Puppet Name: xtrabackup-weekly
30 23 * * 0 /usr/local/sbin/xtrabackup.sh --target-dir=/home/backup/mysql/xtrabackup --backup
# Puppet Name: xtrabackup-daily
30 23 * * 1-6 /usr/local/sbin/xtrabackup.sh --incremental-basedir=/home/backup/mysql/xtrabackup --target-dir=/home/backup/mysql/xtrabackup/`date +%F_%H-%M-%S` --backup

Para obtener más detalles y opciones disponibles para esta clase (y otras clases), consulta la referencia de opciones aquí.

Para el aspecto de la restauración, el módulo solo admite la restauración con el método de copia de seguridad mysqldump, importando el archivo SQL directamente a la base de datos usando la clase mysql::db, por ejemplo:

mysql::db { 'mydb':
  user     => 'myuser',
  password => 'mypass',
  host     => 'localhost',
  grant    => ['ALL PRIVILEGES'],
  sql      => '/home/backup/mysql/mydb/backup.gz',
  import_cat_cmd => 'zcat',
  import_timeout => 900
}

El archivo SQL se cargará solo una vez y no en cada ejecución, a menos que se use enforce_sql => true.

Opciones de configuración

En este ejemplo, usamos manage_config_file => true con override_options para estructurar nuestras líneas de configuración que luego serán enviadas por Puppet. Cualquier modificación del archivo de manifiesto solo reflejará el contenido del archivo de configuración de MySQL de destino. Este módulo no cargará la configuración en el tiempo de ejecución ni reiniciará el servicio MySQL después de introducir los cambios en el archivo de configuración. Es responsabilidad del administrador del sistema reiniciar el servicio para activar los cambios.

Para agregar una configuración personalizada de MySQL, podemos colocar archivos adicionales en "includedir", predeterminado en /etc/mysql/conf.d. Esto nos permite anular configuraciones o agregar configuraciones adicionales, lo cual es útil si no usa override_options en mysql::server class. Aquí se recomienda encarecidamente utilizar la plantilla Puppet. Coloque el archivo de configuración personalizado en el directorio de plantillas del módulo (por defecto, /etc/puppetlabs/code/environments/production/modules/mysql/templates) y luego agregue las siguientes líneas en el manifiesto:

# Loads /etc/puppetlabs/code/environments/production/modules/mysql/templates/my-custom-config.cnf.erb into /etc/mysql/conf.d/my-custom-config.cnf

file { '/etc/mysql/conf.d/my-custom-config.cnf':
  ensure  => file,
  content => template('mysql/my-custom-config.cnf.erb')
}

Para implementar parámetros específicos de la versión, use la directiva de versión, por ejemplo [mysqld-5.5]. Esto permite una configuración para diferentes versiones de MySQL.

Marioneta vs ClusterControl

¿Sabía que también puede automatizar la implementación de la replicación de MySQL o MariaDB utilizando ClusterControl? Puede usar el módulo ClusterControl Puppet para instalarlo, o simplemente descargándolo de nuestro sitio web.

En comparación con ClusterControl, puede esperar las siguientes diferencias:

  • Una pequeña curva de aprendizaje para comprender la sintaxis, el formato y las estructuras de Puppet antes de poder escribir manifiestos.
  • El manifiesto debe probarse con regularidad. Es muy común que obtenga un error de compilación en el código, especialmente si el catálogo se aplica por primera vez.
  • Puppet supone que los códigos son idempotentes. La condición de prueba/comprobación/verificación cae bajo la responsabilidad del autor para evitar estropear un sistema en ejecución.
  • Puppet requiere un agente en el nodo administrado.
  • Incompatibilidad hacia atrás. Algunos módulos antiguos no se ejecutarían correctamente en la nueva versión.
  • La supervisión de la base de datos/host debe configurarse por separado.

El asistente de implementación de ClusterControl guía el proceso de implementación:

Alternativamente, puede usar la interfaz de línea de comandos de ClusterControl llamada "s9s" para lograr resultados similares. El siguiente comando crea un clúster de replicación MySQL de tres nodos (siempre que se haya configurado sin contraseña para todos los nodos de antemano):

$ s9s cluster --create \
  --cluster-type=mysqlreplication \
      --nodes=192.168.0.41?master;192.168.0.42?slave;192.168.0.43?slave;192.168.0.44?master; \
  --vendor=oracle \
  --cluster-name='MySQL Replication 8.0' \
  --provider-version=8.0 \
  --db-admin='root' \
  --db-admin-passwd='$ecR3t^word' \
  --log
Recursos relacionados Módulo Puppet para ClusterControl:agregar administración y supervisión a sus clústeres de bases de datos existentes Cómo automatizar la implementación de MySQL Galera Cluster mediante s9s CLI y Chef Una guía de DevOps para la automatización de la infraestructura de bases de datos para el comercio electrónico:reproducción y diapositivas

Se admiten las siguientes configuraciones de replicación de MySQL/MariaDB:

  • Replicación maestro-esclavo (basada en archivo/posición)
  • Replicación maestro-esclavo con GTID (MySQL/Percona)
  • Replicación maestro-esclavo con MariaDB GTID
  • Replicación maestro-maestro (semi-sync/async)
  • Replicación de cadena maestro-esclavo (semi-sync/async)

Después de la implementación, ClusterControl puede monitorear y administrar completamente los nodos/clústeres, incluida la detección automática de fallas, la conmutación por error maestra, la promoción de esclavos, la recuperación automática, la administración de copias de seguridad, la administración de configuración, etc. Todos estos están agrupados en un solo producto. La edición comunitaria (¡gratis para siempre!) ofrece implementación y monitoreo. En promedio, su clúster de base de datos estará en funcionamiento en 30 minutos. Lo que necesita es solo SSH sin contraseña para los nodos de destino.

En la siguiente parte, lo guiaremos a través de la implementación de Galera Cluster utilizando el mismo módulo de Puppet. ¡Estén atentos!