Como vimos na primeira parte deste blog, um cluster de banco de dados fortemente consistente como o Galera não funciona bem com ferramentas de orquestração de contêineres como Kubernetes ou Swarm. Mostramos como implantar o Galera e configurar o gerenciamento de processos para o Docker, para que você mantenha o controle total do comportamento. Esta postagem no blog é a continuação disso, vamos analisar a operação e manutenção do cluster.
Para recapitular alguns dos principais pontos da parte 1 deste blog, implantamos um cluster Galera de três nós, com ProxySQL e Keepalived em três hosts Docker diferentes, onde todas as instâncias do MariaDB são executadas como contêineres do Docker. O diagrama a seguir ilustra a implantação final:
Desligamento normal
Para executar um desligamento normal do MySQL, a melhor maneira é enviar SIGTERM (sinal 15) para o contêiner:
$ docker kill -s 15 {db_container_name}
Se desejar encerrar o cluster, repita o comando acima em todos os contêineres de banco de dados, um nó por vez. O acima é semelhante a executar "systemctl stop mysql" no serviço systemd para MariaDB. Usar o comando "docker stop" é bastante arriscado para o serviço de banco de dados porque ele aguarda 10 segundos de tempo limite e o Docker forçará o SIGKILL se essa duração for excedida (a menos que você use um --timeout adequado valor).
O último nó que for encerrado normalmente terá o seqno diferente de -1 e safe_to_bootstrap sinalizador é definido como 1 no /{datadir volume}/grastate.dat do host do Docker, por exemplo, no 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
Detectando o nó mais avançado
Se o cluster não for encerrado normalmente ou o nó que você estava tentando inicializar não for o último nó a sair do cluster, você provavelmente não conseguirá inicializar um dos nós do Galera e poderá encontrar o seguinte erro :
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 o nó que tem safe_to_bootstrap sinalizador definido como 1 como o primeiro nó de referência. Essa é a maneira mais segura de evitar a perda de dados e garantir que o nó correto sempre seja inicializado.
Se você recebeu o erro, temos que descobrir o nó mais avançado primeiro antes de escolher o nó como o primeiro a ser inicializado. Crie um contêiner temporário (com --rm flag), mapeie-o para o mesmo diretório de dados e diretório de configuração do contêiner de banco de dados real com dois sinalizadores de comando MySQL, --wsrep_recover e --wsrep_cluster_address . Por exemplo, se quisermos saber o último número confirmado de mariadb1, precisamos executar:
$ 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
A última linha é o que estamos procurando. O MariaDB imprime o UUID do cluster e o número de sequência da transação confirmada mais recentemente. O nó que contém o maior número é considerado o nó mais avançado. Como especificamos --rm , o contêiner será removido automaticamente assim que sair. Repita a etapa acima em cada host do Docker substituindo o --volume caminho para os respectivos volumes de contêiner de banco de dados.
Depois de comparar o valor relatado por todos os contêineres de banco de dados e decidir qual contêiner é o nó mais atualizado, altere o safe_to_bootstrap sinalizar para 1 dentro de /{datadir volume}/grastate.dat manualmente. Digamos que todos os nós estão relatando o mesmo número de sequência exato, podemos apenas escolher mariadb3 para ser inicializado alterando o safe_to_bootstrap valor para 1:
$ vim /containers/mariadb3/datadir/grasate.dat
...
safe_to_bootstrap: 1
Salve o arquivo e comece a autoinicializar o cluster a partir desse nó, conforme descrito no próximo capítulo.
Reinicializando o cluster
A inicialização do cluster é semelhante ao primeiro comando docker run que usamos ao inicializar o cluster pela primeira vez. Se mariadb1 for o nó de bootstrap escolhido, podemos simplesmente executar novamente o contêiner de bootstrap criado:
$ docker start mariadb0 # on host1
Caso contrário, se o container bootstrap não existir no nó escolhido, digamos no host2, execute o comando bootstrap container e mapeie os volumes existentes do mariadb2. Estamos usando mariadb0 como o nome do contêiner no host2 para indicar que é um contêiner de bootstrap:
$ 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
Você pode notar que este comando é um pouco mais curto em comparação com o comando bootstrap anterior descrito neste guia. Como já temos o usuário proxysql criado em nosso primeiro comando bootstrap, podemos pular essas duas variáveis de ambiente:
- --env MYSQL_USER=proxysql
- --env MYSQL_PASSWORD=proxysqlpassword
Em seguida, inicie os contêineres MariaDB restantes, remova o contêiner de bootstrap e inicie o contêiner MariaDB existente no host de bootstrap. Basicamente a ordem dos comandos seria:
$ docker start mariadb1 # on host1
$ docker start mariadb3 # on host3
$ docker stop mariadb0 # on host2
$ docker start mariadb2 # on host2
Neste ponto, o cluster é iniciado e está funcionando com capacidade total.
Controle de recursos
A memória é um recurso muito importante no MySQL. É aqui que os buffers e caches são armazenados, e é fundamental para o MySQL reduzir o impacto de atingir o disco com muita frequência. Por outro lado, a troca é ruim para o desempenho do MySQL. Por padrão, não haverá restrições de recursos nos contêineres em execução. Os contêineres usam tanto de um determinado recurso quanto o kernel do host permitir. Outra coisa importante é o limite do descritor de arquivo. Você pode aumentar o limite do descritor de arquivo aberto, ou "nofile" para algo maior para atender ao número de arquivos que o servidor MySQL pode abrir simultaneamente. Definir isso para um valor alto não vai doer.
Para limitar a alocação de memória e aumentar o limite do descritor de arquivo para nosso contêiner de banco de dados, deve-se anexar --memory , --memória-troca e --ulimit parâmetros no 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
Observe que se --memory-swap é definido com o mesmo valor que --memory , e --memória for definido como um número inteiro positivo, o contêiner não terá acesso à troca. Se --memory-swap não estiver definido, a troca de contêiner será padrão para --memory multiplique por 2. Se --memory e --memória-troca forem definidos com o mesmo valor, isso impedirá que os contêineres usem qualquer troca. Isso ocorre porque --memory-swap é a quantidade combinada de memória e troca que pode ser usada, enquanto --memory é apenas a quantidade de memória física que pode ser usada.
Alguns dos recursos do contêiner, como memória e CPU, podem ser controlados dinamicamente por meio do comando "docker update", conforme mostrado no exemplo a seguir, para atualizar a memória do contêiner mariadb1 para 32G dinamicamente:
$ docker update \
--memory 32g \
--memory-swap 32g \
mariadb1
Não se esqueça de ajustar o my.cnf de acordo com as novas especificações. O gerenciamento de configuração é explicado na próxima seção.
Gerenciamento de configuração
A maioria dos parâmetros de configuração do MySQL/MariaDB pode ser alterada durante o tempo de execução, o que significa que você não precisa reiniciar para aplicar as alterações. Confira a página de documentação do MariaDB para obter detalhes. O parâmetro listado com "Dynamic:Yes" significa que a variável é carregada imediatamente após a alteração sem a necessidade de reiniciar o servidor MariaDB. Caso contrário, defina os parâmetros dentro do arquivo de configuração personalizado no host do Docker. Por exemplo, em mariadb3, faça as alterações no seguinte arquivo:
$ vim /containers/mariadb3/conf.d/my.cnf
E, em seguida, reinicie o contêiner do banco de dados para aplicar a alteração:
$ docker restart mariadb3
Verifique se o contêiner inicia o processo observando os logs do docker. Execute esta operação em um nó por vez se desejar fazer alterações em todo o cluster.
Backup
Fazer um backup lógico é bastante simples porque a imagem MariaDB também vem com o binário mysqldump. Você simplesmente usa o comando "docker exec" para executar o mysqldump e enviar a saída para um arquivo relativo ao caminho do host. O comando a seguir executa o backup do mysqldump no mariadb2 e o salva em /backups/mariadb2 dentro do host2:
$ docker exec -it mariadb2 mysqldump -uroot -p --single-transaction > /backups/mariadb2/dump.sql
Backup binário como Percona Xtrabackup ou MariaDB Backup requer que o processo acesse diretamente o diretório de dados do MariaDB. Você precisa instalar essa ferramenta dentro do contêiner ou através do host da máquina ou usar uma imagem dedicada para essa finalidade, como a imagem "perconalab/percona-xtrabackup" para criar o backup e armazená-lo dentro de /tmp/backup no host do 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
Você também pode parar o contêiner com innodb_fast_shutdown defina como 0 e copie o volume datadir para outro local no 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
A restauração é bastante simples para o mysqldump. Você pode simplesmente redirecionar o stdin para o contêiner do host físico:
$ docker exec -it mariadb2 mysql -uroot -p < /backups/mariadb2/dump.sql
Você também pode usar a linha de comando padrão do cliente mysql remotamente com o nome do host e o valor da porta adequados em vez de usar este comando "docker exec":
$ mysql -uroot -p -h127.0.0.1 -P3306 < /backups/mariadb2/dump.sql
Para Percona Xtrabackup e MariaDB Backup, temos que preparar o backup com antecedência. Isso avançará o backup para o momento em que o backup foi concluído. Digamos que nossos arquivos Xtrabackup estejam localizados em /tmp/backup do host Docker, para prepará-lo, basta:
$ docker run --rm -it \
-v mysql-datadir:/var/lib/mysql \
-v /tmp/backup:/xtrabackup_backupfiles \
perconalab/percona-xtrabackup \
--prepare --target-dir /xtrabackup_backupfiles
O backup preparado em /tmp/backup do host do Docker pode ser usado como o datadir MariaDB para um novo contêiner ou cluster. Digamos que queremos apenas verificar a restauração em um contêiner MariaDB autônomo, executarí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
Se você executou um backup usando a abordagem stop and copy, você pode simplesmente duplicar o datadir e usar o diretório duplicado como um mapa de volume para o datadir do MariaDB para executar em outro contêiner. Digamos que o backup foi copiado em /backups/mariadb2/datadir_copied, podemos executar um novo contêiner executando:
$ 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
O MYSQL_ROOT_PASSWORD deve corresponder à senha raiz real desse backup específico.
Vários noves MySQL no Docker:como conteinerizar seu banco de dadosDescubra tudo o que você precisa entender ao considerar executar um serviço MySQL em cima da virtualização de contêiner do DockerBaixe o whitepaper
Atualização da versão do banco de dados
Existem dois tipos de atualização - atualização in-loco ou atualização lógica.
A atualização in-loco envolve desligar o servidor MariaDB, substituir os binários antigos pelos novos binários e, em seguida, iniciar o servidor no diretório de dados antigo. Uma vez iniciado, você deve executar mysql_upgrade script para verificar e atualizar todas as tabelas do sistema e também para verificar as tabelas de usuários.
A atualização lógica envolve a exportação do SQL da versão atual usando um utilitário de backup lógico, como mysqldump, executando o novo contêiner com os binários da versão atualizada e, em seguida, aplicando o SQL à nova versão do MySQL/MariaDB. É semelhante à abordagem de backup e restauração descrita na seção anterior.
No entanto, é uma boa abordagem sempre fazer backup de seu banco de dados antes de realizar qualquer operação destrutiva. As etapas a seguir são necessárias ao atualizar da imagem atual, MariaDB 10.1.33 para outra versão principal, MariaDB 10.2.15 em mariadb3 reside no host3:
-
Faça backup do banco de dados. Não importa o backup físico ou lógico, mas o último usando mysqldump é recomendado.
-
Faça o download da imagem mais recente para a qual gostaríamos de atualizar:
$ docker pull mariadb:10.2.15
-
Defina innodb_fast_shutdown como 0 para nosso contêiner de banco de dados:
$ docker exec -it mariadb3 mysql -uroot -p -e 'SET GLOBAL innodb_fast_shutdown = 0'
-
Graceful encerre o contêiner de banco de dados:
$ docker kill --signal=TERM mariadb3
-
Crie um novo contêiner com a nova imagem para nosso contêiner de banco de dados. Mantenha o restante dos parâmetros intactos, exceto usando o novo nome do contêiner (caso contrário, entraria em conflito):
$ 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
-
Execute o script mysql_upgrade:
$ docker exec -it mariadb3-new mysql_upgrade -uroot -p
-
Se nenhum erro ocorreu, remova o contêiner antigo, mariadb3 (o novo é mariadb3-new):
$ docker rm -f mariadb3
-
Caso contrário, se o processo de atualização falhar no meio, podemos voltar ao contêiner anterior:
$ docker stop mariadb3-new $ docker start mariadb3
A atualização da versão principal pode ser executada de forma semelhante à atualização da versão secundária, exceto que você deve ter em mente que o MySQL/MariaDB suporta apenas a atualização principal da versão anterior. Se você estiver no MariaDB 10.0 e gostaria de atualizar para o 10.2, será necessário atualizar primeiro para o MariaDB 10.1, seguido por outra etapa de atualização para o MariaDB 10.2.
Anote as alterações de configuração que estão sendo introduzidas e obsoletas entre as versões principais.
Failover
No Galera, todos os nós são mestres e possuem a mesma função. Com o ProxySQL na imagem, as conexões que passam por esse gateway sofrerão failover automaticamente, desde que haja um componente primário em execução para o Galera Cluster (ou seja, a maioria dos nós está ativa). O aplicativo não notará nenhuma diferença se um nó do banco de dados ficar inativo porque o ProxySQL simplesmente redirecionará as conexões para os outros nós disponíveis.
Se o aplicativo se conectar diretamente ao MariaDB ignorando o ProxySQL, o failover deve ser executado no lado do aplicativo, apontando para o próximo nó disponível, desde que o nó do banco de dados atenda às seguintes condições:
- Status wsrep_local_state_comment está sincronizado (O estado "Dessincronizado/Doador" também é possível, somente se wsrep_sst_method é xtrabackup, xtrabackup-v2 ou mariabackup).
- Status wsrep_cluster_status é Primário.
No Galera, um nó disponível não significa que está íntegro até que o status acima seja verificado.
Escalando para fora
Para expandir, podemos criar um novo contêiner na mesma rede e usar o mesmo arquivo de configuração personalizado para o contêiner existente nesse host específico. Por exemplo, digamos que queremos adicionar o quarto container MariaDB no host3, podemos usar o mesmo arquivo de configuração montado para mariadb3, conforme ilustrado no diagrama a seguir:
Execute o seguinte comando no host3 para dimensionar 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
Depois que o contêiner for criado, ele ingressará no cluster e executará o SST. Ele pode ser acessado na porta 3307 externamente ou fora da rede Weave, ou na porta 3306 dentro do host ou dentro da rede Weave. Não é mais necessário incluir mariadb0.weave.local no endereço do cluster. Depois que o cluster for dimensionado, precisamos adicionar o novo contêiner MariaDB ao conjunto de balanceamento de carga ProxySQL por meio do console de administração:
$ 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 os comandos acima na segunda instância do ProxySQL.
Finalmente, para a última etapa, (você pode pular esta parte se já executou a instrução "SAVE .. TO DISK" no ProxySQL), adicione a seguinte linha em proxysql.cnf para torná-la persistente na reinicialização do contêiner em host1 e host2:
$ vim /containers/proxysql1/proxysql.cnf # host1
$ vim /containers/proxysql2/proxysql.cnf # host2
E acrescente linhas relacionadas ao mariadb4 na diretiva 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 }
)
Salve o arquivo e devemos estar bem na próxima reinicialização do contêiner.
Diminuição
Para reduzir, basta desligar o contêiner normalmente. O melhor comando seria:
$ docker kill -s 15 mariadb4
$ docker rm -f mariadb4
Lembre-se de que, se o nó do banco de dados deixasse o cluster de forma inadequada, ele não fazia parte da redução e afetaria o cálculo do quorum.
Para remover o contêiner do ProxySQL, execute os comandos a seguir em ambos os contêineres do ProxySQL. Por exemplo, em 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;
Você pode então remover a entrada correspondente dentro do proxysql.cnf ou simplesmente deixá-la assim. Ele será detectado como OFFLINE do ponto de vista do ProxySQL de qualquer maneira.
Resumo
Com o Docker, as coisas ficam um pouco diferentes da maneira convencional de lidar com servidores MySQL ou MariaDB. O manuseio de serviços com estado, como o Galera Cluster, não é tão fácil quanto os aplicativos sem estado e requer testes e planejamento adequados.
Em nosso próximo blog sobre este tópico, avaliaremos os prós e contras de executar o Galera Cluster no Docker sem nenhuma ferramenta de orquestração.