Estou tentando executar um escravo de replicação do MySQL em um contêiner docker. Estamos executando o MySQL 5.7.24-27-log em produção e é do repositório percona (Ubuntu 18.04).
Eu costumava xtrabackup
fazer backup, preparar e enviar um conjunto de dados inicial para replicação e, em seguida, iniciei a imagem do docker percona ( docker pull percona
) assim:
$ docker run --name mysql-replication -v /replication/data:/var/lib/mysql -v /replication/docker.cnf:/etc/mysql/docker.cnf:ro -e MYSQL_ROOT_PASSWORD=xxxx -P -d percona
Meu docker.cnf simplesmente anota o server-id (eu copiei da percona
imagem).
[mysqld]
skip-host-cache
skip-name-resolve
bind-address = 0.0.0.0
server-id = 4
Depois de usar CHANGE MASTER
etc. Eu tenho a replicação funcionando muito bem.
Minha intenção (de acordo com o volume mount -v /replication/data:/var/lib/mysql
) é manter todos os dados do MySQL na máquina host e tratar o contêiner docker de replicação como efêmero, ou seja, nenhum estado mantido no contêiner. Também deve ser fácil iniciar outro contêiner de replicação, caso eu precise de um, interrompendo o contêiner existente, copiando os dados em outro lugar, alterando server-id
e executando um novo contêiner.
Para testar isso, depois que ele foi configurado e executado corretamente (eu assisti Seconds_Behind_Master
ao menu suspenso 0
), imaginei que deveria ser capaz de excluir o contêiner e recriá-lo, e a replicação ainda funcionaria bem. Por isso, tentei isso:
$ docker stop mysql-replication
$ docker rm mysql-replication
$ docker run ... // same command as before
Quando faço isso e me conecto ao MySQL em execução no contêiner, descubro que Slave_IO_Running
é No
, e depois de iniciá-lo ( START SLAVE;
) recebo o seguinte (como visto em SHOW SLAVE STATUS;
):
Last_Error: Could not execute Update_rows event on table databasename.tablename; Can't find record in 'tablename', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000681, end_log_pos 9952
( databasename
e tablename
são nomes reais de banco de dados e tabelas)
No começo, pensei que provavelmente tinha estragado alguma coisa, mas tentei isso várias vezes agora para tentar resolver o problema. Using docker diff mysql-replication
não mostra alterações no contêiner em execução que parecem ser significativas:
$ docker diff mysql-replication
C /run
C /run/mysqld
A /run/mysqld/mysqld.pid
C /var
C /var/log
A /var/log/mysql
A pesquisa no Google sugeriu que eu preciso usar RESET SLAVE;
e, START SLAVE;
mas isso não parece resolvê-lo - é como se os dados (fora do contêiner) não estivessem mais sincronizados com o mestre e, portanto, a replicação não pudesse continuar.
Alguém pode escolher buracos no que estou fazendo, por favor?
Muito obrigado.
A causa raiz desse problema foi a ausência da
relay-log
opção nomysql.cnf
arquivo (ou, neste caso, devido às montagens de volume do docker, odocker.cnf
arquivo). Isso levou à criação e uso de arquivos como89726507f176-relay-bin.000002
inicialmente, onde89726507f176
é o nome do host da máquina (atribuído aleatoriamente pelo daemon do docker quando uma imagem é criada). Quando o contêiner foi parado, removido e recriado, um novo conjunto de arquivos foi criado e usado (por exemplobe0c801d95bc-relay-bin.000407
, ), mas isso causou problemas de sincronização.Ao especificar explicitamente um valor para
relay-log
nodocker.cnf
arquivo, o contêiner pôde ser removido e recriado sem problemas.Como nota lateral, sugeri também que havia um problema com o diretório /var/log/mysql não sendo montado - este não é o caso. Se, no entanto, você especificar um valor de
log_bin = /var/log/mysql/mysql-bin.log
por exemplo, isso será um requisito. Se você não especificar este caminho, parece que os logs binários são armazenados localmente em /var/lib/mysql que já está montado fora do contêiner.Meu arquivo final
docker.cnf
é o seguinte:Nota:
server_id = 2
no escravo de replicação.Observe também que, sem a
relay-log
opção, o comandoSHOW MASTER STATUS;
não retornou resultados no contêiner do banco de dados mestre.Há um possível problema pendente ainda que, por padrão, quando você o usa
docker stop
, solicita que o contêiner seja encerrado (enviando um SIGHUP para o comando docker entrypoint) e, se não for encerrado em 10 segundos, será interrompido com força. Eu preciso garantir que isso tenha tempo suficiente para desligar, pois pode demorar um pouco para se resolver enquanto estiver sob carga, possivelmente resultando em perda de dados como resultado.