ElasticsearchのData StreamとILMについて

# はじめに
Elasticsearchにログやメトリクスを保存して利活用されている方は多いと思います。
ただデータには「鮮度」があります。当然ながら新しいデータほど価値があり、素早く解析すればするほど効果が出ます。例えばセキュリティインシデントなどはそれにあたります。
それに対して、長期間データを保存しなければいけないこともあります。しかしそれらのログはたまにしか参照しないためそこまで性能を必要とはしないこともあります。監査ログ等はそれにあたります。

上記の2つの要望を満たす方法として、Elasticsearchにはデータティアリングの考え方があります。本ブログではデータティアリングの使い方について基本的な解説をいたします。

:::note warn
Elasticsearchのバージョンは8.13.1をベースに記載しています
:::

# Data Stream
ログやメトリクスは次々に新しいデータが入ってきますが、上書きしたりすることはまずありません。そのようなデータを効率的に処理するためにElasticでは`Data Stream`という形式が使用されます。
ドキュメントが２つあります。
- Elasticsearchのドキュメント
https://www.elastic.co/guide/en/elasticsearch/reference/current/data-streams.html
これはData Streamをマニュアルで管理する方法です
- Elastic Agentのドキュメント
https://www.elastic.co/guide/en/fleet/current/data-streams.html
Elastic Agentで自動生成されるData Streamについてのマニュアル

このブログではElastic Agentで生成されるData Streamについて解説します。

ログやメトリクスのインデックスは基本的にどんどん追記されていって、インデックスがある程度まで大きくなったりすると別の名前のインデックスを作っていきます。これを**ロールオーバー**といいます。
例えば以下のような感じになります。
![スクリーンショット 2024-05-10 15.45.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/1e0a379a-cc61-e9a5-cea9-9771bf663d83.png)

勿論ログを検索するときには全てのインデックスが検索対象となります。
![スクリーンショット 2024-05-10 15.47.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/af3d29f5-abfe-7b90-458e-134da65c631c.png)

なぜこんな事をするかというと、一つのインデックスに書き込み続けるとそのインデックスが大きくなりすぎて効率が悪くなるからです。基本的には一つのインデックスが10-50GBぐらいになるように設計します。
詳しくはこのページに記載されています。
https://www.elastic.co/guide/en/elasticsearch/reference/8.13/size-your-shards.html#shard-size-recommendation

逆に小さいインデックスを大量に作成するのも効率が悪いです。
ここを効率的に制御する仕組みが`Data Stream`と`ILM`です。

## Data Streamの名前とインデックス
### 名前
Data Streamと言っても結局は普通にElasticsearchのインデックスの集まりです。ログやメトリクスでは大量のインデックスが作成されるので、それらをわかりやすく管理するために名前がつけられます。
Data Streamの命名は決まりがあります。

`<type>-<dataset>-<namespace>`
- type
`log`とか`metrics`などです
- dataset
`nginx`とか`system.auth`などです
- namespace
何もしないと`default`になりますが、自由に指定できます。

ただ上記のように決めればわかりやすいというだけで、ルールとしてハイフンで３つつなぐということだけです。
別に`hoge-hoge-hoge`とかでも大丈夫です。

### インデックス
`<type>-<dataset>-<namespace>`という名前のインデックスが作られるわけではありません。これはエイリアスのようなものです。
何も設定をせずにElastic AgentをLinuxにインストールすると、`/var/log/auth.log`を勝手に集めてくれます。このときのインデックス名は`.ds-logs-system.auth-default-<日付>-<通し番号>`です。例えば`.ds-logs-system.auth-default-2024.05.02-000001`という感じです。

## デフォルト設定
ではデフォルトでどのように動くのか見ていきます。
何も設定をせずにElastic AgentをLinuxにインストールする場合を見てみます。

### Agent Policy
Agent Policyはどのようなログを集めるのかという設定です。何もしなければSystem Logを集める設定が自動的にONになっています。
Fleet -> Agent Policies -> Create Agent Policyとすると以下のような画面になります。
![スクリーンショット 2024-05-20 13.28.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/196efc90-2446-b353-8e19-bf2f485be046.png)
**Collect system logs and metrics**という部分にチェックボックスがついていますので、自動的に`/var/log`等を集める設定が行われます。
適当に名前を入れてAgent Policyを作ってみます。無事作り終わると一覧の部分に今作成したpolicyが表示されているので、それをクリックしてみます。
![スクリーンショット 2024-05-20 13.32.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/869a8f37-ad43-bfdd-9911-ed696b2db988.png)
このように**System**というものが自動的に設定されています。これが**Integrations**と呼ばれるもので、何を集めるかという設定です。とりあえず左端（ここでは**system-3**)をクリックします。
![スクリーンショット 2024-05-20 13.35.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/825a5825-9e37-f703-a53c-d322c6b0775d.png)
これを見ると何を集めるのか一目瞭然です。

### Data Streamの名前
設定はこれで終わるのですが、このままではData Streamの名前がわかりません。
Integrationsを使用すると一部を除き(Custom Logs等)Data Streamの名前は自動的に決まります。
`<type>-<dataset>-<namespace>`のうち、`<type>`はlogsやmetrics等が自動的に入ります。`<dataset>`はIntegraionsの種類によりますが、大体そのIntegraionsの名前が入っています。
今回のLinuxのデータだと`system.auth`や`system.syslog`等です。NGINXだと`nginx.access`とかになります。
`<namespace>`は`default`になってますが、ここは変更できます。Integration settingsのAdvanced optionsをクリックして開くとNamespaceを変更できます。
![スクリーンショット 2024-05-28 12.59.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/a2cada20-a55f-edb5-c2ae-0a2a6e848dc2.png)

### Data Streamの確認
Stack Management -> Index Management -> Data Streamとクリックします。
検索ボックスに**system**と入れると`logs-system.auth-default`が表示されるのでそれをクリックします。これが上記で設定したLinuxのSystem LogのData Streamです。
![スクリーンショット 2024-05-28 13.12.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/321e3441-a45d-1efc-4336-563a76e8a039.png)

ではまずデータを見てみましょう。
`logs-system.auth-default`の右側にある方位磁石のようなアイコンをクリックするとDiscoverのページに飛べます。
![スクリーンショット 2024-05-28 15.17.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/65a90e6d-58c2-b048-4a5e-8a051a2facfa.png)
Discoverでのログ表示
![スクリーンショット 2024-05-28 15.25.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/bc7cd431-9ffe-7ad2-117e-df881fe51faf.png)

とりあえずデータが取れていることが確認できます。

# 世代管理
Data Streamの中身がわかったところで、次に世代管理について説明していきます。
ElasticにはHot-Warm-Cold-Frozenという4つのデータティアがあり、Frozenに近づくほどコストが下がりますが検索性能が落ちます(=検索に時間がかかる)。
検索性能は大体RAM:Storageの比率で決まります(RAMがStorageに比べて大きければ検索は早い)
性能面についてはこちらのブログに記載があります。
https://www.elastic.co/jp/blog/querying-a-petabyte-of-cloud-storage-in-10-minutes
- Hot
    - RAM:Storage=1:30ぐらい。全てのデータは必ずHotに入る
- Warm
    - RAM:Storage=1:160ぐらい。
- Cold
    - ここから少し役割が変わります。Coldはデータの冗長性を無くしますので単純に倍のデータが入ります。もちろんノード障害が起きるとデータが消失しますが、Searchable Snapshotを設定しておくと、自動的にSnapshotからデータが復活します。
- Frozen
    - 実データを全てオブジェクトストレージに入れておき、ローカルにはキャッシュしか持たないので、非常にコストは安い。アクセスが有ると必要な部分だけオブジェクトストレージから取ってくる。
    https://qiita.com/nobuhikosekiya/items/dd2ce836b184730f8d70#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB

これらのデータティアをどの用に使うかを設定するのがILMです。
まずは上記で設定した`logs-system.auth-default`がどう設定しているか見てみます。
再度Data Streamの設定を見てみます。右下のIndex lifecycle policyに`logs`とありますのでこれをクリックします。
![スクリーンショット 2024-05-28 16.58.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/eaf88b83-9728-f0ca-b362-98d1796af32d.png)
以下の画面がILMを設定する画面です。赤線で囲った部分をクリックして詳細な情報を表示します。
![スクリーンショット 2024-05-28 17.23.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/1e1daab9-9866-384e-7438-b722d043b19a.png)

デフォルトではHotにずっと残り続けます（=データ量が増え続ける）。右上に**Keep data in this phase forever**とある部分がそれです。

**Rollover**とありますが、これがインデックスを新しく作っていく部分です。
デフォルトでは以下の条件で新しいインデックスが作成されます。

- Maximum primary shard size: 50GB
    - シャードのサイズが50GBを超える
- Maximum age: 30days
    - インデックスが作成されてから30日経過する

上記のどちらかに引っかかると新しいインデックスが作成されて、今までのインデックスは読み込み専用になります。
1日に500GBの書き込みがあれば、1日に10個のインデックスが作成されることになります。
逆に1日に1MBの書き込みしかない場合、30MBのインデックスが1ヶ月毎に作成されます。
他にはドキュメントの数(=ログの数)でもRollover出来ます。

例) 毎日100GBの書き込みがある場合
最初に`.ds-logs-system.auth-default-2024.05.02-000001`が作成されます。12時間後に50GBに達するのでその時点で`.ds-logs-system.auth-default-2024.05.02-000001`は読み込み専用となり、新たに`.ds-logs-system.auth-default-2024.05.02-000002`が作成される。

## データティア移動の設定
それでは、以下のような条件にする場合を説明します。
- RolloverしたらすぐにWarmへ移動
- 365日たったら消去

以下のような設定になります。
![スクリーンショット 2024-05-28 17.41.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/010a79ab-7970-0af6-4097-43947827e628.png)

:::note warn
ここで保存すると全てのログにこのポリシーが適用されます
:::

- Warm phaseを有効にする
    - これはクリックするだけです
- `Move data into phase when`に**0**を入れる
    - ここが複雑な部分です。ここに入れる日数というのは「Rolloverしてからの日数」です
    - 例えば毎日5GBのデータが書き込まれるとすると、Rolloverするまでに10日かかりますので、Warmに移るのはインデックスが作成されてから10日後です。もしここに**3**と入れればRolloverしてからHotに3日間滞在してからWarmへ移りますので、インデックスが作成されてから13日後にWarmへ移ります。
- `Delete data after this phase`のゴミ箱アイコンをクリック
    - これによりDelete phaseが追加されます
- Delete phaseの`Move data into phase when`は自動的に365になっています。これの意味するところも同じでRolloverしてから365日なので、Rolloverしてから365日でそのインデックスは消去されます。

## デフォルト設定
`logs-system.auth-default`が`logs`というポリシーを使うというのは特に設定する必要はありませんでした。これは**Index Template**という機能を使って`logs-`から始まるものは全て`logs`ポリシーを使うようになっているからです。
### Index Template
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-templates.html
Elasticsearchのインデックスにはいろいろな設定があります。ILMのポリシーもそうですが、レプリカを何個持つかとか、どのようなMappingにするか、日本語処理をどうするか、などです。
一つ一つ設定を入れていくのは面倒なので、似たようなインデックスは同じ設定にしたいですよね？それを実現するのはIndex Templateです。それでは実際にどういうものか見ていきましょう。

`logs-system.auth-default`の下記画面にある`Index template`の下の`logs-system.auth`をクリックします。
![スクリーンショット 2024-05-30 10.14.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/8f5d4e45-1977-e9b8-1ba6-0e70ef7e2e36.png)

するとこのような設定が出てきます。
![スクリーンショット 2024-05-30 10.30.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/29c135d2-5ca3-ce95-6b86-de4f5cc57eb5.png)
少し解説します。
- Index pattern
    - `logs-system.auth-*`というパターンにマッチするインデックスは全てこのテンプレートにある設定が適用されます。
- Priority
    - この値が大きいほど優先して適用されます。例えば`logs-system*`っていうIndex Patternで別のテンプレートを作るとどっちを適用していいかわからなくなります。そういう場合にこのPriorityで使い分けます。デフォルトは200になっています。
- Component templates
    - テンプレートの部品です。同じ設定をいろんなテンプレートで使い回せるようになっています。`ecs@mappings`なんかはほぼ全てで使われています。

さて、ここまで見ても`logs`というILMポリシーがどこで設定されているかがわかりません。その設定はComponent templatesの`logs@settings`に記載されています。Stack Management -> Index management -> Component Templatesとクリックして、`"logs@settings"`で検索します。
![スクリーンショット 2024-05-30 10.49.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/bda50d68-3a02-d484-2e37-cd8e30585100.png)
このテンプレートが`logs-`から始まるインデックスに適用されていることがわかります。`Settings`をクリックしてみます。
![スクリーンショット 2024-05-30 10.51.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/8c4f760c-3f30-3aae-9f93-ba6a50aaa6b4.png)
ようやく出てきました。ここで`logs`というILMポリシーが適用されていること言うことがわかります。

面倒くさい？？実はDev Toolsを使うと一発でこの情報が出てきます。Dev Toolsに
```
GET logs-system.auth-default
```
と入力してみてください。下の方に同じ情報が出てきます。（Mappingが長々と出てきます）

## ILMポリシーの変更
当然ですが、ログの種類によって保存期間は変更したいですよね。メトリクスは3日で捨てていいけど、ログインとかのセキュリティ関係は監査に使うので1年保管、等です。

では`logs-system.auth`だけ保存期間を変えてみましょう。`logs`ポリシーを変えると他のログも全部変わってしまうので新しいポリシーを作る必要があります。この手順はこちらに記載があります。
https://www.elastic.co/guide/en/fleet/8.13/data-streams-ilm-tutorial.html

### 新しいILMポリシーの作成
ポリシーを作る時に、その情報をどう管理したいかを考えましょう。ポイントはその情報にどのぐらい頻繁にアクセスしてどう使いたいか？です。Hotに入っていれば一瞬で表示されますし、Frozenに入っていると少し時間がかかります。常に見ておきたい情報はその期間はHotに入れる、そうでなく監査目的で保存することが目的であればすぐにFrozenにいれる、などです。

今回はRolloverしてから、Hotに3日/Frozenに1年保管、としましょう。Stack Management -> Index Lifecycle PoliciesでCreate Policyをクリックします。
![Index-Lifecycle-Policies-Elastic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/6fad860d-bc08-6e67-a1f0-56ef5b32b561.png)

- Policy name
    - `3day-hot-1year-frozen`とでもしておきます。何でもよいです。
- Frozen
    - クリックして有効にします。
    - Move data into phase when:に3を入れます
    - Keep data in this phase foreverの横のゴミ箱マークをクリックしてDelete Phaseを追加します
- Delete
    - Move data into phase when:に365を入れます

Save Policyをクリックして保存します。

### Component Template作成
`3day-hot-1year-frozen`というポリシーを使うテンプレートを作成します。
Stack Management -> Index management -> Component TemplatesからCreate component templateをクリックします。
Nameに適当な名前を入れて(ここでは3day-hot-1year-frozen)、Nextをクリック
![スクリーンショット 2024-05-30 11.36.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/92629214-e3cd-f58c-c67e-a132b5bc3841.png)

Index settingsに下記の設定を貼り付けます。
```json
  "lifecycle": {
    "name": "3day-hot-1year-frozen"
  }
```
![スクリーンショット 2024-05-30 11.35.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/5cc9b7ae-2ed1-03a2-9786-f8ee61815c37.png)
後はNextを3回クリックして最後にcreate componentを押して作成を完了します。

### Index templateの作成
いちから作るのは面倒なので既存のものをクローンします。
Stack Management -> Index management -> Index Templatesから`logs-system.auth`をクリックして右下のManageからCloneを選びます。
![スクリーンショット 2024-05-30 11.43.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/f4919fdb-ec76-fa94-3c47-20a5ce576624.png)

Priorityを200より大きい値にします（ここでは300)
名前は勝手に`logs-system.auth-copy`となってますので、適宜変更してください（今回はそのままにしています）
![スクリーンショット 2024-05-31 16.56.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/b8e2a193-fa08-5863-ad05-c411c2f8ba4b.png)

Nextをクリックして、Component Template選択画面に行きます。
右側に`3day-hot-1year-frozen`があるので、**+**をクリックして追加します。
下にあるほどその設定が優先されます（上書きされる）。
`Preview index template`をクリックして正しく追加されていることを確認します。
![スクリーンショット 2024-06-03 9.59.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/2285c310-b248-fdde-54f7-6945e35063ba.png)
Nextを4回クリックして最後の画面でSave templatesで保存します。
保存すると適用されています。

### 確認
Stack Management -> Index management -> Data Streamで`logs-system.auth-default`を確認してみましょう。変わってますね。
![スクリーンショット 2024-06-03 10.15.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/29c6de85-8691-5d1a-a976-753204c67c5c.png)

### いつから適用されるか
ここで終わっても問題はないですが、実はこの作成したILMポリシーは現在書き込み中のインデックスには適用されません。
上記画像のIndicesの下の数字（ここでは**3**)をクリックしてみてください。
![スクリーンショット 2024-06-03 10.33.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/2a8e516f-15e1-3808-1321-5884f9012a5f.png)
一番下に今書き込んでいるインデックスが表示されます。ここでは`.ds-logs-system.auth-default-2024.01.31-000003`をクリックします。
![スクリーンショット 2024-06-03 10.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/0d3d7908-5278-599d-5213-355b87d6a42b.png)
**Index lifecycle**をクリックしてみると、まだ`logs`になっています。

これを変更するにはまず一回ILMポリシーを外します。
Manage Index -> Remove lifecycle policyとクリックします。
（本当に外していいか、と聞いてきますが、外しましょう）
![スクリーンショット 2024-06-03 10.37.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/137fb93c-8d24-5272-85d6-e2c233212585.png)

自動的に**Overview**に戻されます(Index lifecycleのタブがなくなっている)。再びManage IndexをクリックするとAdd lifecycle policyというメニューに変わっていますので、それをクリックします。
![スクリーンショット 2024-06-03 10.39.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/9db8db0c-aba1-46fc-53cb-c9730352ca67.png)

ILMポリシーを選ぶ画面が出てくるので`3day-hot-1year-frozen`を選びます。
![スクリーンショット 2024-06-03 10.42.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/7ae46ec1-5c4c-feed-4a1c-9a11cec20e63.png)

その後こんな感じでWarningが出ますが気にせず追加します。
![スクリーンショット 2024-06-03 10.42.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/f765a013-acfb-ae6d-c142-8151242dc8d2.png)

先程のページに戻りますが、少し表記が変わっています。
![スクリーンショット 2024-06-03 10.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/04499524-4281-e292-0c39-96749eceea19.png)

確かにILMポリシーは`3day-hot-1year-frozen`になってますね。
ただ見かけない言葉があります。`Current action`に`unfollow`とあります。ここは通常は`rollover`となっています。

こうなっている理由はILMポリシーをチェックする頻度にあります。実は10分に一回チェックをしているので、しばらく待ってみてください。最終的にはこうなります。
![スクリーンショット 2024-06-03 10.55.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/082ffe0e-6250-9b1d-d963-f5cda6fafa18.png)

チェックする周期である10分というのは変更することは可能です。
この変更はManagement -> Dev Toolsからのみ行えます。
以下のようにすると1分間隔でチェックします。
```
PUT _cluster/settings
{
  "persistent": {
    "indices.lifecycle.poll_interval": "1m" 
  }
}
```

# まとめ
ILMをうまく利用すればLogやメトリクスの保管コストを下げることができます。特にFrozenはうまく使えば驚異的にコストを下げられます。
ElasticはObservabilityにもセキュリティにも使えます。Observabilityで使っているところをILMをうまく使ってコスト削減頂いて、空いた部分でセキュリティを試す、など柔軟な使い方ができます。

Elasticsearchの豊富な機能を適切なコストでご利用いただける一助になれば幸いです。