MariaDB
 sql >> Base de Dados >  >> RDS >> MariaDB

Automação de banco de dados com Puppet:implantando a replicação MySQL e MariaDB


Puppet é uma ferramenta de gerenciamento de sistemas de código aberto para centralizar e automatizar o gerenciamento de configuração. As ferramentas de automação ajudam a minimizar tarefas manuais e repetitivas e podem economizar muito tempo.

Puppet funciona por padrão em um modelo de servidor/agente. Os agentes buscam seu “catálogo” (estado final desejado) do mestre e o aplicam localmente. Em seguida, eles relatam de volta ao servidor. O catálogo é calculado dependendo dos “fatos” que a máquina envia ao servidor, entrada do usuário (parâmetros) e módulos (código fonte).

Neste blog, mostraremos como implantar e gerenciar instâncias MySQL/MariaDB via Puppet. Existem várias tecnologias em torno do MySQL/MariaDB, como replicação (master-slave, Galera ou replicação de grupo para MySQL), balanceadores de carga com reconhecimento de SQL como ProxySQL e MariaDB MaxScale, ferramentas de backup e recuperação e muito mais que abordaremos neste série de blogs. Há também muitos módulos disponíveis no Puppet Forge construídos e mantidos pela comunidade que podem nos ajudar a simplificar o código e evitar reinventar a roda. Neste blog, vamos nos concentrar na replicação do MySQL.

puppetlabs/mysql


Este é o módulo Puppet mais popular para MySQL e MariaDB (e provavelmente o melhor do mercado) no momento. Este módulo gerencia a instalação e configuração do MySQL, bem como estende o Puppet para permitir o gerenciamento de recursos do MySQL, como bancos de dados, usuários e concessões.

O módulo é mantido oficialmente pela equipe Puppet (através do repositório Puppetlabs Github) e suporta todas as principais versões do Puppet Enterprise 2019.1.x, 2019.0.x, 2018.1.x, Puppet>=5.5.10 <7.0.0 no RedHat, Ubuntu, Plataformas Debian, SLES, Scientific, CentOS, OracleLinux. O usuário tem opções para instalar MySQL, MariaDB e Percona Server personalizando o repositório de pacotes

O exemplo a seguir mostra como implantar um servidor MySQL. No puppet master instale o módulo MySQL e crie o arquivo de manifesto:
(puppet-master)$ puppet module install puppetlabs/mysql
(puppet-master)$ vim /etc/puppetlabs/code/environments/production/manifests/mysql.pp

Adicione as seguintes linhas:
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'
      }
    }
  }
}

Em seguida, no nó do agente puppet, execute o seguinte comando para aplicar o catálogo de configuração:
(db1.local)$ puppet agent -t

Na primeira execução, você pode receber o seguinte erro:
Info: Certificate for db1.local has not been signed yet

Basta executar o seguinte comando no Puppet master para assinar o certificado:
(puppet-master)$ puppetserver ca sign --certname=db1.local
Successfully signed certificate request for db1.local

Tente novamente com o comando "puppet agent -t" para reiniciar a conexão com o certificado assinado.

A definição acima instalará os pacotes padrão relacionados ao MySQL disponíveis no repositório de distribuição do SO. Por exemplo, no Ubuntu 18.04 (Bionic), você obteria os pacotes MySQL 5.7.26 instalados:
(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

Você pode optar por outros fornecedores como Oracle, Percona ou MariaDB com configuração extra no repositório (consulte a seção README para obter detalhes). A definição a seguir instalará os pacotes MariaDB do repositório apt MariaDB (requer o módulo Puppet apt):
$ 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']
}

Observe o valor key->id, onde há uma maneira especial de recuperar o id de 40 caracteres, conforme mostrado neste artigo:
$ 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:

Onde o valor do id está na linha iniciada com "fpr", que é 'A6E773A1812E4B8FD94024AAC0F47944DE8F6914'.

Após a aplicação do catálogo Puppet, você pode acessar diretamente o console MySQL como root sem senha explícita, pois o módulo configura e gerencia ~/.my.cnf automaticamente. Se quisermos redefinir a senha do root para outra coisa, basta alterar o valor root_password na definição do Puppet e aplicar o catálogo no nó do agente.

Implantação de replicação MySQL


Para implantar uma configuração de Replicação MySQL, é preciso criar pelo menos dois tipos de configuração para separar a configuração mestre e escrava. O mestre terá somente leitura desabilitado para permitir leitura/gravação enquanto os escravos serão configurados com somente leitura habilitado. Neste exemplo, vamos usar a replicação baseada em GTID para simplificar a configuração (já que a configuração de todos os nós seria muito semelhante). Vamos querer iniciar o link de replicação para o mestre logo após o escravo estar ativo.

Suponha que estamos tendo 3 nós de replicação mestre-escravo MySQL:
  • db1.local - mestre
  • db2.local - escravo nº 1
  • db3.local - escravo nº 2

Para atender aos requisitos acima, podemos escrever nosso manifesto para algo assim:
# 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
}

Force o agente a aplicar o catálogo:
(all-mysql-nodes)$ puppet agent -t

No mestre (db1.local), podemos verificar todos os escravos 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 atenção extra à seção "exec { 'change master' :", onde significa que um comando MySQL será executado para iniciar o link de replicação se a condição for atendida. Todos os recursos "exec" executados pelo Puppet devem ser idempotentes, ou seja, a operação que terá o mesmo efeito se você executá-lo uma vez ou 10.001 vezes. Existem vários atributos de condição que você pode usar como "unless", "onlyif" e "create" para proteger o estado correto e evitar que o Puppet estrague sua configuração. Você pode excluir/comentar essa seção se desejar iniciar o link de replicação manualmente.

Gerenciamento MySQL


Este módulo pode ser usado para executar várias tarefas de gerenciamento do MySQL:
  • opções de configuração (modificar, aplicar, configuração personalizada)
  • recursos de banco de dados (banco de dados, usuário, concessões)
  • backup (criar, agendar, usuário de backup, armazenamento)
  • restauração simples (somente mysqldump)
  • instalação/ativação de plugins

Recurso de banco de dados


Como você pode ver no manifesto de exemplo acima, definimos dois recursos MySQL - mysql_user e mysql_grant - para criar usuário e conceder privilégios para o usuário, respectivamente. Também podemos usar a classe mysql::db para garantir que um banco de dados com usuário e privilégios associados esteja presente, por exemplo:
  # make sure the database and user exist with proper grant
  mysql::db { 'mynewdb':
    user          => 'mynewuser',
    password      => 'passw0rd',
    host          => '192.168.0.%',
    grant         => ['SELECT', 'UPDATE']
  } 

Observe que na replicação do MySQL, todas as gravações devem ser executadas apenas no mestre. Portanto, certifique-se de que o recurso acima esteja atribuído ao mestre. Caso contrário, pode ocorrer uma transação errônea.

Backup e restauração


Normalmente, apenas um host de backup é necessário para todo o cluster (a menos que você replique um subconjunto de dados). Podemos usar a classe mysql::server::backup para preparar os recursos de backup. Suponha que temos a seguinte declaração em nosso manifesto:
  # 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
  }

O Puppet configurará todos os pré-requisitos antes de executar um backup - criando o usuário de backup, preparando o caminho de destino, atribuindo propriedade e permissão, definindo o cron job e configurando as opções de comando de backup a serem usadas no script de backup fornecido localizado em /usr/local /sbin/mysqlbackup.sh.sh. Cabe então ao usuário executar ou agendar o script. Para fazer um backup imediato, basta invocar:
$ mysqlbackup.sh

Se extrairmos o comando mysqldump real com base no acima, aqui está o que parece:
$ mysqldump --defaults-extra-file=/tmp/backup.NYg0TR --opt --flush-logs --single-transaction --events --set-gtid-purged=OFF --all-databases

Para quem deseja usar outras ferramentas de backup como Percona Xtrabackup, MariaDB Backup (somente MariaDB) ou MySQL Enterprise Backup, o módulo oferece as seguintes classes privadas:
  • mysql::backup::xtrabackup (Percona Xtrabackup e MariaDB Backup)
  • mysql::backup::mysqlbackup (Backup do MySQL Enterprise)

Exemplo de declaração com 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
  }

O acima agendará dois backups, um backup completo todos os domingos às 23h30 e um backup incremental todos os dias, exceto domingo, ao mesmo tempo, conforme mostrado pela saída do cron job após a aplicação do manifesto acima:
(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 mais detalhes e opções disponíveis para esta classe (e outras classes), confira a referência de opções aqui.

Para o aspecto de restauração, o módulo suporta apenas restauração com o método de backup mysqldump, importando o arquivo SQL diretamente para o banco de dados usando a classe mysql::db, por exemplo:
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
}

O arquivo SQL será carregado apenas uma vez e não em todas as execuções, a menos que force_sql => true seja usado.

Opções de configuração


Neste exemplo, usamos manage_config_file => true com override_options para estruturar nossas linhas de configuração que mais tarde serão enviadas pelo Puppet. Qualquer modificação no arquivo de manifesto refletirá apenas o conteúdo do arquivo de configuração MySQL de destino. Este módulo não carregará a configuração em tempo de execução nem reiniciará o serviço MySQL após enviar as alterações para o arquivo de configuração. É responsabilidade do sysadmin reiniciar o serviço para ativar as alterações.

Para adicionar uma configuração personalizada do MySQL, podemos colocar arquivos adicionais em "includedir", padrão para /etc/mysql/conf.d. Isso nos permite substituir configurações ou adicionar outras, o que é útil se você não usar override_options na classe mysql::server. Fazer uso do modelo Puppet é altamente recomendado aqui. Coloque o arquivo de configuração personalizado no diretório do modelo do módulo (padrão para , /etc/puppetlabs/code/environments/production/modules/mysql/templates) e adicione as seguintes linhas no manifesto:
# 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 da versão, use a diretiva version, por exemplo [mysqld-5.5]. Isso permite uma configuração para diferentes versões do MySQL.

Puppet vs ClusterControl


Você sabia que também pode automatizar a implantação da replicação MySQL ou MariaDB usando o ClusterControl? Você pode usar o módulo ClusterControl Puppet para instalá-lo, ou simplesmente baixando-o do nosso site.

Quando comparado ao ClusterControl, você pode esperar as seguintes diferenças:
  • Um pouco de curva de aprendizado para entender as sintaxes, formatação e estruturas do Puppet antes de escrever manifestos.
  • O manifesto deve ser testado regularmente. É muito comum você receber um erro de compilação no código, especialmente se o catálogo for aplicado pela primeira vez.
  • Puppet presume que os códigos sejam idempotentes. A condição de teste/verificação/verificação é de responsabilidade do autor para evitar atrapalhar um sistema em execução.
  • O Puppet requer um agente no nó gerenciado.
  • Incompatibilidade com versões anteriores. Alguns módulos antigos não funcionariam corretamente na nova versão.
  • O monitoramento de banco de dados/host deve ser configurado separadamente.

O assistente de implantação do ClusterControl orienta o processo de implantação:

Como alternativa, você pode usar a interface de linha de comando do ClusterControl chamada "s9s" para obter resultados semelhantes. O comando a seguir cria um cluster de replicação MySQL de três nós (desde que sem senha para todos os nós tenha sido configurado previamente):
$ 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 - Adicionando gerenciamento e monitoramento a seus clusters de banco de dados existentes Como automatizar a implantação do MySQL Galera Cluster usando s9s CLI e Chef Um guia de DevOps para automação de infraestrutura de banco de dados para comércio eletrônico - Replay e slides
As seguintes configurações de replicação MySQL/MariaDB são suportadas:
  • Replicação mestre-escravo (com base em arquivo/posição)
  • Replicação mestre-escravo com GTID (MySQL/Percona)
  • Replicação mestre-escravo com MariaDB GTID
  • Replicação mestre-mestre (semi-sincronização/assíncrona)
  • Replicação de cadeia mestre-escravo (semi-sincronização/assíncrona)

Após a implantação, os nós/clusters podem ser monitorados e totalmente gerenciados pelo ClusterControl, incluindo detecção automática de falhas, failover de mestre, promoção de escravo, recuperação automática, gerenciamento de backup, gerenciamento de configuração e assim por diante. Tudo isso reunido em um único produto. A edição da comunidade (gratuita para sempre!) oferece implantação e monitoramento. Em média, seu cluster de banco de dados estará funcionando em 30 minutos. O que ele precisa é apenas SSH sem senha para os nós de destino.

Na próxima parte, vamos orientá-lo na implantação do Galera Cluster usando o mesmo módulo Puppet. Fique atento!