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!