MariaDB
 sql >> Database >  >> RDS >> MariaDB

Automazione del database con Puppet:distribuzione di MySQL e replica MariaDB

Puppet è uno strumento di gestione dei sistemi open source per centralizzare e automatizzare la gestione della configurazione. Gli strumenti di automazione aiutano a ridurre al minimo le attività manuali e ripetitive e possono far risparmiare molto tempo.

Puppet funziona per impostazione predefinita in un modello server/agent. Gli agenti prelevano il loro "catalogo" (stato finale desiderato) dal master e lo applicano localmente. Quindi riportano al server. Il catalogo viene calcolato in base ai "fatti" che la macchina invia al server, all'input dell'utente (parametri) e ai moduli (codice sorgente).

In questo blog ti mostreremo come distribuire e gestire istanze MySQL/MariaDB tramite Puppet. Esistono numerose tecnologie intorno a MySQL/MariaDB come la replica (master-slave, Galera o replica di gruppo per MySQL), bilanciatori del carico SQL come ProxySQL e MariaDB MaxScale, strumenti di backup e ripristino e molti altri che tratteremo in questo serie di blog. Ci sono anche molti moduli disponibili in Puppet Forge costruiti e gestiti dalla community che possono aiutarci a semplificare il codice ed evitare di reinventare la ruota. In questo blog ci concentreremo sulla replica di MySQL.

puppetlabs/mysql

Questo è il modulo Puppet più popolare per MySQL e MariaDB (e probabilmente il migliore sul mercato) in questo momento. Questo modulo gestisce sia l'installazione e la configurazione di MySQL, sia l'estensione di Puppet per consentire la gestione delle risorse MySQL, come database, utenti e sovvenzioni.

Il modulo è ufficialmente mantenuto dal team Puppet (tramite il repository Github di puppetlabs) e supporta tutte le principali versioni di Puppet Enterprise 2019.1.x, 2019.0.x, 2018.1.x, Puppet>=5.5.10 <7.0.0 su RedHat, Ubuntu, Piattaforme Debian, SLES, Scientific, CentOS, OracleLinux. L'utente ha opzioni per installare MySQL, MariaDB e Percona Server personalizzando il repository dei pacchetti

L'esempio seguente mostra come distribuire un server MySQL. Sul burattinaio installa il modulo MySQL e crea il file manifest:

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

Aggiungi le seguenti righe:

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'
      }
    }
  }
}

Quindi, sul nodo dell'agente puppet, esegui il comando seguente per applicare il catalogo di configurazione:

(db1.local)$ puppet agent -t

Alla prima esecuzione, potresti ricevere il seguente errore:

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

Basta eseguire il seguente comando sul Puppet master per firmare il certificato:

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

Riprova con il comando "puppet agent -t" per riavviare la connessione con il certificato firmato.

La definizione di cui sopra installerà i pacchetti standard relativi a MySQL disponibili nel repository di distribuzione del sistema operativo. Ad esempio, su Ubuntu 18.04 (Bionic), avresti installato i pacchetti 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

Puoi optare per altri fornitori come Oracle, Percona o MariaDB con una configurazione aggiuntiva sul repository (fare riferimento alla sezione README per i dettagli). La seguente definizione installerà i pacchetti MariaDB dal repository apt di MariaDB (richiede il modulo 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']
}

Prendi nota del valore chiave->id, dove esiste un modo speciale per recuperare l'id di 40 caratteri come mostrato in questo articolo:

$ 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:

Dove il valore id è nella riga che inizia con "fpr", che è "A6E773A1812E4B8FD94024AAC0F47944DE8F6914".

Dopo aver applicato il catalogo Puppet, puoi accedere direttamente alla console MySQL come root senza password esplicita poiché il modulo configura e gestisce ~/.my.cnf automaticamente. Se desideriamo reimpostare la password di root su qualcos'altro, è sufficiente modificare il valore root_password nella definizione del pupazzo e applicare il catalogo sul nodo dell'agente.

Distribuzione della replica MySQL

Per implementare una configurazione di replica MySQL, è necessario creare almeno due tipi di configurazione per separare la configurazione master e quella slave. Il master avrà la sola lettura disabilitata per consentire la lettura/scrittura mentre gli slave saranno configurati con la sola lettura abilitata. In questo esempio, utilizzeremo la replica basata su GTID per semplificare la configurazione (poiché la configurazione di tutti i nodi sarebbe molto simile). Vorremo avviare il collegamento di replica al master subito dopo che lo slave è attivo.

Supponiamo di avere 3 nodi di replica MySQL master-slave:

  • db1.local - master
  • db2.local - slave n. 1
  • db3.local - slave n. 2

Per soddisfare i requisiti di cui sopra, possiamo annotare il nostro manifest in qualcosa del genere:

# 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
}

Forza l'agente ad applicare il catalogo:

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

Sul master (db1.local) possiamo verificare tutti gli slave collegati:

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 |
+-----------+-----------+------+-----------+--------------------------------------+

Presta particolare attenzione alla sezione "exec { 'change master' :" , dove significa che verrà eseguito un comando MySQL per avviare il collegamento di replica se la condizione è soddisfatta. Tutte le risorse "exec" eseguite da Puppet devono essere idempotenti, ovvero l'operazione che avrà lo stesso effetto sia che venga eseguita una volta o 10.001 volte. Ci sono una serie di attributi di condizione che puoi usare come "unless", "onlyif" e "create" per salvaguardare lo stato corretto ed evitare che Puppet incasini con la tua configurazione. Puoi eliminare/commentare quella sezione se desideri avviare manualmente il collegamento di replica.

Gestione MySQL

Questo modulo può essere utilizzato per eseguire una serie di attività di gestione di MySQL:

  • opzioni di configurazione (modifica, applica, configurazione personalizzata)
  • risorse del database (database, utente, sovvenzioni)
  • backup (creazione, pianificazione, backup utente, archiviazione)
  • ripristino semplice (solo mysqldump)
  • Installazione/attivazione plugin

Risorsa database

Come puoi vedere nel manifest di esempio sopra, abbiamo definito due risorse MySQL - mysql_user e mysql_grant - per creare rispettivamente l'utente e concedere i privilegi per l'utente. Possiamo anche usare la classe mysql::db per garantire che sia presente un database con utente e privilegi associati, ad esempio:

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

Tieni presente che nella replica MySQL, tutte le scritture devono essere eseguite solo sul master. Quindi, assicurati che la risorsa sopra sia assegnata al master. In caso contrario, potrebbe verificarsi una transazione errata.

Backup e ripristino

In genere, è necessario un solo host di backup per l'intero cluster (a meno che non si replichi un sottoinsieme di dati). Possiamo usare la classe mysql::server::backup per preparare le risorse di backup. Supponiamo di avere la seguente dichiarazione nel nostro manifest:

  # 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 configurerà tutti i prerequisiti prima di eseguire un backup:creazione dell'utente di backup, preparazione del percorso di destinazione, assegnazione di proprietà e autorizzazione, impostazione del processo cron e impostazione delle opzioni del comando di backup da utilizzare nello script di backup fornito situato in /usr/local /sbin/mysqlbackup.sh. Spetta quindi all'utente eseguire o pianificare lo script. Per effettuare un backup immediato, è sufficiente invocare:

$ mysqlbackup.sh

Se estraiamo il comando mysqldump effettivo in base a quanto sopra, ecco come appare:

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

Per coloro che desiderano utilizzare altri strumenti di backup come Percona Xtrabackup, MariaDB Backup (solo MariaDB) o MySQL Enterprise Backup, il modulo fornisce le seguenti classi private:

  • mysql::backup::xtrabackup (Percona Xtrabackup e MariaDB Backup)
  • mysql::backup::mysqlbackup (backup di MySQL Enterprise)

Esempio di dichiarazione 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
  }

Quanto sopra pianificherà due backup, un backup completo ogni domenica alle 23:30 e un backup incrementale ogni giorno eccetto la domenica alla stessa ora, come mostrato dall'output del processo cron dopo l'applicazione del manifest precedente:

(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

Per maggiori dettagli e opzioni disponibili per questa classe (e altre classi), controlla il riferimento alle opzioni qui.

Per l'aspetto del ripristino, il modulo supporta solo il ripristino con il metodo di backup mysqldump, importando il file SQL direttamente nel database utilizzando la classe mysql::db, ad esempio:

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
}

Il file SQL verrà caricato solo una volta e non a ogni esecuzione, a meno che non venga utilizzato force_sql => true.

Opzioni di configurazione

In questo esempio, abbiamo usato manage_config_file => true con override_options per strutturare le nostre linee di configurazione che in seguito verranno espulse da Puppet. Qualsiasi modifica al file manifest rifletterà solo il contenuto del file di configurazione MySQL di destinazione. Questo modulo non caricherà la configurazione in runtime né riavvierà il servizio MySQL dopo aver inserito le modifiche nel file di configurazione. È responsabilità dell'amministratore di sistema riavviare il servizio per attivare le modifiche.

Per aggiungere una configurazione MySQL personalizzata, possiamo inserire file aggiuntivi in ​​"includedir", predefinito su /etc/mysql/conf.d. Questo ci consente di sovrascrivere le impostazioni o aggiungerne altre, il che è utile se non usi override_options nella classe mysql::server. L'utilizzo del modello Puppet è altamente raccomandato qui. Posiziona il file di configurazione personalizzato nella directory del modello del modulo (impostazione predefinita , /etc/puppetlabs/code/environments/production/modules/mysql/templates) e quindi aggiungi le seguenti righe nel manifest:

# 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')
}

Per implementare parametri specifici della versione, utilizzare la direttiva version, ad esempio [mysqld-5.5]. Ciò consente una configurazione per diverse versioni di MySQL.

Puppet vs ClusterControl

Sapevi che puoi anche automatizzare la distribuzione della replica MySQL o MariaDB utilizzando ClusterControl? Puoi utilizzare il modulo ClusterControl Puppet per installarlo o semplicemente scaricandolo dal nostro sito Web.

Rispetto a ClusterControl, puoi aspettarti le seguenti differenze:

  • Un po' di curva di apprendimento per comprendere le sintassi, la formattazione e le strutture dei pupazzi prima di poter scrivere manifest.
  • Il manifesto deve essere testato regolarmente. È molto comune ricevere un errore di compilazione sul codice soprattutto se il catalogo viene applicato per la prima volta.
  • Il burattino presume che i codici siano idempotenti. La condizione di test/verifica/verifica rientra nella responsabilità dell'autore per evitare di incasinare un sistema in esecuzione.
  • Il pupazzo richiede un agente sul nodo gestito.
  • Incompatibilità a ritroso. Alcuni vecchi moduli non funzionerebbero correttamente sulla nuova versione.
  • Il monitoraggio del database/dell'host deve essere impostato separatamente.

La procedura guidata di distribuzione di ClusterControl guida il processo di distribuzione:

In alternativa, è possibile utilizzare l'interfaccia della riga di comando di ClusterControl denominata "s9s" per ottenere risultati simili. Il comando seguente crea un cluster di replica MySQL a tre nodi (a condizione che tutti i nodi siano configurati senza password):

$ 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
Risorse correlate Modulo pupazzo per ClusterControl:aggiunta di gestione e monitoraggio ai cluster di database esistenti Come automatizzare la distribuzione di MySQL Galera Cluster utilizzando s9s CLI e Chef Una guida DevOps all'automazione dell'infrastruttura di database per l'eCommerce - Replay e diapositive

Sono supportate le seguenti configurazioni di replica MySQL/MariaDB:

  • Replica master-slave (basata su file/posizione)
  • Replica master-slave con GTID (MySQL/Percona)
  • Replica master-slave con MariaDB GTID
  • Replica master-master (semi-sync/async)
  • Replica della catena master-slave (semi-sync/async)

Dopo l'implementazione, i nodi/cluster possono essere monitorati e gestiti completamente da ClusterControl, incluso il rilevamento automatico degli errori, il failover principale, la promozione dello slave, il ripristino automatico, la gestione del backup, la gestione della configurazione e così via. Tutti questi sono raggruppati in un unico prodotto. L'edizione community (gratuita per sempre!) offre distribuzione e monitoraggio. In media, il tuo cluster di database sarà attivo e funzionante entro 30 minuti. Ciò di cui ha bisogno è solo SSH senza password per i nodi di destinazione.

Nella parte successiva, ti guideremo attraverso la distribuzione del cluster Galera utilizzando lo stesso modulo Puppet. Resta sintonizzato!