Monitorowanie jest problemem dla kontenerów, ponieważ infrastruktura jest dynamiczna. Kontenery mogą być rutynowo tworzone i niszczone i są efemeryczne. Jak więc śledzić swoje instancje MySQL działające w Dockerze?
Podobnie jak w przypadku każdego komponentu oprogramowania, istnieje wiele opcji, których można użyć. Przyjrzymy się Prometheusowi jako rozwiązaniu zbudowanemu dla infrastruktury rozproszonej, które działa bardzo dobrze z Dockerem.
To jest dwuczęściowy blog. W tej części 1 bloga zamierzamy omówić aspekt wdrażania naszych kontenerów MySQL z Prometheusem i jego komponentami, działającymi jako samodzielne kontenery Docker i usługi Docker Swarm. W części 2 przyjrzymy się ważnym metrykom do monitorowania z naszych kontenerów MySQL, a także integracji z systemami stronicowania i powiadomień.
Wprowadzenie do Prometeusza
Prometheus to pełny system monitorowania i trendów, który obejmuje wbudowane i aktywne skrobanie, przechowywanie, zapytania, wykresy i alerty na podstawie danych szeregów czasowych. Prometheus zbiera metryki za pomocą mechanizmu ściągania ze skonfigurowanych celów w określonych odstępach czasu, ocenia wyrażenia reguł, wyświetla wyniki i może wyzwalać alerty, jeśli jakiś warunek jest spełniony. Obsługuje wszystkie docelowe metryki, które chcemy mierzyć, jeśli chcemy uruchomić MySQL jako kontenery Dockera. Te metryki obejmują metryki hostów fizycznych, metryki kontenerów Docker i metryki serwera MySQL.
Spójrz na poniższy diagram ilustrujący architekturę Prometheusa (zaczerpnięty z oficjalnej dokumentacji Prometheusa):
Zamierzamy wdrożyć niektóre kontenery MySQL (samodzielne i Docker Swarm) wraz z serwerem Prometheus, eksporterem MySQL (tj. agentem Prometheus w celu ujawnienia metryk MySQL, które mogą być następnie zeskrobane przez serwer Prometheus), a także Alertmanager do obsługi alertów opartych na na zebranych danych.
Więcej szczegółów znajdziesz w dokumentacji Prometheusa. W tym przykładzie użyjemy oficjalnych obrazów platformy Docker dostarczonych przez zespół Prometheus.
Samodzielny dok
Wdrażanie kontenerów MySQL
Uruchommy dwa niezależne serwery MySQL w platformie Docker, aby uprościć nasz przewodnik po wdrażaniu. Jeden kontener będzie korzystał z najnowszej wersji MySQL 8.0, a drugi to MySQL 5.7. Oba kontenery znajdują się w tej samej sieci Docker o nazwie „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
MySQL 8 domyślnie używa nowej wtyczki uwierzytelniającej o nazwie caching_sha2_password . Aby zapewnić zgodność z kontenerem eksportera Prometheus MySQL, użyjmy powszechnie używanego mysql_native_password wtyczki za każdym razem, gdy tworzymy nowego użytkownika MySQL na tym serwerze.
W przypadku drugiego kontenera MySQL działającego w wersji 5.7 wykonujemy następujące czynności:
$ 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
Sprawdź, czy nasze serwery MySQL działają poprawnie:
[[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
W tym momencie nasza architektura wygląda mniej więcej tak:
Zacznijmy je monitorować.
Udostępnianie danych Dockera Prometheusowi
Docker ma wbudowaną obsługę jako target Prometheus, gdzie możemy monitorować statystyki silnika Dockera. Możemy go po prostu włączyć, tworząc plik tekstowy o nazwie „daemon.json” na hoście Docker:
$ vim /etc/docker/daemon.json
I dodaj następujące wiersze:
{
"metrics-addr" : "12.168.55.161:9323",
"experimental" : true
}
Gdzie 192.168.55.161 to podstawowy adres IP hosta platformy Docker. Następnie uruchom ponownie demona Docker, aby załadować zmianę:
$ systemctl restart docker
Ponieważ zdefiniowaliśmy --restart=unless-stopped w poleceniu uruchamiania naszych kontenerów MySQL, kontenery zostaną automatycznie uruchomione po uruchomieniu Dockera.
Wdrażanie eksportera MySQL
Zanim przejdziemy dalej, eksporter mysqld wymaga użycia użytkownika MySQL do celów monitorowania. W naszych kontenerach MySQL utwórz użytkownika monitorującego:
$ 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'@'%';
Zwróć uwagę, że zaleca się ustawienie maksymalnego limitu połączeń dla użytkownika, aby uniknąć przeciążenia serwera przez problemy z monitorowaniem przy dużym obciążeniu. Powtórz powyższe instrukcje na drugim kontenerze, 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'@'%';
Uruchommy kontener eksportera mysqld o nazwie „mysql8-exporter”, aby wyświetlić metryki dla naszej instancji MySQL 8.0, jak poniżej:
$ 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
A także kolejny kontener eksportera dla naszej instancji 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
Włączyliśmy kilka flag zbierających dla kontenera, aby ujawnić metryki MySQL. Możesz także włączyć --collect.slave_status, --collect.slave_hosts, jeśli masz uruchomioną replikację MySQL na kontenerach.
Powinniśmy być w stanie pobrać metryki MySQL przez curl bezpośrednio z hosta Docker (port 32771 jest portem opublikowanym automatycznie przypisywanym przez Docker dla kontenera 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
W tym momencie nasza architektura wygląda mniej więcej tak:
Teraz możemy skonfigurować serwer Prometheus.
Wdrażanie serwera Prometheus
Najpierw utwórz plik konfiguracyjny Prometheusa w ~/prometheus.yml i dodaj następujące wiersze:
$ 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']
Z pliku konfiguracyjnego Prometheusa zdefiniowaliśmy trzy zadania - "prometheus", "mysql" i "docker". Pierwszym z nich jest zadanie monitorowania samego serwera Prometheus. Następnym zadaniem jest monitorowanie naszych kontenerów MySQL o nazwie "mysql". Definiujemy punkty końcowe na naszych eksporterach MySQL na porcie 9104, który ujawnia metryki zgodne z Prometheusem z instancji MySQL 8.0 i 5.7 odpowiednio. „alert.rules” to plik reguł, który uwzględnimy później w następnym poście na blogu w celu ostrzegania.
Możemy wtedy zmapować konfigurację z kontenerem Prometheus. Musimy również utworzyć wolumin Docker dla danych Prometheus w celu zapewnienia trwałości, a także publicznie ujawnić port 9090:
$ 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
Teraz nasz serwer Prometheus już działa i jest dostępny bezpośrednio na porcie 9090 hosta Docker. Otwórz przeglądarkę internetową i przejdź do http://192.168.55.161:9090/, aby uzyskać dostęp do interfejsu internetowego Prometheus. Sprawdź status celu w Status -> Cele i upewnij się, że wszystkie są zielone:
W tym momencie nasza architektura kontenerowa wygląda mniej więcej tak:
Nasz system monitorowania Prometheus dla naszych samodzielnych kontenerów MySQL jest już wdrożony.
Rój Dokerów
Wdrażanie 3-węzłowego klastra Galera
Zakładając, że chcemy wdrożyć trzywęzłowy klaster Galera w Docker Swarm, musielibyśmy stworzyć 3 różne usługi, z których każda reprezentuje jeden węzeł Galera. Korzystając z tego podejścia, możemy zachować statyczną, możliwą do rozwiązania nazwę hosta dla naszego kontenera Galera, wraz z kontenerami eksportera MySQL, które będą towarzyszyć każdemu z nich. Do obsługi naszego klastra Galera będziemy używać obrazu MariaDB 10.2 obsługiwanego przez zespół Dockera.
Najpierw utwórz plik konfiguracyjny MySQL, który będzie używany przez naszą usługę 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
Utwórz w naszym roju dedykowaną sieć baz danych o nazwie "db_swarm":
$ docker network create --driver overlay db_swarm
Zaimportuj nasz plik konfiguracyjny MySQL do konfiguracji Docker, abyśmy mogli załadować go do naszej usługi Swarm, gdy utworzymy go później:
$ cat ~/my.cnf | docker config create my-cnf -
Utwórz pierwszą usługę ładowania początkowego Galera z „gcomm://” jako adresem klastra o nazwie „galera0”. Jest to usługa przejściowa tylko dla procesu ładowania początkowego. Usuniemy tę usługę, gdy uruchomimy 3 inne usługi Galera:
$ 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
W tym momencie naszą architekturę bazy danych można zilustrować jak poniżej:
Następnie powtórz następujące polecenie 3 razy, aby utworzyć 3 różne usługi Galera. Zastąp {name} odpowiednio przez galera1, galera2 i galera3:
$ 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}
Sprawdź nasze obecne usługi 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
Nasza architektura wygląda teraz mniej więcej tak:
Musimy usunąć usługę Galera bootstrap Swarm, galera0, aby zatrzymać jej działanie, ponieważ jeśli kontener jest zmieniany przez Docker Swarm, nowa replika zostanie uruchomiona z nowym woluminem. Narażamy się na ryzyko utraty danych, ponieważ --wsrep_cluster_address zawiera "galera0" w innych węzłach Galera (lub usługach Swarm). Więc usuńmy to:
$ docker service rm galera0
W tym momencie mamy nasz trzywęzłowy klaster Galera:
Jesteśmy teraz gotowi do wdrożenia naszego eksportera MySQL i serwera Prometheus.
Usługa roju eksportera MySQL
Zaloguj się do jednego z węzłów Galera i utwórz użytkownika eksportera z odpowiednimi uprawnieniami:
$ 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'@'%';
Następnie utwórz usługę eksportera dla każdej usługi Galera (zamień {name} odpowiednio na galera1, galera2 i galera3):
$ 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
W tym momencie nasza architektura wygląda mniej więcej tak z usługami eksportera na zdjęciu:
Usługa roju serwerów Prometheus
Na koniec wdrożmy nasz serwer Prometheus. Podobnie jak w przypadku wdrożenia Galera, musimy najpierw przygotować plik konfiguracyjny Prometheusa przed zaimportowaniem go do Swarm za pomocą polecenia 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']
Z pliku konfiguracyjnego Prometheusa zdefiniowaliśmy trzy zadania - "prometheus" i "galera". Pierwszym z nich jest zadanie monitorowania samego serwera Prometheus. Kolejnym zadaniem jest monitorowanie naszych kontenerów MySQL o nazwie "galera". Definiujemy punkty końcowe na naszych eksporterach MySQL na porcie 9104, które udostępniają metryki zgodne z Prometheusem odpowiednio z trzech węzłów Galera. „alert.rules” to plik reguł, który uwzględnimy później w następnym poście na blogu w celu ostrzegania.
Zaimportuj plik konfiguracyjny do Docker config, aby później użyć go z kontenerem Prometheus:
$ cat ~/prometheus.yml | docker config create prometheus-yml -
Uruchommy kontener serwera Prometheus i opublikujmy port 9090 wszystkich hostów platformy Docker dla usługi interfejsu internetowego 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
Sprawdź za pomocą polecenia usługi Docker, że mamy 3 usługi Galera, 3 usługi eksportera i 1 usługę 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
Teraz nasz serwer Prometheus już działa i można uzyskać do niego dostęp bezpośrednio na porcie 9090 z dowolnego węzła Docker. Otwórz przeglądarkę internetową i przejdź do http://192.168.55.161:9090/, aby uzyskać dostęp do interfejsu internetowego Prometheus. Sprawdź status celu w Status -> Cele i upewnij się, że wszystkie są zielone:
W tym momencie nasza architektura Swarm wygląda mniej więcej tak:
Ciąg dalszy nastąpi..
Mamy teraz naszą bazę danych i stos monitorowania wdrożony w Dockerze. W drugiej części bloga przyjrzymy się różnym metrykom MySQL, na które warto mieć oko. Zobaczymy również, jak skonfigurować alerty w Prometheusie.