Basicライセンスの下、Elasticsearchのアラートを発報する

# はじめに
Elasticsearchを使っていると、データが溜まってくるに従ってインデックスが多くなってきます。
インデックスパターン毎にライフサイクルを管理できていれば良いですが、
うっかりしていると多くなりすぎて、`open_file_descriptors`が最大値（`max_file_descriptors`）に達してしまい、
インデックスが作成できなくなる事態が発生し得ます。

こういったリソース不足の発生を検知するために、リソース状況を監視し、通常と異なる振る舞いをしている場合にはアラートを発報することが必要です。

Elasticsearchの有償ライセンスを購入していれば、[Watcher](https://www.elastic.co/guide/en/elasticsearch/reference/current/xpack-alerting.html)というアラート機能を使用することができますが、無償のBasicライセンスで運用している場合、Watcher機能を使用することができません。

そこで、アラート通知のためにgrafanaを利用し、Elasticsearchノードのリソース不足を通知できるようにしてみます。
(Elasticsearch + grafanaという組み合わせは検索するとたくさん出てきますが、「Elasticsearchでアラートと言ったらWatcher!」という固定観念があり、なかなかそれに気が付きませんでした。grafana自体ほとんど使ったことがなかったので、今回はその備忘を兼ねて書きます。)

# 環境
以下の環境で試してみます。

```terminal
$ docker version
Client: Docker Engine - Community
 Version:           19.03.5
 API version:       1.40
 Go version:        go1.12.12
 Git commit:        633a0ea838
 Built:             Wed Nov 13 07:22:05 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.5
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.12
  Git commit:       633a0ea838
  Built:            Wed Nov 13 07:28:45 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

$ docker images | grep elasticsearch
elasticsearch                       7.6.1               41072cdeebc5        4 weeks ago         790MB

$ docker images | grep grafana
grafana/grafana                     6.7.0               8d9380d6a636        11 days ago         233MB
```

# Elasticsearch の設定
何はともあれ、[X-Pack Monitoring](https://www.elastic.co/guide/en/elasticsearch/reference/current/monitor-elasticsearch-cluster.html)を有効にして、モニタリングデータを収集できるようにします（デフォルトでは有効になっていません）。
[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/collecting-monitoring-data.html)を参考にして、収集したモニタリングデータを同じクラスタに格納します。
（本番環境でX-Pack Monitoringを使用する場合、[本番ワークロードを実行するクラスタとモニタリングデータを収集するクラスタを分けることが推奨されています](https://www.elastic.co/guide/en/elasticsearch/reference/current/monitoring-overview.html#monitoring-overview)。また、モニタリングデータの収集・転送には、[MetricBeatを使用する](https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-metricbeat.html)ことが推奨されています。）

今回は簡単のため、単一のElasticsearchノードからなるクラスタで試します。
（複数ノードクラスタを使用する場合、Basicライセンス下ではX-Pack Securityの設定が必要となります。）

今回は、以下の通り設定しました。（設定可能な項目の一覧は[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/monitoring-settings.html)）。

```yaml:docker-compose.yml
services:
  elasticsearch:
    image: elasticsearch:7.6.1
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - xpack.monitoring.enabled=true
      - xpack.monitoring.collection.enabled=true
      - xpack.monitoring.elasticsearch.collection.enabled=true
    ports:
      - "9200:9200"
```

収集されたElasticsearchのモニタリングデータは、インデックスパターンが`.monitoring-es-7-*`であるインデックスに格納されます（templateは`.monitoring-es`です）。

```
$ curl -s "localhost:9200/_cat/indices" | grep "\.monitoring-es-7"
green open .monitoring-es-7-2020.03.21 5GydtmSWSCSmKHYmVIUoXw 1 0 1001 165 701kb 701kb
```

# Grafanaの設定
モニタリングデータの収集ができるようになったので、grafanaでデータを取得し、アラートを設定します。
以下は、[公式ドキュメント](https://grafana.com/docs/grafana/latest/features/datasources/elasticsearch/)を参考に設定しています。
`docker-compose.yml`は以下の通り。

```yaml:docker-compose.yml
version: "2.2"
services:
  grafana:
    image: grafana/grafana:6.7.0
    container_name: grafana
    ports:
      - "3000:3000"
```

## データソース設定
データソースとして、収集対象のインデックスを設定します。
注意点として、普通のインデックスでは、データ投入時点を表す`@timestamp`フィールドが存在しますが、`.monitoring-*`のインデックスには`@timestamp`が存在しません。代わりに`timestamp`フィールドが存在するので、Time field nameにはそちらを指定します。
今回は以下の通り設定しました。

![データソース設定1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/a702e8c7-35fc-64e2-f598-c46d1a833d77.png)
![データソース設定2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/f2b4a0b4-77ee-303c-9513-bb50db6eb672.png)

## 通知チャネルの設定
通知チャネルを作成します。今回は、Slackへ通知してみることにします。
Slackで[Incoming Webhook](https://slack.com/intl/ja-jp/help/articles/115005265063-Slack-での-Incoming-Webhook-の利用)をあらかじめ作成しておきます。
以下のように設定しました。
![通知チャネル設定1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/129c8744-f0e6-45db-7f39-f9825c21ddc1.png)

## アラートの設定
file descriptorの増加を監視するためのメトリックは`node_stats.process.open_file_descriptors`です。
監視設定とアラートの設定を、以下の通り設定しました。
（アラートが発報されるのを確認するため、閾値は小さい値を設定しています。）
![アラート設定1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/6997e011-c3de-63c1-4e13-4978cc59f4f7.png)
![アラート設定2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/b0e58133-d49a-f7d4-c49e-cfb641008ac0.png)
![アラート設定3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/ec98543d-ca7c-592e-6d2e-fa403401bed9.png)


# アラートの確認
設定できたら、アラートの確認をします。（モニタリングインデックス自体が増加するため、それに伴いfile descriptorも増加します。）
<img width="320" alt="Slack通知1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115336/96a62929-7987-ba6c-3eb2-9c856cb114f2.png">

ちゃんと通知できているようです。