Grafana5.2.0+でElasticsearch内のデータに対するAlertingを実行し、Discordに通知する

# はじめに
2018/6/27にリリースされたGrafana 5.2.0で遂にElasticsearch内のデータに対するAlertingが実行できるようになりました。
[（リリースノートはこちら）](http://docs.grafana.org/guides/whats-new-in-v5-2/)

これまではElasticsearchの閾値検知の仕組みとして、X-Pack Alerting以外の選択肢は[Elastalert](https://github.com/Yelp/elastalert)ぐらいでしたが、そこに新たな方法が浮上したことになります。

本記事では、Grafana(v5.2.1)を使って、Elasticsearch(v6.3.1)内に保管されたMetricbeatのメトリックに対する閾値検知を実行し、Discordに通知するまでの流れを紹介します。


# 環境準備
## 目指す環境の状態
Metricbeatが起動されており、ElasticsearchにCPU使用率が常時投入され続けている状態であること。
また、Grafanaが起動しており、Elasticsearchと疎通可能なネットワークに繋がれていること。
その状態の環境が既にあれば、本章は読み飛ばしてください。

## 前提条件
Linux系OSで以下のツールが使える状態であること。

- git
- Docker Engine 1.13.0+
- docker-compose

## 準備手順
Elastic公式の全部入りdocker-composeをgit cloneし、`docker-compose.yml`にGrafanaの定義を追記します。
今回は現時点で最新の6.3.1を指定します。

```bash
git clone https://github.com/elastic/stack-docker.git
cd stack-docker
vim docker-compose.yml
```

```diff
  ...(省略)...
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:${TAG}
    container_name: elasticsearch
    environment: ['http.host=0.0.0.0', 'transport.host=127.0.0.1']
    ports: ['127.0.0.1:9200:9200']
    networks: ['stack']

+ grafana:
+   image: grafana/grafana:5.2.1
+   ports: ['3000:3000']
+   networks: ['stack']

  kibana:
  ...(省略)...
```

Grafanaの定義を追記したら`docker-compose up`で起動します。起動時にTAGでElastic Stackのverを指定します。

```bash
TAG=6.3.1 docker-compose up
```
実行後、しばらく待つと、Elasticsearch（localhost:9200）、Kibana（localhost:5601）、Grafana（localhost:3000）に接続できるようになります。

## 準備手順の注意事項

なお、この時ホストLinuxのkernelバージョンが古いと以下のメッセージが出現するかもしれません。

```terminal
ERROR: for auditbeat  Cannot start service auditbeat: linux spec capabilities: Unknown capability to add: "CAP_AUDIT_READ"
```

この場合は、以下のように、思い切って`docker-compose.yml`からAuditbeat関連の記述（`auditbeat`配下と`setup_auditbeat`配下）を削除します。今回はあくまでMetricbeatだけ動けばよいので。

```diff
-  auditbeat:
-    image: docker.elastic.co/beats/auditbeat:${TAG}
-    container_name: auditbeat
-    cap_add: ['AUDIT_CONTROL', 'AUDIT_READ']
-    # Auditbeat must run in the main process namespace.
-    pid: host
-    networks: ['stack']
-    depends_on: ['elasticsearch']

-  setup_auditbeat:
-    image: docker.elastic.co/beats/auditbeat:${TAG}
-    container_name: setup_auditbeat
-    volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro']
-    # The script may have CR/LF line endings if using Docker for Windows, so
-    # remove them so that they won't confuse Bash.
-    command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s auditbeat']
-    networks: ['stack']
-    depends_on: ['kibana']
```

また、Virtualboxなど、直接ホストLinuxに接続できない環境の場合は、`elasticsearch`と`kibana`のポート設定を以下のように変更します。

```diff
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:${TAG}
    container_name: elasticsearch
    environment: ['http.host=0.0.0.0', 'transport.host=127.0.0.1']
-   ports: ['127.0.0.1:9200:9200']
+   ports: ['9200:9200']
    networks: ['stack']

  kibana:
    image: docker.elastic.co/kibana/kibana:${TAG}
    container_name: kibana
-   ports: ['127.0.0.1:5601:5601']
+   ports: ['5601:5601']
    networks: ['stack']
    depends_on: ['elasticsearch']
```

これでポートフォワーディング越しでもブラウザで接続できるようになります。

# DiscordのWebhook設定
Grafanaの設定に移る前にDiscordのWebhook設定をしておきます。
面倒なので画像で済ませます。

まず、サーバ設定画面に遷移します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/e3ddd05a-016c-b2b4-3330-d4d5f59a9b91.png)

続いて、Webhooks設定画面へ遷移し、新規Webhookを作成します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/22fdba07-b61c-5a07-88a8-12b21fe434f0.png)

新規追加するWebhookの設定をします。アイコン画像をGrafanaにしておくといい感じです。
また、ここでWebhook URLを控えておくと良いです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/94c089fa-57db-b2fd-d045-ec37aa1305ff.png)

Discordの設定は以上です。

# GrafanaでElasticsearch内のデータに対するAlertingを設定する
## データソースの設定
ブラウザで`localhost:3000`に接続し、Grafanaにログインします。初期IDと初期passwordは`admin:admin`です。
初回ログイン時はパスワードの変更をサジェストするのでスキップするなり、変更するなりします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/8b12072a-ade6-539b-0fad-997250e41564.png)

初期画面に移動できたら、データソース追加画面に遷移します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/bb129f41-ff64-ad5d-0692-0d3c025e2055.png)

遷移後、データソースの設定をします。
初期値ではなく変更しているものを以下に示します。他は初期値ままでOKです。

|名称|設定値|備考|
|----|-----|----|
|Name|MyES|データソースに付与する名称|
|Type|Elasticsearch|データソースの種類|
|URL|http://elasticsearch:9200|データソースのURL。Dockerでなければ`http://localhost:9200`とかになるはず。|
|Index name|[metricbeat-6.3.1-]YYYY.MM.DD|データソースとするindex名の形式|
|Pattern|Daily|データソースとするIndexがどの時系列レベルで分割されるか（時/日/週/月/年）|
|Version|5.6+|Elasticsearchのバージョン|

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/4472bced-c1a5-aabb-0851-0603f8dca270.png)

データソースの設定に必要な項目を入力したら`Save & Test`をクリックします。`Index OK. Time field name OK.`の表示が出れば問題なく接続できています。
エラーっぽい表示が出たら環境や入力した情報を見直してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/d2b8ce5c-4e27-0887-2a13-d1afc051c658.png)

## Alerting設定

新規ダッシュボードを作成します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/61e55ab5-4604-714c-c277-226fb0da1ee4.png)

New Panelのグラフ形式選択で`Graph`を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/a4a0fc9a-9707-3896-7858-73f913435bf4.png)

追加されたGraphの編集画面へ遷移します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/61626a38-d149-5e41-805c-f19f9663388f.png)

以下のようにグラフで可視化するメトリックの設定をします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/4d44674a-3c75-b1a1-2743-983dcf2fdec5.png)

メトリックの設定を終えたら、Alertの設定画面へ遷移し、新規Alertを作成します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/0ea7e329-a995-2c27-f329-2c6702199695.png)

Alertの設定をします。すぐさま`Test Rule`を実行したいところですが、Dashboardが保存されていないと実行できないので、いったんダッシュボードを保存します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/acb0e852-ee2a-66fa-e0ba-5549071b1fd4.png)

その後、同じ画面に戻って`Test Rule`を実行すると、こんな感じで結果が見られます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/7751c34e-1051-2391-8684-40d07fa2160b.png)

`Metric: Average system.cpu.total.pct`の値は`Value: 0.104`で、設定された閾値0.80を超えなかったため、`Eval: false`ですよ、というように読み取れます。これでAlertのルールが設定できました。

## Disocrdへの通知設定
上記のAlertが失敗したときにGrafanaからDiscordへ通知が飛ぶように設定します。

Notification channelsの設定画面に遷移します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/c7f85edf-bf59-2226-68f3-8d3320326848.png)

`Add channel`をクリックし、新しい通知先を設定します。

|名称|設定値|備考|
|----|-----|----|
|Name|MyDiscord|新規作成するNotification Channelに付与する名称|
|Type|Discord|Notification Channelの種類|
|Webhook URL|（Discord側で払い出したWebhookのURL）|通知先URL|

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/3bd8a2be-56a0-b114-e235-c91f8be398b7.png)

ついでにこの画面で正常に通知が送られるかの動作確認もできます。`Send Test`してみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/439f729b-d265-7d6f-06b6-a8e1d9b8670b.png)

こんな感じでDiscordの通知が飛んできます。画像も含まれて良い感じです。
では、動作確認を終えたので`Save`して、Notification Channelを有効にしましょう。

再度、先ほど作成したGraphのAlert画面へ遷移します。Alert Rules画面から遷移するのが楽です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/aacd9771-cdf5-178a-b552-b5178b1e0e50.png)

通知先の設定をします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/e9a0747a-3cb6-7883-011c-2e9b66f288ae.png)

これで全ての準備が整いました。

# 動作確認
実際にコンテナに負荷をかけて確認してみます。
（環境に負荷をかけたくない方は閾値を変更したりして動作確認してください。）

```bash
docker exec -it metricbeat bash
yes >> /dev/null
```

しばらくすると、Discordに通知が飛んできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/5e89dfbb-0fc6-dae5-e663-75a4a52aadeb.png)

見事に100%使用しています。かわいそうなのでコンソール画面で`Ctrl+C`して、負荷を止めてあげます。

```bash
Ctrl+C
```

しばらくすると、再度Discordに通知が飛んできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/822928ca-9315-e8e6-6ad9-bd2880ef473b.png)

このように回復した際の通知も飛んできます。やったぜ。
また、Grafana画面でも過去の状態履歴を見ることもできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/264679/bcec0c93-1391-1390-6273-6901b7a2eff1.png)


# おわりに
いかがだったでしょうか。
GUIのみで簡単に設定ができ、通知先も豊富なGrafanaにElasticsearchのAlert機能が搭載されたのは非常に強力だと思っています。

なお、Grafanaは今回初めて触ったので、よりスマートな設定方法などあればコメントで指摘をお願いします！