Alertmanagerについて書いてみる

Prometehus, Grafanaでモニタリングできるのはもうわかったので監視をどうするかというとAlertmanagerを使うことになります。

Prometehus本体に比べればAlertmanagerはまだ成熟してないと思うけど、使う価値は十分にあると個人的にあると思ってます。

その理由は2つあって、Prometehusで収集したメトリクスに対してアラートを設定できることと、アラート通知をまとめることができるということ。


1番目はまあわかりますよね。GangliaでモニタリングしてNagiosで監視とかだとツールが分かれているのでやりづらい。Gangliaでモニタリング結果に対してNagiosでアラート通知できないからね。


2番目が今日最も書きたかったこと。


監視はナイーブにやると、いったんアラートがなったときに対処しない限り延々とアラートがなり続けることになります。

例えばあるプロセスが落ちてたら通知することを考えてみましょう。


そうですね。例えばpresto workerが10台起動しているものとして、10台じゃなくなったらアラート通知するとします。
こんな感じのスクリプトをcronで5分間隔で実行するとします。send_notify関数で監視ツールにpostしていると思ってください。

presto_nodes=`java -jar ...`

if [ ${presto_nodes} -ne 10 ]; then
  message="some presto node is down! now presto has ${presto_nodes} nodes..."
  send_notify(message)
fi

夜中3時に9台になって誰も気づかなかったら延々と通知が来ますね。
他のアラートが来ても埋もれそうですよね。

それじゃあ辛いのでスクリプト側をこんな感じにしたとします。

if [ -e /tmp/presto.down ]; then
  exit
fi

presto_nodes=`java -jar ...`

if [ ${presto_nodes} -ne 10 ]; then
  message="some presto node is down! now presto has ${presto_nodes} nodes..."
  send_notify(message)
  echo ${message} > /tmp/presto.down
fi

これならアラートは1回しか来ない!素晴らしい!
でも復旧作業が終わったら/tmp/presto.down消す必要ありますけど、まあ忘れますよね。
それにそもそもこの手の処理を監視スクリプト側に毎回入れないといけないのは辛い。

ここではcronでチェックする例を入れましたけど、標準で用意されてそうなHDD使用率のチェックとかでもアラート通知洪水は起きがちですよね。


ツールによってはerror levelで通知間隔を制御するものもあります。

例えば、HDD使用率が90%を超えてたらlevelがerrorということで10分間隔で通知する、
HDD使用率が95%を超えてたらlevelがfatalということで1分間隔で通知する。

エラーが本当に深刻なものなら通知が来続けて欲しいという人も中にはいますが、僕の経験上、精神を疲弊させると思います。
それに他のアラートが来ても埋もれそうになる問題は避けられない。メール通知ならメーラーのフィルタリングで頑張るという手もあるかもしれませんが。


前置きが長くなりましたが、そこでAlertmanagerですよ。

Alertmanagerはこんな感じでルールを書きます。IFのところがアラートの条件ですね。この例だとupが0の状態が5分超えたらアラート。
FORの部分のおかげで突発的なものはフィルタリングできます。LABELSとANNOTATIONSは補足情報ですね。

# Alert for any instance that is unreachable for >5 minutes.
ALERT InstanceDown
  IF up == 0
  FOR 5m
  LABELS { severity = "page" }
  ANNOTATIONS {
    summary = "Instance {{ $labels.instance }} down",
    description = "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes.",
  }

Prometheusの世界ではアラートもメトリクスです。アラートがなると下記メトリクスが1になります。

ALERTS{alertname="InstanceDown", alertstate="firing", ...}

alertnameでグルーピングされるので、同じアラートが延々きつづけることはありません。
最初のアラートが来て何も対処しない状態だと4時間後に再度アラートが来ます。素晴らしい。
この設定はrepeat_intervalです。


モニタリング対象ホストにexporterをsetupしてメトリクスをPrometheusサーバーからpullしてそれに対してアラートを設定するのが一般的です。

ただ上記の例みたいにcronでチェックしたい場合もあるでしょう。

その場合はAlertmanagerに直接POSTすることもできます。
https://prometheus.io/docs/alerting/clients/

presto workerの例だとこんな感じ。

presto_nodes=`...`

if [ ${presto_nodes} -eq 10 ]; then
  exit 0
fi

curl --data-binary @- http://alertmanager.../api/v1/alerts << EOS
[
  {
    "labels": {
      "alertname": "presto_down",
      "severity": "major"
    },
    "annotations": {
      "summary": "some presto node is down! now presto has ${presto_nodes} nodes.."
    }
  }
]
EOS

これでアラート通知洪水に悩まされることも無くなります。

復旧したかどうかをどう判断するかというと、resolve_timeout(default: 5m)の時間が経ってもアラートがPOSTされてこなかったら解決したとAlertmanagerが判断してます。

Alertmanagerの通知方法として僕はwebhookを使っているんですが、デフォルト設定だとアラート発火と解決の両方のタイミングで通知があります。
send_resolvedをfalseにすればおそらくアラート解決の通知は来ないと思います。

そんなわけで、Alertmanagerには通知を工夫している部分が感じられるので将来有望なソフトだと思ってます。素晴らしい。