Elastic Stack を Docker で構築し IIS ログを分析する

## はじめに

[Elasticsearch アドベントカレンダー（2020年）](https://qiita.com/advent-calendar/2020/elasticsearch)の23日目の記事です。
IIS ログをエクセルに張り付けてピボットテーブルを作成しピボットグラフにする~~原始的な~~作業をもうやりたくないので Elastic Stack を構築してみたところ簡単に分析出来るようになったので記事に起こしました。

## 目次

- [各ソフトウェア概要](#各ソフトウェア概要)
- [処理フロー](#処理フロー)
- [Docker Compose で Elastic Stack を構築する](#docker-compose-で-elastic-stack-を構築する)
  - [構成](#構成)
  - [docker-compose.yml](#docker-composeyml)
  - [.env](#env)
  - [logstash.conf](#logstashconf)
  - [filebeat.yml](#filebeatyml)
  - [IIS ログファイルを置く](#iis-ログファイルを置く)
- [Kibana で可視化する](#kibana-で可視化する)
  - [Elasticsearch の Index 確認](#elasticsearch-の-index-確認)
  - [Kibana の Index Pattern 作成](#kibana-の-index-pattern-作成)
  - [グラフ作成](#グラフ作成)
  - [ダッシュボード作成](#ダッシュボード作成)


## 各ソフトウェア概要

![elkb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/d56d96cd-fe60-1af7-7a3b-04b6efe95778.png)

- Elastic Stack は Elasticsearch，Kibana，Beats，Logstash からなるプロダクト群の総称です。
- Beats はデータシッパーと呼ばれ，データ転送ツールとして用いられます。
  - 自動でファイルの更新を検知し差分を転送してくれます。
  - 今回は Filebeats を使用します。
- Logstash はデータ処理パイプラインと呼ばれ，データを取り込み，変換し Elasticsearch に格納することが出来ます。
- Elasticsearch は言わずと知れた全文検索エンジンです。データ投入時に内部で転置インデックスを作成することで大量のドキュメントを高速に検索出来るようにしてます。
- Kibana は Elasticsearch のデータを可視化するツールとして用いられます。


## 処理フロー

- 処理フローは [Filebeat -> Logstash -> Elasticsearch -> Kibana]
- Filebeat で IIS ログを監視し，更新を検知したら Logstash に転送します。
- Logstash で json に変換し，Elasticsearch に投入します。
- Kibana で Elasticsearch のデータを可視化します。

## Docker Compose で Elastic Stack を構築する

Docker Compose で構築します。　　
docker-compose.yml があるディレクトリで docker-compose up -d でコンテナを起動します。

```
> docker-compose up -d
```

### 構成

- ./filebeat/log に IIS ログを格納します。
  - コンテナが起動していれば自動で Elasticsearch に投入されます。

```
.
├─docker-compose.yml
├─.env
├─elasticsearch
│  └─data
├─filebeat
│  ├─conf
│  │  └─filebeat.yml
│  └─log
│      └─u_exyyyymmdd.log
└─logstash
    └─pipeline
        └─logstash.conf
```

### docker-compose.yml

- Elasticsearch，Kibana，Logstash，Filebeat を構築します。
- Elasticsearch はシングルノードで構築します。
- Elasticsearch のデータを保持できるようボリュームをローカルにマウントします。
  - Kibana で作成したグラフやダッシュボードもここに格納されます。
- Logstash ではローカルの設定ファイルを読み込みます。
- Filebeat ではローカルの設定ファイルを読みこみます。
- Filebeat でローカルのログを参照できるようにボリュームをマウントします。
- Filebeat で Docker のソケットを参照するらしいのでマウントします。

```yml
version: "3"

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
    environment:
      - discovery.type=single-node
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms4096m -Xmx4096m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - 9200:9200
    volumes:
      - ./elasticsearch/data:/usr/share/elasticsearch/data
  kibana:
    image: docker.elastic.co/kibana/kibana:7.2.0
    ports:
      - 5601:5601
  logstash:
    image: docker.elastic.co/logstash/logstash:7.2.0
    ports:
      - 5044:5044
    environment:
      - "LS_JAVA_OPTS=-Xms4096m -Xmx4096m"
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
  filebeat:
    image: docker.elastic.co/beats/filebeat:7.2.0
    volumes:
      - ./filebeat/conf/filebeat.yml:/usr/share/filebeat/filebeat.yml
      - ./filebeat/log:/usr/share/filebeat/log
      - /var/run/docker.sock:/var/run/docker.sock
    user: root
```


### .env

Docker for Windows で /var/run/docker.sock をマウント出来るようにします。

```env
COMPOSE_CONVERT_WINDOWS_PATHS=1
```


### logstash.conf

- Filebeat からの転送を受け付けるように input を設定します。
- IIS ログを加工します。
- Elasticsearch に投入出来るよう output を設定します。

```conf
input {
# input from Filebeat
  beats {
    port => 5044
  }
}

filter {
  dissect {
  # log format is TSV
    mapping => {
      "message" => "%{ts} %{+ts} %{s-ip} %{cs-method} %{cs-uri-stem} %{cs-uri-query} %{s-port} %{cs-username} %{c-ip} %{cs(User-Agent)} %{cs(Referer)} %{sc-status} %{sc-substatus} %{sc-win32-status} %{time-taken}"
    }
  }
  date {
    match => ["ts", "YYYY-MM-dd HH:mm:ss"]
    timezone => "UTC"
  }
  ruby {
    code => "event.set('[@metadata][local_time]',event.get('[@timestamp]').time.localtime.strftime('%Y-%m-%d'))"
  }
  mutate {
    convert => { 
      "sc-bytes" => "integer"
      "cs-bytes" => "integer"
      "time-taken" => "integer"
    }
    remove_field => "message"
  }
}

output {
  elasticsearch { 
    hosts    => [ 'elasticsearch' ]
    index => "iislog-%{[@metadata][local_time]}" 
  }
}
```


### filebeat.yml

- /usr/share/filebeat/log を参照するように input を設定します。
  - 実際は ./filebeat/log を /usr/share/filebeat/log にマウントしているので ./filebeat/log に IIS ログを格納すれば Filebeat が自動で参照します。
- Logstash に転送するよう output を設定します。

```yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /usr/share/filebeat/log/*.log
  exclude_lines: ['^#','HealthChecker']
  
output.logstash:
  hosts: ["logstash:5044"]
```

### IIS ログファイルを置く

IIS ログファイルを ./filebeat/log に置くと Filebeat がそれを検知し Logstash に送信します。  
送信されたデータは Logstash で加工され，Elasticsearch に投入されます。  

## Kibana で可視化する

### Elasticsearch の Index 確認

http://localhost:5601 にアクセスします。  

![00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/718374a9-6823-fd76-d204-3b287da040a9.png)


歯車アイコンをクリックし，Elasticsearch/Index Management をクリックします。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/20821e2d-8bab-fb88-89bb-7f055fe2ecdb.png)



IIS ログの Index が作成されていることを確認します。

### Kibana の Index Pattern 作成

Kibana/Index Patterns をクリックし，Create Index pattern をクリックします。  

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/48802d71-842c-4ad5-6141-9d761c280641.png)

Index pattern を入力し Next step をクリックします。

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/e2d0f3f8-1328-65e3-38c2-31de2a95fe4b.png)



Time Filter field name で @timestamp を選択し Create index pattern をクリックします。  

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/e3ae64ae-888b-5df9-1d66-5c87c59dff8f.png)

ここで作成した Index pattern を選択しグラフを作成していきます。

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/723fb7ec-233c-1a94-a17c-fb41570a363d.png)

### グラフ作成

![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/3887fa7f-02fd-a936-9e99-343d0d09fad5.png)


先ほど作成した Index pattern を指定します。

![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/55051afc-88d0-027f-95a4-06b3c4527ee1.png)



右上の表示期間を絞り込みます。

![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/288580c7-f606-6bf5-9be9-da5f994a3826.png)



X 軸を指定します。  
Aggregation を Date Histogram，Field を @timestamp，Minimum interval を Minute とし，▷をクリックします。  

![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/2249e270-8c14-ef4c-4a3e-7c7ec2c8fe27.png)



これで分間のリクエスト数がグラフに表示されました。  
機能ごとの分間リクエスト数を表示するには Add filter をクリックし，Field（フィルターをかけたい項目），Operator（演算子），Value（値） を指定します。  

![_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/f03fc45e-a103-088d-8441-08ba3de8a7c0.png)


![_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/4267724a-fdb5-f023-625d-2219a5c9a30b.png)


### ダッシュボード作成

作成したグラフをダッシュボードに並べることが出来ます。

![_kibana_dashboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246211/b52583a7-1acf-ca29-95c7-c778b662a746.png)