やったことのまとめ
- 同じ設定の
Prometheus
を単純に複数台動かして冗長化した - 複数台の
Alertmanager
をメッシュとして動かして冗長化した
Prometheus
とAlertmanager
でサービスを監視するのは良いんだけど, 1台ずつで運用してると監視コンポーネント自身がダウンしたときに監視できなくなってしまう.
だったら監視コンポーネント自体も冗長化すれば可用性を上げられるのでは?と思い試してみた.
Prometheus
の時系列DBの冗長化はかなり難しいっぽいので今回はやらない.
Prometheus
は単純に同じ設定のものを複数同時に動かし, Alertmanager
は複数台を同期してメッシュとして動かすのが良さそう.
つかうもの
- macOS Mojave 10.14
- Docker Desktop for Mac
- Version 3.1.0
- Docker Engine Version 20.10.2
- docker-compose version 1.27.4
- Prometheus (Docker)
- version 2.24.1
- Alertmanager (Docker)
- version 0.21.0
- Grafana (Docker)
- version 7.3.7
- nginx (Docker)
- version 1.18.0
やったこと
Prometheusを冗長化する
Prometheus
公式のFAQによると可用性を高めるには
「同じ設定のものを複数台動かせ. 複数のPrometheus
で同じアラートが発火した場合でもAlertmanager
側で勝手に重複排除してくれる.(意訳)」1
とのこと. 単純で良い.
とりあえずPrometheus
を3台立ててnginx
で負荷分散(ラウンドロビン)する2ような構成をDocker Compose
で作ってみた.
その他の設定は下記のとおり.
Prometheus
x3prometheus.yml
: 互いを監視するような設定を入れるrules.yml
: 任意の設定
Alertmanager
alertmanager.yml
: 任意の設定
Grafana
grafana.ini
: 任意の設定(リバースプロキシ対応)datasource.yaml
:Prometheus
をData Sourceとする設定
nginx
default.conf
:Prometheus
のロードバランシング設定(やらなくても良い)
Prometheus
, Alertmanager
, Grafana
のリバースプロキシ設定は前回やったときとほぼ同じだけど, 今回の目的はPrometheus
の冗長化なのでここらへんはやらなくても良い.
rules.yml
, alertmanager.yml
の設定は有効なものなら何でも良いので前回と同じものを使う.
grafana.ini
も一応前回と同じものを使うけど今回の目的はあくまでPrometheus
の冗長化なのでデフォルト設定のままでも良い.
設定ファイルが準備できたらコンテナを立ち上げる.
# ディレクトリ構成
$ tree .
.
├── deployment
│ ├── alertmanager
│ │ └── alertmanager.yml
│ ├── grafana
│ │ ├── datasource.yaml
│ │ └── grafana.ini
│ ├── nginx
│ │ └── default.conf
│ └── prometheus
│ ├── prometheus.yml
│ └── rules.yml
└── docker-compose.yml
# コンテナ起動
$ docker-compose up -d --force-recreate
$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------
alertmanager /bin/alertmanager --config ... Up 9093/tcp
grafana /run.sh Up 3000/tcp
nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
prometheus-01 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-02 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-03 /bin/prometheus --config.f ... Up 9090/tcp
nginx
で80番ポートが開けてあるので, http://localhost/prometheus/を開くとPrometheus
が起動していることを確認できる.
画面上ではどのPrometheus
コンテナがレスポンスを返しているのかわからないが, 実際にはnginx
により1台ずつ順番にリクエストを受け付けている(ラウンドロビン). はず.
http://localhost/grafanaを開きGrafana
でダッシュボードを作成する.
Data Sourceとしてnginx
のPrometheus
用エンドポイントと念の為それぞれのPrometheus
3台のエンドポイントを設定してあるのでそれぞれのData Sourceに対して同じメトリクス(up)のダッシュボードを作ってみる.
余談だけど今回はnginx
ロードバランサの下で複数台のPrometheus
を動かしているので, Grafana
のData Sourceがnginx
上のPrometheus
エンドポイントを見ている場合はロードするたびに微妙にグラフ(メトリクス)が変わったりする.
この挙動が気持ち悪い場合はnginx
上のエンドポイントじゃなくて個別のPrometheus
をData Sourceにするほうが良いかもしれない(あとで気づいた).
この状態で3台あるPrometheus
を一部落としてみる.
# Prometheusを2台落とす
$ docker-compose stop prometheus-01 prometheus-02
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------
alertmanager /bin/alertmanager --config ... Up 9093/tcp
grafana /run.sh Up 3000/tcp
nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
prometheus-01 /bin/prometheus --config.f ... Exit 0
prometheus-02 /bin/prometheus --config.f ... Exit 0
prometheus-03 /bin/prometheus --config.f ... Up 9090/tcp
1台目と2台目のPrometheus
を落としたので, 3台目のPrometheus
でInstanceDownのアラートが発火する.
Alertmanagerが反応し, アラートの通知が届く.
(通知はAlertmanagerからGmail経由で送る設定にしている)
冗長構成にしたおかげで複数台用意したPrometheus
が一部落ちてもメトリクスは継続して収集されていることと,
相互監視の設定により一部が落ちた場合にも残りのPrometheus
でアラートが発火して検知できることが確認できた.
今度はAlertmanager
で複数のPrometheus
から送られた同じアラートが重複排除されることを確かめるため, 3台目のPrometheus
だけを落としてみる.
# Prometheusを復旧させる
$ docker-compose start prometheus-01 prometheus-02
# 3台目だけを落とす
$ docker-compose stop prometheus-03
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------
alertmanager /bin/alertmanager --config ... Up 9093/tcp
grafana /run.sh Up 3000/tcp
nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
prometheus-01 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-02 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-03 /bin/prometheus --config.f ... Exit 0
今度は3台目のPrometheus
が落ちたので, 1台目と2台目のPrometheus
で同じInstanceDownのアラートが発生する.
ただしAlertmanager
側で重複が排除されるようになっているので, アラートは1件として扱われて通知も1件のみ届く.
以上で複数のPrometheus
で同じアラートが発火した場合でもAlertmanager
で重複排除されることが確認できた.
Alertmanagerも冗長化する
Prometheus
は冗長化できたが, Alertmanager
だって絶対落ちないとは限らないのでこれも冗長化したい.
ただしAlertmanager
の場合は実際に通知を送る機能があるため, Prometheus
のように単純に同じものを複数用意するのはあまり良い方法ではなさそう.
(1つのアラートに対して複数のAlertmanager
がそれぞれ通知を送ってしまう)
このため, 複数のAlertmanager
を同時に動かす場合は互いの状況を知るためにメッシュを構成する3.
難しそうに思えるがAlertmanager
の冗長化機能はあらかじめ有効化されているので, 実行時引数--cluster.peer
で同時に動かす対象のホスト名を指定してやれば良い.
(相互の確認に使うポートは9093でなく9094であることに注意)
Prometheus
x3prometheus.yml
: 監視対象とアラートを送る対象に複数のAlertmanager
を追加する(必須)rules.yml
: そのまま
Alertmanager
x3alertmanager.yml
: そのまま- 実行時引数
--cluster.peer
で他のAlertmanager
を指定(必須) - 動作確認用に9093番ポートを疎通可能にしておく(やらなくても良い)
Grafana
grafana.ini
: そのままdatasource.yaml
: そのまま
nginx
default.conf
: 複数のAlertmanager
のロードバランシング設定を追加(やらなくても良い)
prometheus.yml
でアラートの送信先を指定する際はnginx
で負荷分散しているAlertmanager
のエンドポイント(/alertmanager
)を指定したくなるが,
公式FAQによると「Prometheus
からはすべてのAlertmanager
にアラートを送れ」とあるので今回はそれに従っている.
設定ファイルが準備できたら再度コンテナを立ち上げる.
# ディレクトリ構成
$ tree .
.
├── deployment
│ ├── alertmanager
│ │ └── alertmanager.yml
│ ├── grafana
│ │ ├── datasource.yaml
│ │ └── grafana.ini
│ ├── nginx
│ │ └── default.conf
│ └── prometheus
│ ├── prometheus.yml
│ └── rules.yml
└── docker-compose.yml
# コンテナ起動
$ docker-compose up -d --force-recreate --remove-orphans
# 今回は動作確認用にlocalhostから直接Alertmanagerにつながるようにしている
$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------
alertmanager-01 /bin/alertmanager --config ... Up 0.0.0.0:8093->9093/tcp
alertmanager-02 /bin/alertmanager --config ... Up 0.0.0.0:8094->9093/tcp
alertmanager-03 /bin/alertmanager --config ... Up 0.0.0.0:8095->9093/tcp
grafana /run.sh Up 3000/tcp
nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
prometheus-01 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-02 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-03 /bin/prometheus --config.f ... Up 9090/tcp
まずはそれぞれのAlertmanager
を開いてメッシュが有効になっていることを確認する.
- alertmanager-01 : http://localhost:8093/#/status
- alertmanager-02 : http://localhost:8094/#/status
- alertmanager-03 : http://localhost:8095/#/status
Cluster Status
を見るとそれぞれのName
を互いにPeers
として認識していることがわかる.
この状態で試しに1台目のAlertmanager
でSilence
(アラートを一時的に無視する設定)を作成してみる4.
すると2台目と3台目のAlertmanager
にも同じSilence
が勝手に作成されており, これで3台のAlertmanager
がメッシュとして正しく動作していることがわかる.
最後にAlertmanager
の動作確認のため, Grafana
を落としてInstanceDownのアラートを発火させてみる.
# Grafanaを落とす
$ docker-compose stop grafana
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------
alertmanager-01 /bin/alertmanager --config ... Up 0.0.0.0:8093->9093/tcp
alertmanager-02 /bin/alertmanager --config ... Up 0.0.0.0:8094->9093/tcp
alertmanager-03 /bin/alertmanager --config ... Up 0.0.0.0:8095->9093/tcp
grafana /run.sh Exit 0
nginx /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
prometheus-01 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-02 /bin/prometheus --config.f ... Up 9090/tcp
prometheus-03 /bin/prometheus --config.f ... Up 9090/tcp
今までと同じくupが0になり, Prometheus
でアラートが発火する.
Alertmanager
側でもアラートを受け取っているが,
先程確認したとおり3台のAlertmanager
はメッシュとして動作しているのでそれぞれが動作して3回通知が送られるということはなく通知は1件のみ届く.
やったぜ.Prometheus
だけでなくAlertmanager
も冗長構成で動かすことができた.
おわり
Prometheus
とGrafana
を冗長構成で動かしてみた.
今回はGrafana
の冗長化はしなかったけど, 落ちたところでグラフが見られなくなるくらいしか困ることがないのでやらなくて正解だったかも.
(やったとしてもnginx
の下に複数台ぶらさげるだけになりそう)
今回はDocker Compose
で試してみたけど, 実際にそれぞれ別のサーバーで動かす場合もコンテナ名で名前解決している部分をホスト名に変えてやれば同様の動作になるはず.
お金と時間に余裕があればVMとかで試してみたい(たぶんやらない).
おまけ
https://prometheus.io/docs/introduction/faq/#can-prometheus-be-made-highly-available ↩︎
https://nginx.org/en/docs/http/ngx_http_upstream_module.html ↩︎
https://github.com/prometheus/alertmanager#high-availability ↩︎
https://www.robustperception.io/high-availability-prometheus-alerting-and-notification ↩︎