Galera Cluster構築とmysqld_exporterによる監視

#本記事について
今回はMariaDBのGalera clusterを構築しそれをPrometheusで監視するようにする。
1サーバ内に集約してもいいが、少し本番を想定してDB3台、監視サーバ1台を構築する。
![galera1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362091/0f6dd34c-eb9a-2a48-3260-30b876cbfac0.png)

上記のような形で監視結果はGrafanaで見れるようにする。
記載が漏れたがDB、監視ともにDockerを利用して構築する。

#環境
環境としては以下
OS
・Ubuntu20.04
ミドル
・docker:20.10.8
・docker-compose:1.29.0
・mysqld_exporter:0.13.0
コンテナ
・MariaDB:10.6.2-focal
・prom/prometheus
・grafana/grafana

#DB設定
##Galera Cluster構築
それではまずMariaDB3台構築し、GaleraClusterの設定を行う。

###DB1

```linux:DB1
root@db00:~# mkdir db01
root@db00:~# cd db01
root@db00:~/db01# mkdir log
root@db00:~/db01# mkdir mysql
root@db00:~/db01# ls
log  mysql
root@db00:~/db01# vi docker-compose.yml
```

DB1のdocker-compose.ymlは下記。
他のDBも同じdocker-compose.ymlを利用するが唯一DB1のみcommandを付けている。起動するときは一番最初にDB1を起動してClusterを生成してから他のサーバを起動しClusterに参加させる。

```yml:docker-compose.yml
version: '3.7'
services:
  db:
    image: mariadb:10.6.2-focal
    volumes:
      - "./db.cnf:/etc/mysql/conf.d/db.cnf"
      - "db-data:/var/lib/mysql"
      - "db-log:/var/log/mysql"
    environment:
      - TZ=Asia/Tokyo
      - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes
    network_mode: host
    #commandはDB1のみ
    command: ["--wsrep-new-cluster"]
volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      device: ${PWD}/mysql
      o: bind
  db-log:
    driver: local
    driver_opts:
      type: none
      device: ${PWD}/log
      o: bind
```

次に同じディレクトリにdb.cnfを記載する。中身は下記。

```conf:db.cnf
[galera]
wsrep_on                 = ON
wsrep_provider           = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name       = "MariaDB Galera Cluster"
#各サーバのIPアドレスを記載
wsrep_cluster_address    = gcomm://192.168.153.5,192.168.153.6,192.168.153.7
#自サーバのIPアドレスを記載
wsrep_node_address       = 192.168.153.5
#今回はsst_methodはmariabackupを利用する
wsrep_sst_method         = "mariabackup"
wsrep_sst_auth           = 'mariabackup:mypassword'
wsrep_slave_threads      = 4
#node_nameはhost名と同じにする
wsrep_node_name          ="db01"
wsrep_sst_donor          ="db01,db02,db03"
[mysqld]
default_storage_engine     = InnoDB
binlog_format              = ROW
log_bin                    = /var/log/mysql/mysql-bin
innodb_autoinc_lock_mode   = 2
innodb_locks_unsafe_for_binlog = 1
```

ここまででこのようになっている。

```linux:DB1
root@db00:~/db01# ls
db.cnf  docker-compose.yml  log  mysql
```

##DB2
同じように設定していく。
docker-compose.ymlにcommandがないこと、db.cnfの「wsrep_node_address」、「wsrep_node_name」がサーバ固有のものになっていることに注意

```linux:DB2
root@db01:~# mkdir db02
root@db01:~# cd db02
root@db01:~/db02# mkdir log
root@db01:~/db02# mkdir mysql
root@db01:~/db02# vi docker-compose.yml
root@db01:~/db02# vi db.cnf
```

```yml:docker-compose.yml
version: '3.7'
services:
  db:
    image: mariadb:10.6.2-focal
    volumes:
      - "./db.cnf:/etc/mysql/conf.d/db.cnf"
      - "db-data:/var/lib/mysql"
      - "db-log:/var/log/mysql"
    environment:
      - TZ=Asia/Tokyo
      - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes
    network_mode: host
volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      device: ${PWD}/mysql
      o: bind
  db-log:
    driver: local
    driver_opts:
      type: none
      device: ${PWD}/log
      o: bind
```

```conf:db.cnf
[galera]
wsrep_on                 = ON
wsrep_provider           = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name       = "MariaDB Galera Cluster"
#各サーバのIPアドレスを記載
wsrep_cluster_address    = gcomm://192.168.153.5,192.168.153.6,192.168.153.7
#自サーバのIPアドレスを記載
wsrep_node_address       = 192.168.153.6
#今回はsst_methodはmariabackupを利用する
wsrep_sst_method         = "mariabackup"
wsrep_sst_auth           = 'mariabackup:mypassword'
wsrep_slave_threads      = 4
#node_nameはhost名と同じにする
wsrep_node_name          ="db02"
wsrep_sst_donor          ="db01,db02,db03"
[mysqld]
default_storage_engine     = InnoDB
binlog_format              = ROW
log_bin                    = /var/log/mysql/mysql-bin
innodb_autoinc_lock_mode   = 2
innodb_locks_unsafe_for_binlog = 1
```

##DB3

```linux:DB3
root@db01:~# mkdir db03
root@db01:~# cd db03
root@db01:~/db02# mkdir log
root@db01:~/db02# mkdir mysql
root@db01:~/db02# vi docker-compose.yml
root@db01:~/db02# vi db.cnf
```

```yml:docker-compose.yml
version: '3.7'
services:
  db:
    image: mariadb:10.6.2-focal
    volumes:
      - "./db.cnf:/etc/mysql/conf.d/db.cnf"
      - "db-data:/var/lib/mysql"
      - "db-log:/var/log/mysql"
    environment:
      - TZ=Asia/Tokyo
      - MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=yes
    network_mode: host
volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      device: ${PWD}/mysql
      o: bind
  db-log:
    driver: local
    driver_opts:
      type: none
      device: ${PWD}/log
      o: bind
```

```conf:db.cnf
[galera]
wsrep_on                 = ON
wsrep_provider           = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name       = "MariaDB Galera Cluster"
#各サーバのIPアドレスを記載
wsrep_cluster_address    = gcomm://192.168.153.5,192.168.153.6,192.168.153.7
#自サーバのIPアドレスを記載
wsrep_node_address       = 192.168.153.7
#今回はsst_methodはmariabackupを利用する
wsrep_sst_method         = "mariabackup"
wsrep_sst_auth           = 'mariabackup:mypassword'
wsrep_slave_threads      = 4
#node_nameはhost名と同じにする
wsrep_node_name          ="db03"
wsrep_sst_donor          ="db01,db02,db03"
[mysqld]
default_storage_engine     = InnoDB
binlog_format              = ROW
log_bin                    = /var/log/mysql/mysql-bin
innodb_autoinc_lock_mode   = 2
innodb_locks_unsafe_for_binlog = 1
```

##クラスター起動
DB1を起動する

```linux:DB1
root@db00:~/db01# docker-compose up -d
Creating volume "db01_db-data" with local driver
Creating volume "db01_db-log" with local driver
Creating db01_db_1 ... done
root@db00:~/db01# docker-compose ps
  Name                 Command               State   Ports
----------------------------------------------------------
db01_db_1   docker-entrypoint.sh --wsr ...   Up
```

クラスターが起動しているか確認しましょう。

```linux:DB1
root@db00:~/db01# docker-compose exec db mysql -u root -e "show status like 'wsrep_cluster_%'"
+----------------------------+--------------------------------------+
| Variable_name              | Value                                |
+----------------------------+--------------------------------------+
| wsrep_cluster_weight       | 1                                    |
| wsrep_cluster_capabilities |                                      |
| wsrep_cluster_conf_id      | 1                                    |
| wsrep_cluster_size         | 1                                    |
| wsrep_cluster_state_uuid   | ffc5854e-21a5-11ec-ac7b-9b4df50357e9 |
| wsrep_cluster_status       | Primary                              |
+----------------------------+--------------------------------------+
```

次に他のDBを起動する前にmariabackup用のユーザを作成する。
事前にユーザ作成を行わないとDBが起動してSSTをするときに失敗する。

```linux:DB1
root@db00:~/db01# docker-compose exec db mysql -u root
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.6.2-MariaDB-1:10.6.2+maria~focal-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> CREATE USER 'mariabackup'@'localhost' IDENTIFIED BY 'mypassword';
Query OK, 0 rows affected (0.004 sec)

MariaDB [(none)]> GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'mariabackup'@'localhost';
Query OK, 0 rows affected (0.005 sec)
```

これで準備は整ったので他のDBコンテナも起動。

```linux:DB2
root@db01:~/db02# docker-compose up -d
Creating volume "db02_db-data" with local driver
Creating volume "db02_db-log" with local driver
Creating db02_db_1 ... done
root@db01:~/db02# docker-compose ps
  Name                Command             State   Ports
-------------------------------------------------------
db02_db_1   docker-entrypoint.sh mysqld   Up
root@db01:~/db02# docker-compose exec db mysql -u root -e "show status like 'wsrep_cluster_%'"
+----------------------------+--------------------------------------+
| Variable_name              | Value                                |
+----------------------------+--------------------------------------+
| wsrep_cluster_weight       | 2                                    |
| wsrep_cluster_capabilities |                                      |
| wsrep_cluster_conf_id      | 2                                    |
| wsrep_cluster_size         | 2                                    |
| wsrep_cluster_state_uuid   | 276f65ef-21a6-11ec-ab3a-b716b6fe3644 |
| wsrep_cluster_status       | Primary                              |
+----------------------------+--------------------------------------+
```

```linux:DB3
root@db02:~/db03# docker-compose up -d
Creating volume "db03_db-data" with local driver
Creating volume "db03_db-log" with local driver
Creating db03_db_1 ... done
root@db02:~/db03# docker-compose ps
  Name                Command             State   Ports
-------------------------------------------------------
db03_db_1   docker-entrypoint.sh mysqld   Up
root@db02:~/db03# docker-compose exec db mysql -u root -e "show status like 'wsrep_cluster_%'"
+----------------------------+--------------------------------------+
| Variable_name              | Value                                |
+----------------------------+--------------------------------------+
| wsrep_cluster_weight       | 3                                    |
| wsrep_cluster_capabilities |                                      |
| wsrep_cluster_conf_id      | 3                                    |
| wsrep_cluster_size         | 3                                    |
| wsrep_cluster_state_uuid   | 276f65ef-21a6-11ec-ab3a-b716b6fe3644 |
| wsrep_cluster_status       | Primary                              |
+----------------------------+--------------------------------------+
```

これで3台構成のGalera Clusterを組むことができた。

##mysqld_exporterのサービス登録
まずmysqld_exporterをダウンロードする。

```linux:DB
root@db00:~# cd /var/tmp/
##ダウンロード
root@db00:/var/tmp# curl -LO https://github.com/prometheus/mysqld_exporter/releases/download/v0.13.0/mysqld_exporter-0.13.0.linux-amd64.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   647  100   647    0     0   2028      0 --:--:-- --:--:-- --:--:--  2028
100 7072k  100 7072k    0     0  3388k      0  0:00:02  0:00:02 --:--:-- 4025k
root@db00:/var/tmp# ls
mysqld_exporter-0.13.0.linux-amd64.tar.gz
##解凍
root@db00:/var/tmp# tar -zxvf mysqld_exporter-0.13.0.linux-amd64.tar.gz
mysqld_exporter-0.13.0.linux-amd64/
mysqld_exporter-0.13.0.linux-amd64/LICENSE
mysqld_exporter-0.13.0.linux-amd64/NOTICE
mysqld_exporter-0.13.0.linux-amd64/mysqld_exporter
##実行ファイルを適当な場所に配置する
root@db00:/var/tmp# mkdir /var/lib/mysqld_exporter
root@db00:/var/tmp# cp mysqld_exporter-0.13.0.linux-amd64/mysqld_exporter /var/lib/mysqld_exporter/
root@db00:/var/tmp# ls /var/lib/mysqld_exporter
mysqld_exporter
```

次にサービスファイルを作成する。

```linux:DB
root@db00:/var/tmp# vi /etc/systemd/system/mysqld_exporter.service

[Unit]
Description=Mysql Exporter
After=network-online.target
[Service]
EnvironmentFile=-/etc/default/mysqld_exporter
WorkingDirectory=/var/lib/mysqld_exporter
ExecStart=/var/lib/mysqld_exporter/mysqld_exporter $OPTIONS
Restart=always
RestartSec=1
Type=simple
[Install]
WantedBy = multi-user.target

root@db00:/var/tmp# vi /etc/default/mysqld_exporter

DATA_SOURCE_NAME= "exporter:test@(localhost:3306)/"
OPTIONS="--collect.engine_innodb_status --collect.global_status"
```

ここまでは全DBサーバ共通の作業となる。
次にサービス起動する前にmysqld_exporterのユーザを作成する。
クラスターを組んでいるのでどこかで作れば全台に共有される。

```linux:DB1
root@db00:~/db01# ls
db.cnf  docker-compose.yml  log  mysql
root@db00:~/db01# docker-compose exec db mysql -u root -e "CREATE USER 'exporter'@'127.0.0.1' IDENTIFIED BY 'test' WITH MAX_USER_CONNECTIONS 3;"
root@db00:~/db01# docker-compose exec db mysql -u root -e "GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'127.0.0.1';"
```

これで事前準備が整ったのでサービス起動する。

```linux:DB1
root@db00:~/db01# systemctl daemon-reload
root@db00:~/db01# systemctl start mysqld_exporter
root@db00:~/db01# systemctl status mysqld_exporter
● mysqld_exporter.service - Mysql Exporter
     Loaded: loaded (/etc/systemd/system/mysqld_exporter.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2021-09-30 21:15:29 JST; 9s ago
   Main PID: 40329 (mysqld_exporter)
      Tasks: 4 (limit: 1072)
     Memory: 1.7M
     CGroup: /system.slice/mysqld_exporter.service
             mq40329 /var/lib/mysqld_exporter/mysqld_exporter --collect.engine_innodb_status --collect.global_status
```

他のDBでも同様にサービス起動させる。

#監視
##Prometheus構築
[PrometheusをDockerを使って触ってみる](https://qiita.com/ryuichi1208/items/caf2d32b7a49ce5a39b1)
こちらを参考にしていく。

監視サーバにてdocker-compose.ymlと設定ファイルを作る

```linux:prometheus
root@prometheus:~# mkdir prometheus
root@prometheus:~# cd prometheus/
root@prometheus:~/prometheus# vi docker-compose.yml
root@prometheus:~/prometheus# vi prometheus.yml
```

```yml:docker-compose.yml
version: '3.7'
services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - '9090:9090'
  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
```

```yml:prometheus.yml
global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: 'codelab-monitor'

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s

    static_configs:
      - targets: ['localhost:9090']

  - job_name: "db1"
    scrape_interval: "40s"
    scrape_timeout: "30s"
    static_configs:
      - targets: ['192.168.153.5:9104']

  - job_name: "db2"
    scrape_interval: "40s"
    scrape_timeout: "30s"
    static_configs:
      - targets: ['192.168.153.6:9104']

  - job_name: "db3"
    scrape_interval: "40s"
    scrape_timeout: "30s"
    static_configs:
      - targets: ['192.168.153.7:9104']
```

prometheus.ymlに関しては[公式](https://prometheus.io/docs/prometheus/latest/getting_started/)にあるものに下記を追加している

```yml:prometheus.yml
  - job_name: "db1"
    scrape_interval: "40s"
    scrape_timeout: "30s"
    static_configs:
      - targets: ['192.168.153.5:9104']

  - job_name: "db2"
    scrape_interval: "40s"
    scrape_timeout: "30s"
    static_configs:
      - targets: ['192.168.153.6:9104']

  - job_name: "db3"
    scrape_interval: "40s"
    scrape_timeout: "30s"
    static_configs:
      - targets: ['192.168.153.7:9104']
```

起動させる。

```linux:prometheus
root@prometheus:~/prometheus# docker-compose up -d
oot@prometheus:~/prometheus# docker-compose ps
         Name                        Command               State                    Ports
-----------------------------------------------------------------------------------------------------------
prometheus_grafana_1      /run.sh                          Up      0.0.0.0:3000->3000/tcp,:::3000->3000/tcp
prometheus_prometheus_1   /bin/prometheus --config.f ...   Up      0.0.0.0:9090->9090/tcp,:::9090->9090/tcp
```

<監視サーバIP>:9090にアクセスし、画面が表示されることを確認する。
![pro1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362091/8459d41a-9e35-5b26-be04-59240b079176.png)

Status->Targetsを選び、DBへの疎通が問題ないことを確認する。
![pro2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362091/0aa37ba0-a8a5-73bf-be44-34073114e511.png)

##Grafana設定
それでは最後にGrafanaの設定をして終わろうと思う。
<監視サーバIP>:3000にアクセス、初期ユーザ：パスワードはadmin:admin
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362091/44aaefbd-e8ce-ce48-3b70-4dda1d81892b.png)

Configration -> Data sourcesからPrometheusを追加する。
URLを設定してHTTPMethodをGETに変更すれば問題ない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362091/c5df4a86-ae87-4ddf-24d3-576920949f96.png)

あとはDashboardで見たい監視設定をすればよい。