O monitoramento é uma preocupação para os containers, pois a infraestrutura é dinâmica. Os contêineres podem ser criados e destruídos rotineiramente e são efêmeros. Então, como você acompanha suas instâncias MySQL em execução no Docker?
Como acontece com qualquer componente de software, existem muitas opções que podem ser usadas. Veremos o Prometheus como uma solução criada para infraestrutura distribuída e funciona muito bem com o Docker.
Este é um blog de duas partes. Neste blog da parte 1, abordaremos o aspecto de implantação de nossos contêineres MySQL com o Prometheus e seus componentes, executados como contêineres Docker autônomos e serviços Docker Swarm. Na parte 2, veremos as métricas importantes para monitorar de nossos contêineres MySQL, bem como a integração com os sistemas de paginação e notificação.
Introdução ao Prometheus
O Prometheus é um sistema completo de monitoramento e tendências que inclui captura, armazenamento, consulta, gráficos e alertas integrados e ativos com base em dados de séries temporais. O Prometheus coleta métricas por meio do mecanismo de pull de destinos configurados em determinados intervalos, avalia expressões de regras, exibe os resultados e pode acionar alertas se alguma condição for observada como verdadeira. Ele suporta todas as métricas de destino que queremos medir se alguém quiser executar o MySQL como contêineres do Docker. Essas métricas incluem métricas de hosts físicos, métricas de contêiner do Docker e métricas de servidor MySQL.
Dê uma olhada no diagrama a seguir que ilustra a arquitetura do Prometheus (retirado da documentação oficial do Prometheus):
Vamos implantar alguns contêineres MySQL (independentes e Docker Swarm) completos com um servidor Prometheus, exportador MySQL (ou seja, um agente Prometheus para expor as métricas do MySQL, que podem ser extraídas pelo servidor Prometheus) e também Alertmanager para lidar com alertas baseados nas métricas coletadas.
Para obter mais detalhes, consulte a documentação do Prometheus. Neste exemplo, usaremos as imagens oficiais do Docker fornecidas pela equipe do Prometheus.
Docker autônomo
Implantando contêineres MySQL
Vamos executar dois servidores MySQL autônomos no Docker para simplificar nosso passo a passo de implantação. Um contêiner usará o MySQL 8.0 mais recente e o outro é o MySQL 5.7. Ambos os contêineres estão na mesma rede do Docker chamada "db_network":
$ docker network create db_network
$ docker run -d \
--name mysql80 \
--publish 3306 \
--network db_network \
--restart unless-stopped \
--env MYSQL_ROOT_PASSWORD=mypassword \
--volume mysql80-datadir:/var/lib/mysql \
mysql:8 \
--default-authentication-plugin=mysql_native_password
O padrão do MySQL 8 é um novo plug-in de autenticação chamado caching_sha2_password . Para compatibilidade com o contêiner do exportador Prometheus MySQL, vamos usar a amplamente usada mysql_native_password plugin sempre que criamos um novo usuário MySQL neste servidor.
Para o segundo contêiner MySQL executando 5.7, executamos o seguinte:
$ docker run -d \
--name mysql57 \
--publish 3306 \
--network db_network \
--restart unless-stopped \
--env MYSQL_ROOT_PASSWORD=mypassword \
--volume mysql57-datadir:/var/lib/mysql \
mysql:5.7
Verifique se nossos servidores MySQL estão rodando OK:
[[email protected] mysql]# docker ps | grep mysql
cc3cd3c4022a mysql:5.7 "docker-entrypoint.s…" 12 minutes ago Up 12 minutes 0.0.0.0:32770->3306/tcp mysql57
9b7857c5b6a1 mysql:8 "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 0.0.0.0:32769->3306/tcp mysql80
Neste ponto, nossa arquitetura está mais ou menos assim:
Vamos começar a monitorá-los.
Exposição de métricas do Docker ao Prometheus
O Docker possui suporte integrado como destino do Prometheus, onde podemos usar para monitorar as estatísticas do mecanismo do Docker. Podemos simplesmente habilitá-lo criando um arquivo de texto chamado "daemon.json" dentro do host do Docker:
$ vim /etc/docker/daemon.json
E adicione as seguintes linhas:
{
"metrics-addr" : "12.168.55.161:9323",
"experimental" : true
}
Em que 192.168.55.161 é o endereço IP primário do host do Docker. Em seguida, reinicie o daemon do Docker para carregar a alteração:
$ systemctl restart docker
Como definimos --restart=unless-stopped no comando run dos nossos contêineres MySQL, os contêineres serão iniciados automaticamente após a execução do Docker.
Implantando o MySQL Exporter
Antes de prosseguirmos, o exportador mysqld requer que um usuário MySQL seja usado para fins de monitoramento. Em nossos contêineres MySQL, crie o usuário de monitoramento:
$ docker exec -it mysql80 mysql -uroot -p
Enter password:
mysql> CREATE USER 'exporter'@'%' IDENTIFIED BY 'exporterpassword' WITH MAX_USER_CONNECTIONS 3;
mysql> GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';
Observe que é recomendável definir um limite máximo de conexão para o usuário para evitar sobrecarregar o servidor com monitoramento de rascunhos sob carga pesada. Repita as instruções acima no segundo contêiner, mysql57:
$ docker exec -it mysql57 mysql -uroot -p
Enter password:
mysql> CREATE USER 'exporter'@'%' IDENTIFIED BY 'exporterpassword' WITH MAX_USER_CONNECTIONS 3;
mysql> GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';
Vamos executar o contêiner do exportador mysqld chamado "mysql8-exporter" para expor as métricas para nossa instância MySQL 8.0 conforme abaixo:
$ docker run -d \
--name mysql80-exporter \
--publish 9104 \
--network db_network \
--restart always \
--env DATA_SOURCE_NAME="exporter:[email protected](mysql80:3306)/" \
prom/mysqld-exporter:latest \
--collect.info_schema.processlist \
--collect.info_schema.innodb_metrics \
--collect.info_schema.tablestats \
--collect.info_schema.tables \
--collect.info_schema.userstats \
--collect.engine_innodb_status
E também outro contêiner exportador para nossa instância MySQL 5.7:
$ docker run -d \
--name mysql57-exporter \
--publish 9104 \
--network db_network \
--restart always \
-e DATA_SOURCE_NAME="exporter:[email protected](mysql57:3306)/" \
prom/mysqld-exporter:latest \
--collect.info_schema.processlist \
--collect.info_schema.innodb_metrics \
--collect.info_schema.tablestats \
--collect.info_schema.tables \
--collect.info_schema.userstats \
--collect.engine_innodb_status
Habilitamos vários sinalizadores de coletor para o contêiner para expor as métricas do MySQL. Você também pode habilitar --collect.slave_status, --collect.slave_hosts se você tiver uma replicação MySQL rodando em containers.
Devemos ser capazes de recuperar as métricas do MySQL via curl diretamente do host do Docker (a porta 32771 é a porta publicada atribuída automaticamente pelo Docker para o contêiner mysql80-exporter):
$ curl 127.0.0.1:32771/metrics
...
mysql_info_schema_threads_seconds{state="waiting for lock"} 0
mysql_info_schema_threads_seconds{state="waiting for table flush"} 0
mysql_info_schema_threads_seconds{state="waiting for tables"} 0
mysql_info_schema_threads_seconds{state="waiting on cond"} 0
mysql_info_schema_threads_seconds{state="writing to net"} 0
...
process_virtual_memory_bytes 1.9390464e+07
Neste ponto, nossa arquitetura está mais ou menos assim:
Agora estamos prontos para configurar o servidor Prometheus.
Implantando o Prometheus Server
Primeiramente, crie o arquivo de configuração do Prometheus em ~/prometheus.yml e adicione as seguintes linhas:
$ vim ~/prometheus.yml
global:
scrape_interval: 5s
scrape_timeout: 3s
evaluation_interval: 5s
# Our alerting rule files
rule_files:
- "alert.rules"
# Scrape endpoints
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'mysql'
static_configs:
- targets: ['mysql57-exporter:9104','mysql80-exporter:9104']
- job_name: 'docker'
static_configs:
- targets: ['192.168.55.161:9323']
A partir do arquivo de configuração do Prometheus, definimos três jobs - "prometheus", "mysql" e "docker". O primeiro é o trabalho de monitorar o próprio servidor Prometheus. O próximo é o trabalho de monitorar nossos contêineres MySQL chamados "mysql". Definimos os endpoints em nossos exportadores MySQL na porta 9104, que expuseram as métricas compatíveis com Prometheus das instâncias MySQL 8.0 e 5.7, respectivamente. O "alert.rules" é o arquivo de regras que incluiremos posteriormente na próxima postagem do blog para fins de alerta.
Podemos então mapear a configuração com o container Prometheus. Também precisamos criar um volume do Docker para dados do Prometheus para persistência e também expor a porta 9090 publicamente:
$ docker run -d \
--name prometheus-server \
--publish 9090:9090 \
--network db_network \
--restart unless-stopped \
--mount type=volume,src=prometheus-data,target=/prometheus \
--mount type=bind,src="$(pwd)"/prometheus.yml,target=/etc/prometheus/prometheus.yml \
--mount type=bind,src="$(pwd)
prom/prometheus
Agora nosso servidor Prometheus já está em execução e pode ser acessado diretamente na porta 9090 do host Docker. Abra um navegador da Web e acesse http://192.168.55.161:9090/ para acessar a interface do usuário da Web do Prometheus. Verifique o status do alvo em Status -> Targets e certifique-se de que estejam todos verdes:
Neste ponto, nossa arquitetura de contêiner está parecida com isto:
Nosso sistema de monitoramento Prometheus para nossos contêineres MySQL autônomos já está implantado.
Enxame do Docker
Implantando um Galera Cluster de 3 nós
Supondo que queiramos implantar um Galera Cluster de três nós no Docker Swarm, teríamos que criar 3 serviços diferentes, cada serviço representando um nó Galera. Usando essa abordagem, podemos manter um nome de host resolvível estático para nosso contêiner Galera, juntamente com os contêineres exportadores do MySQL que acompanharão cada um deles. Usaremos a imagem MariaDB 10.2 mantida pela equipe do Docker para executar nosso cluster Galera.
Primeiramente, crie um arquivo de configuração do MySQL para ser usado pelo nosso serviço Swarm:
$ vim ~/my.cnf
[mysqld]
default_storage_engine = InnoDB
binlog_format = ROW
innodb_flush_log_at_trx_commit = 0
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_autoinc_lock_mode = 2
innodb_lock_schedule_algorithm = FCFS # MariaDB >10.1.19 and >10.2.3 only
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_sst_method = mariabackup
Crie uma rede de banco de dados dedicada em nosso Swarm chamada "db_swarm":
$ docker network create --driver overlay db_swarm
Importe nosso arquivo de configuração do MySQL para a configuração do Docker para que possamos carregá-lo em nosso serviço Swarm quando o criarmos mais tarde:
$ cat ~/my.cnf | docker config create my-cnf -
Crie o primeiro serviço de bootstrap Galera, com "gcomm://" como o endereço do cluster chamado "galera0". Este é um serviço transitório apenas para o processo de bootstrap. Excluiremos este serviço assim que tivermos 3 outros serviços Galera em execução:
$ docker service create \
--name galera0 \
--replicas 1 \
--hostname galera0 \
--network db_swarm \
--publish 3306 \
--publish 4444 \
--publish 4567 \
--publish 4568 \
--config src=my-cnf,target=/etc/mysql/mariadb.conf.d/my.cnf \
--env MYSQL_ROOT_PASSWORD=mypassword \
--mount type=volume,src=galera0-datadir,dst=/var/lib/mysql \
mariadb:10.2 \
--wsrep_cluster_address=gcomm:// \
--wsrep_sst_auth="root:mypassword" \
--wsrep_node_address=galera0
Neste ponto, nossa arquitetura de banco de dados pode ser ilustrada como abaixo:
Em seguida, repita o seguinte comando por 3 vezes para criar 3 serviços Galera diferentes. Substitua {name} por galera1, galera2 e galera3 respectivamente:
$ docker service create \
--name {name} \
--replicas 1 \
--hostname {name} \
--network db_swarm \
--publish 3306 \
--publish 4444 \
--publish 4567 \
--publish 4568 \
--config src=my-cnf,target=/etc/mysql/mariadb.conf.d/my.cnf \
--env MYSQL_ROOT_PASSWORD=mypassword \
--mount type=volume,src={name}-datadir,dst=/var/lib/mysql \
mariadb:10.2 \
--wsrep_cluster_address=gcomm://galera0,galera1,galera2,galera3 \
--wsrep_sst_auth="root:mypassword" \
--wsrep_node_address={name}
Verifique nossos serviços atuais do Docker:
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
wpcxye3c4e9d galera0 replicated 1/1 mariadb:10.2 *:30022->3306/tcp, *:30023->4444/tcp, *:30024-30025->4567-4568/tcp
jsamvxw9tqpw galera1 replicated 1/1 mariadb:10.2 *:30026->3306/tcp, *:30027->4444/tcp, *:30028-30029->4567-4568/tcp
otbwnb3ridg0 galera2 replicated 1/1 mariadb:10.2 *:30030->3306/tcp, *:30031->4444/tcp, *:30032-30033->4567-4568/tcp
5jp9dpv5twy3 galera3 replicated 1/1 mariadb:10.2 *:30034->3306/tcp, *:30035->4444/tcp, *:30036-30037->4567-4568/tcp
Nossa arquitetura agora está mais ou menos assim:
Precisamos remover o serviço Galera bootstrap Swarm, galera0, para impedi-lo de ser executado, pois se o contêiner estiver sendo reagendado pelo Docker Swarm, uma nova réplica será iniciada com um novo volume. Corremos o risco de perda de dados porque o --wsrep_cluster_address contém "galera0" nos outros nós Galera (ou serviços Swarm). Então, vamos removê-lo:
$ docker service rm galera0
Neste ponto, temos nosso Galera Cluster de três nós:
Agora estamos prontos para implantar nosso exportador MySQL e servidor Prometheus.
Serviço de enxame do exportador MySQL
Faça login em um dos nós Galera e crie o usuário exportador com os devidos privilégios:
$ docker exec -it {galera1} mysql -uroot -p
Enter password:
mysql> CREATE USER 'exporter'@'%' IDENTIFIED BY 'exporterpassword' WITH MAX_USER_CONNECTIONS 3;
mysql> GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';
Em seguida, crie o serviço exportador para cada um dos serviços Galera (substitua {name} por galera1, galera2 e galera3 respectivamente):
$ docker service create \
--name {name}-exporter \
--network db_swarm \
--replicas 1 \
-p 9104 \
-e DATA_SOURCE_NAME="exporter:[email protected]({name}:3306)/" \
prom/mysqld-exporter:latest \
--collect.info_schema.processlist \
--collect.info_schema.innodb_metrics \
--collect.info_schema.tablestats \
--collect.info_schema.tables \
--collect.info_schema.userstats \
--collect.engine_innodb_status
Neste ponto, nossa arquitetura está mais ou menos assim com os serviços do exportador na imagem:
Serviço Prometheus Server Swarm
Finalmente, vamos implantar nosso servidor Prometheus. Semelhante à implantação do Galera, temos que preparar o arquivo de configuração do Prometheus primeiro antes de importá-lo para o Swarm usando o comando Docker config:
$ vim ~/prometheus.yml
global:
scrape_interval: 5s
scrape_timeout: 3s
evaluation_interval: 5s
# Our alerting rule files
rule_files:
- "alert.rules"
# Scrape endpoints
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'galera'
static_configs:
- targets: ['galera1-exporter:9104','galera2-exporter:9104', 'galera3-exporter:9104']
A partir do arquivo de configuração do Prometheus, definimos três jobs - "prometheus" e "galera". O primeiro é o trabalho de monitorar o próprio servidor Prometheus. O próximo é o trabalho de monitorar nossos contêineres MySQL chamados "galera". Definimos os endpoints em nossos exportadores MySQL na porta 9104, que expõem as métricas compatíveis com Prometheus dos três nós Galera, respectivamente. O "alert.rules" é o arquivo de regras que incluiremos posteriormente na próxima postagem do blog para fins de alerta.
Importe o arquivo de configuração para a configuração do Docker para ser usado com o contêiner Prometheus posteriormente:
$ cat ~/prometheus.yml | docker config create prometheus-yml -
Vamos executar o contêiner do servidor Prometheus e publicar a porta 9090 de todos os hosts Docker para o serviço de IU da Web do Prometheus:
$ docker service create \
--name prometheus-server \
--publish 9090:9090 \
--network db_swarm \
--replicas 1 \
--config src=prometheus-yml,target=/etc/prometheus/prometheus.yml \
--mount type=volume,src=prometheus-data,dst=/prometheus \
prom/prometheus
Verifique com o comando de serviço do Docker que temos 3 serviços Galera, 3 serviços exportadores e 1 serviço Prometheus:
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
jsamvxw9tqpw galera1 replicated 1/1 mariadb:10.2 *:30026->3306/tcp, *:30027->4444/tcp, *:30028-30029->4567-4568/tcp
hbh1dtljn535 galera1-exporter replicated 1/1 prom/mysqld-exporter:latest *:30038->9104/tcp
otbwnb3ridg0 galera2 replicated 1/1 mariadb:10.2 *:30030->3306/tcp, *:30031->4444/tcp, *:30032-30033->4567-4568/tcp
jq8i77ch5oi3 galera2-exporter replicated 1/1 prom/mysqld-exporter:latest *:30039->9104/tcp
5jp9dpv5twy3 galera3 replicated 1/1 mariadb:10.2 *:30034->3306/tcp, *:30035->4444/tcp, *:30036-30037->4567-4568/tcp
10gdkm1ypkav galera3-exporter replicated 1/1 prom/mysqld-exporter:latest *:30040->9104/tcp
gv9llxrig30e prometheus-server replicated 1/1 prom/prometheus:latest *:9090->9090/tcp
Agora nosso servidor Prometheus já está em execução e pode ser acessado diretamente na porta 9090 de qualquer nó do Docker. Abra um navegador da Web e acesse http://192.168.55.161:9090/ para acessar a interface do usuário da Web do Prometheus. Verifique o status do alvo em Status -> Targets e certifique-se de que estejam todos verdes:
Neste ponto, nossa arquitetura Swarm está parecida com isto:
Continuação..
Agora temos nosso banco de dados e pilha de monitoramento implantados no Docker. Na parte 2 do blog, veremos as diferentes métricas do MySQL para ficar de olho. Também veremos como configurar alertas com o Prometheus.