Die Überwachung ist für Container ein Problem, da die Infrastruktur dynamisch ist. Container können routinemäßig erstellt und zerstört werden und sind kurzlebig. Wie behalten Sie also den Überblick über Ihre MySQL-Instanzen, die auf Docker ausgeführt werden?
Wie bei jeder Softwarekomponente gibt es viele Optionen, die verwendet werden können. Wir betrachten Prometheus als eine Lösung, die für eine verteilte Infrastruktur entwickelt wurde und sehr gut mit Docker funktioniert.
Dies ist ein zweiteiliger Blog. In diesem Teil 1-Blog behandeln wir den Bereitstellungsaspekt unserer MySQL-Container mit Prometheus und seinen Komponenten, die als eigenständige Docker-Container und Docker-Swarm-Dienste ausgeführt werden. In Teil 2 werden wir uns die wichtigen Metriken ansehen, die von unseren MySQL-Containern überwacht werden müssen, sowie die Integration mit den Paging- und Benachrichtigungssystemen.
Einführung in Prometheus
Prometheus ist ein vollständiges Überwachungs- und Trendsystem, das integriertes und aktives Scraping, Speichern, Abfragen, Diagramme und Warnmeldungen auf der Grundlage von Zeitreihendaten umfasst. Prometheus sammelt Metriken über einen Pull-Mechanismus von konfigurierten Zielen in bestimmten Intervallen, wertet Regelausdrücke aus, zeigt die Ergebnisse an und kann Warnungen auslösen, wenn festgestellt wird, dass eine Bedingung wahr ist. Es unterstützt alle Zielmetriken, die wir messen wollen, wenn man MySQL als Docker-Container betreiben möchte. Diese Metriken beinhalten Metriken zu physischen Hosts, Docker-Container-Metriken und MySQL-Server-Metriken.
Sehen Sie sich das folgende Diagramm an, das die Prometheus-Architektur veranschaulicht (aus der offiziellen Prometheus-Dokumentation):
Wir werden einige MySQL-Container (Standalone und Docker Swarm) komplett mit einem Prometheus-Server, einem MySQL-Exporter (d. h. einem Prometheus-Agenten zum Offenlegen von MySQL-Metriken, die dann vom Prometheus-Server gescraped werden können) und auch einem Alertmanager zum Handhaben von Warnungen bereitstellen auf den gesammelten Metriken.
Weitere Einzelheiten finden Sie in der Prometheus-Dokumentation. In diesem Beispiel verwenden wir die offiziellen Docker-Images, die vom Prometheus-Team bereitgestellt werden.
Eigenständiger Docker
Bereitstellen von MySQL-Containern
Lassen Sie uns zwei eigenständige MySQL-Server auf Docker ausführen, um unsere exemplarische Vorgehensweise für die Bereitstellung zu vereinfachen. Ein Container wird das neueste MySQL 8.0 verwenden und der andere ist MySQL 5.7. Beide Container befinden sich im selben Docker-Netzwerk namens „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 verwendet standardmäßig ein neues Authentifizierungs-Plugin namens caching_sha2_password . Um die Kompatibilität mit dem Prometheus-MySQL-Exporter-Container zu gewährleisten, verwenden wir das weit verbreitete mysql_native_password plugin, wenn wir einen neuen MySQL-Benutzer auf diesem Server erstellen.
Für den zweiten MySQL-Container mit 5.7 führen wir Folgendes aus:
$ 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
Überprüfen Sie, ob unsere MySQL-Server in Ordnung sind:
[[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
An diesem Punkt sieht unsere Architektur in etwa so aus:
Fangen wir an, sie zu überwachen.
Docker-Metriken für Prometheus verfügbar machen
Docker verfügt über eine integrierte Unterstützung als Prometheus-Ziel, mit dem wir die Docker-Engine-Statistiken überwachen können. Wir können es einfach aktivieren, indem wir eine Textdatei namens „daemon.json“ im Docker-Host erstellen:
$ vim /etc/docker/daemon.json
Und fügen Sie die folgenden Zeilen hinzu:
{
"metrics-addr" : "12.168.55.161:9323",
"experimental" : true
}
Dabei ist 192.168.55.161 die primäre IP-Adresse des Docker-Hosts. Starten Sie dann den Docker-Daemon neu, um die Änderung zu laden:
$ systemctl restart docker
Da wir --restart=unless-stopped im run-Befehl unserer MySQL-Container definiert haben, werden die Container automatisch gestartet, nachdem Docker ausgeführt wird.
Bereitstellen von MySQL Exporter
Bevor wir fortfahren, erfordert der mysqld-Exporter, dass ein MySQL-Benutzer für Überwachungszwecke verwendet wird. Erstellen Sie in unseren MySQL-Containern den Überwachungsbenutzer:
$ 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'@'%';
Beachten Sie, dass es empfohlen wird, ein maximales Verbindungslimit für den Benutzer festzulegen, um eine Überlastung des Servers mit Überwachungsabfällen unter hoher Last zu vermeiden. Wiederholen Sie die obigen Anweisungen für den zweiten Container, 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'@'%';
Lassen Sie uns den mysqld-Exporter-Container namens „mysql8-exporter“ ausführen, um die Metriken für unsere MySQL 8.0-Instanz wie folgt bereitzustellen:
$ 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
Und auch ein weiterer Exporter-Container für unsere MySQL 5.7-Instanz:
$ 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
Wir haben eine Reihe von Collector-Flags für den Container aktiviert, um die MySQL-Metriken verfügbar zu machen. Sie können auch --collect.slave_status, --collect.slave_hosts aktivieren, wenn Sie eine MySQL-Replikation auf Containern ausführen.
Wir sollten in der Lage sein, die MySQL-Metriken über curl direkt vom Docker-Host abzurufen (Port 32771 ist der veröffentlichte Port, der automatisch von Docker für den Container mysql80-exporter zugewiesen wird):
$ 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
An diesem Punkt sieht unsere Architektur in etwa so aus:
Jetzt können wir den Prometheus-Server einrichten.
Prometheus-Server bereitstellen
Erstellen Sie zunächst die Prometheus-Konfigurationsdatei unter ~/prometheus.yml und fügen Sie die folgenden Zeilen hinzu:
$ 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']
Aus der Prometheus-Konfigurationsdatei haben wir drei Jobs definiert – „prometheus“, „mysql“ und „docker“. Der erste ist die Aufgabe, den Prometheus-Server selbst zu überwachen. Der nächste ist die Aufgabe, unsere MySQL-Container namens "mysql" zu überwachen. Wir definieren die Endpunkte auf unseren MySQL-Exportern auf Port 9104, der die Prometheus-kompatiblen Metriken von den MySQL 8.0- bzw. 5.7-Instanzen offengelegt hat. Die "alert.rules" ist die Regeldatei, die wir später in den nächsten Blogbeitrag für Warnzwecke aufnehmen werden.
Wir können dann die Konfiguration mit dem Prometheus-Container abbilden. Außerdem müssen wir aus Gründen der Persistenz ein Docker-Volume für Prometheus-Daten erstellen und Port 9090 öffentlich verfügbar machen:
$ 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
Nun läuft unser Prometheus-Server bereits und ist direkt auf Port 9090 des Docker-Hosts erreichbar. Öffnen Sie einen Webbrowser und rufen Sie http://192.168.55.161:9090/ auf, um auf die Prometheus-Webbenutzeroberfläche zuzugreifen. Überprüfen Sie den Zielstatus unter Status -> Ziele und vergewissern Sie sich, dass alle grün sind:
An diesem Punkt sieht unsere Containerarchitektur etwa so aus:
Unser Prometheus-Überwachungssystem für unsere eigenständigen MySQL-Container wird jetzt bereitgestellt.
Dockerschwarm
Bereitstellung eines 3-Knoten-Galera-Clusters
Angenommen, wir möchten einen Galera-Cluster mit drei Knoten in Docker Swarm bereitstellen, müssten wir drei verschiedene Dienste erstellen, wobei jeder Dienst einen Galera-Knoten darstellt. Mit diesem Ansatz können wir einen statischen, auflösbaren Hostnamen für unseren Galera-Container zusammen mit MySQL-Exporter-Containern, die jeden von ihnen begleiten, beibehalten. Wir werden das MariaDB 10.2-Image verwenden, das vom Docker-Team verwaltet wird, um unseren Galera-Cluster auszuführen.
Erstellen Sie zunächst eine MySQL-Konfigurationsdatei, die von unserem Swarm-Dienst verwendet werden soll:
$ 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
Erstellen Sie in unserem Swarm ein dediziertes Datenbanknetzwerk mit dem Namen "db_swarm":
$ docker network create --driver overlay db_swarm
Importieren Sie unsere MySQL-Konfigurationsdatei in die Docker-Konfiguration, damit wir sie später bei der Erstellung in unseren Swarm-Dienst laden können:
$ cat ~/my.cnf | docker config create my-cnf -
Erstellen Sie den ersten Galera-Bootstrap-Dienst mit „gcomm://“ als Clusteradresse mit dem Namen „galera0“. Dies ist ein vorübergehender Dienst nur für den Bootstrapping-Prozess. Wir werden diesen Dienst löschen, sobald wir 3 andere Galera-Dienste zum Laufen gebracht haben:
$ 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
An dieser Stelle kann unsere Datenbankarchitektur wie folgt dargestellt werden:
Wiederholen Sie dann den folgenden Befehl dreimal, um drei verschiedene Galera-Dienste zu erstellen. Ersetzen Sie {Name} durch galera1, galera2 bzw. 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}
Überprüfen Sie unsere aktuellen Docker-Dienste:
$ 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
Unsere Architektur sieht jetzt etwa so aus:
Wir müssen den Galera-Bootstrap-Swarm-Dienst galera0 entfernen, damit er nicht mehr ausgeführt wird, denn wenn der Container von Docker Swarm neu geplant wird, wird eine neue Replik mit einem neuen neuen Volume gestartet. Wir gehen das Risiko eines Datenverlusts ein, weil die --wsrep_cluster_address enthält "galera0" in den anderen Galera-Knoten (oder Swarm-Diensten). Entfernen wir es also:
$ docker service rm galera0
An diesem Punkt haben wir unseren Galera-Cluster mit drei Knoten:
Wir sind jetzt bereit, unseren MySQL-Exporter und Prometheus-Server einzusetzen.
MySQL Exporter Swarm Service
Melden Sie sich bei einem der Galera-Knoten an und erstellen Sie den Exporter-Benutzer mit den entsprechenden Rechten:
$ 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'@'%';
Erstellen Sie dann den Exporterdienst für jeden der Galera-Dienste (ersetzen Sie {Name} jeweils durch galera1, galera2 und 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
An diesem Punkt sieht unsere Architektur in etwa so aus, mit Exporteurdiensten im Bild:
Prometheus Server Swarm Service
Lassen Sie uns schließlich unseren Prometheus-Server bereitstellen. Ähnlich wie bei der Galera-Bereitstellung müssen wir zuerst die Prometheus-Konfigurationsdatei vorbereiten, bevor wir sie mit dem Docker-Konfigurationsbefehl in Swarm importieren:
$ 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']
Aus der Prometheus-Konfigurationsdatei haben wir drei Jobs definiert – „prometheus“ und „galera“. Der erste ist die Aufgabe, den Prometheus-Server selbst zu überwachen. Der nächste ist die Aufgabe, unsere MySQL-Container namens "galera" zu überwachen. Wir definieren die Endpunkte auf unseren MySQL-Exportern auf Port 9104, die die Prometheus-kompatiblen Metriken von den drei Galera-Knoten bereitstellen. Die "alert.rules" ist die Regeldatei, die wir später in den nächsten Blogbeitrag für Warnzwecke aufnehmen werden.
Importieren Sie die Konfigurationsdatei in die Docker-Konfiguration, um sie später mit dem Prometheus-Container zu verwenden:
$ cat ~/prometheus.yml | docker config create prometheus-yml -
Lassen Sie uns den Prometheus-Servercontainer ausführen und Port 9090 aller Docker-Hosts für den Prometheus-Web-UI-Dienst veröffentlichen:
$ 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
Überprüfen Sie mit dem Docker-Dienstbefehl, dass wir 3 Galera-Dienste, 3 Exporter-Dienste und 1 Prometheus-Dienst haben:
$ 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
Jetzt läuft unser Prometheus-Server bereits und kann von jedem Docker-Knoten direkt auf Port 9090 erreicht werden. Öffnen Sie einen Webbrowser und rufen Sie http://192.168.55.161:9090/ auf, um auf die Prometheus-Webbenutzeroberfläche zuzugreifen. Überprüfen Sie den Zielstatus unter Status -> Ziele und vergewissern Sie sich, dass alle grün sind:
An diesem Punkt sieht unsere Swarm-Architektur in etwa so aus:
Fortsetzung folgt...
Wir haben jetzt unsere Datenbank und unseren Monitoring-Stack auf Docker bereitgestellt. In Teil 2 des Blogs werden wir uns die verschiedenen MySQL-Metriken ansehen, die Sie im Auge behalten sollten. Wir werden auch sehen, wie Sie die Benachrichtigung mit Prometheus konfigurieren.