DockerでELKスタックを構築する(2021/02)

## はじめに

ELKスタックですね。
Beatsはまだ入れてませんので・・・Elasticスタックではないかなー。

以下の記事を参考にしてお勉強として構築してみました。

- [DockerでELK(Elasticsearch Logstash Kibana) を構築してみました](https://qiita.com/okcoder/items/00c60614b819edc0c0b8)

## 今回使ったもの

Dockerはインストールされている、という前提で実施しています。

|ミドルウェア |バージョン |確認URL |
|--------|--------|--------|
|[nginx](https://hub.docker.com/_/nginx) |1.19.7-alpine |http://localhost |
|[elasticsearch-oss](https://www.docker.elastic.co/r/elasticsearch/elasticsearch-oss) |7.10.1 |http://localhost:9200 |
|[logstash-oss](https://www.docker.elastic.co/r/logstash/logstash-oss) |7.10.1 |http://localhost:9200/_cat/count/access_log1 |
|[kibana-oss](https://www.docker.elastic.co/r/kibana/kibana-oss) |7.10.1 |http://localhost:5601 |

## 構築スタート

### 1.作業用フォルダを作成する

作業用フォルダを作成します。

```terminal
$ mkdir elkwork
$ cd elkwork
```

Dockerと共有するフォルダを作成します。

```terminal
$ sudo mkdir -p /data/elk
```

elkフォルダのオーナを変更します。
例ではuser:userとしていますが、私はmyname:staffとしました。（mynameのところは自分のユーザ名）[^1]

```terminal
$ sudo chown user:user data/elk
```

ここから、elkフォルダの配下に共有フォルダを作成していきます。

まず、elasticsearch用の共有フォルダを作成します。

```terminal
$ mkdir data/elk/elasticsearch
```

次に、logstash用の共有フォルダを作成します。

```terminal
$ mkdir -p data/elk/logstash/pipeline
```

最後にnginx用の共有フォルダを作成します。

```terminal
$ mkdir -p data/elk/log/nginx
```

### 2.nginxを起動する

nginxを起動します。
nginx用の共有フォルダを指定するところでエラーが出ましたが、対応済み。[^2]

```terminal
$ docker run -d --restart always -v /Users/myname/Downloads/elkwork/data/elk/log/nginx:/var/log/nginx -p 80:80 nginx:1.19.7-alpine
```

nginxが起動したことを確認します。

![20210225-1111.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/58a22a4b-ad91-232b-72e0-8aa4e09dd739.jpeg)

### 3.Elasticsearchを起動する

elasticsearchを起動します。

```terminal
$ docker run -d --restart always -v /Users/myname/Downloads/elkwork/data/elk/elasticsearch:/usr/share/elasticsearch/data -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node"  --name elasticsearch docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.1
```

elasticsearchが起動したことを確認します。
JSONが返却されればOKです。

```json
{
  "name" : "34db2f5a288c",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "RZ9UOc4TTv-28XD7Kw5Nqw",
  "version" : {
    "number" : "7.10.1",
    "build_flavor" : "oss",
    "build_type" : "docker",
    "build_hash" : "1c34507e66d7db1211f66f3513706fdf548736aa",
    "build_date" : "2020-12-05T01:00:33.671820Z",
    "build_snapshot" : false,
    "lucene_version" : "8.7.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
```

### 4.Logstashを起動する

logstashの設定ファイル(confファイル)を data/elk/logstash/pipeline 直下に作成します。

```conf:data/elk/logstash/pipeline/logstash.conf
input {
  file {
    path => "/var/log/nginx/access.log"
    start_position => beginning
  }
}

filter {
  grok {
    match => { "message" => ["%{IPORHOST:[nginx][access][remote_ip]} - %{DATA:[nginx][access][user_name]} \[%{HTTPDATE:[nginx][access][time]}\] \"%{WORD:[nginx][access][method]} %{DATA:[nginx][access][url]} HTTP/%{NUMBER:[nginx][access][http_version]}\" %{NUMBER:[nginx][access][response_code]} %{NUMBER:[nginx][access][body_sent][bytes]} \"%{DATA:[nginx][access][referrer]}\" \"%{DATA:[nginx][access][agent]}\""] }
    remove_field => "message"
  }
  mutate {
    add_field => { "read_timestamp" => "%{@timestamp}" }
  }
  date {
    match => [ "[nginx][access][time]", "dd/MM/YYYY:H:m:s Z" ]
    remove_field => "[nginx][access][time]"
  }
  useragent {
    source => "[nginx][access][agent]"
    target => "[nginx][access][user_agent]"
    remove_field => "[nginx][access][agent]"
  }
  geoip {
    source => "[nginx][access][remote_ip]"
    target => "[nginx][access][geoip]"
  }
}

output {
  elasticsearch {
    hosts => [ 'elasticsearch' ]
    index => "access_log1"
  }
}
```

logstashを起動します。

```terminal
$ docker run -d --restart always -v /Users/myname/Downloads/elkwork/data/elk/logstash/pipeline:/usr/share/logstash/pipeline -v /Users/myname/Downloads/elkwork/data/elk/log:/var/log --link elasticsearch:elasticsearch  --name logstash docker.elastic.co/logstash/logstash-oss:7.10.1
```

logstashが起動し、ログ転送されたことを確認します。
内容を見ると、ちゃんと転送されているかが非常にギモンですが・・・・。
見やすいように、整形しています。

```json
{
    "error":{
        "root_cause":[{
            "type":"index_not_found_exception",
            "reason":"no such index [access_log1]",
            "resource.type":"index_or_alias",
            "resource.id":"access_log1",
            "index_uuid":"_na_",
            "index":"access_log1"
        }],
        "type":"index_not_found_exception",
        "reason":"no such index [access_log1]",
        "resource.type":"index_or_alias",
        "resource.id":"access_log1",
        "index_uuid":"_na_",
        "index":"access_log1"
    },
    "status":404
}
```

### 5.Kibanaを起動する

kibanaを起動します。

```terminal
$ docker run -d --restart always -p 5601:5601 --link elasticsearch:elasticsearch -e ELASTICSEARCH_URL=http://elasticsearch:9200 --name kibana docker.elastic.co/kibana/kibana-oss:7.10.1
```

kibanaが起動したことを確認します。[^3]

![20210225-1210.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/5dda205e-8aa9-e30c-3dd8-9c861776ed94.jpeg)


### 6.起動したELKスタックが機能しているかを確認する

kibanaで、logstashからログが転送されていることを確認します。
左側のハンバーガーボタンから、**Dev Tool** を開きます。

![20210225-1216.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/cd20ea8d-7112-addc-039e-cc4f6acdfc31.jpeg)

Consoleに **GET /access_log1/_search?pretty=true** を入力します。

![20210225-1217.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/8b5f6151-fd6d-af0b-6c4c-b24637e7f1f9.jpeg)

入力したら、 **▶** をクリックします。

![20210225-1218.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/c3de5304-fe32-86fe-cc8c-aab4768c774a.jpeg)

右側に、**200 - OK** で、アクセスログが表示されたら、バッチリです。

## 色々確認

### 1.Status

http://localhost:5601/status で確認できます。

![20210302-1625.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/074b9caf-add2-86a9-dfdd-87ac007f1fcd.jpeg)


### 2.Index Patternを設定する

KibanaはElasticsearchインデックスを最初に作成する必要があるらしい。

"Create index pattern"を押して遷移します。

![20210302-1634.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/d3b0930b-bf98-05e7-1bc8-d50ecfab44e1.jpeg)

Index pattern nameのところに、ひとつ以上のElasticsearchインデックスの名前と一致するIndex Patternを指定する必要があります。
下の方に、"access_log1"が表示されているので、これをIndex Patternとして使用すれば良さそうです。

![20210302-1636.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/91965495-c140-2192-376f-2a7966a11d91.jpeg)

"access*"を指定すると、"Next step >"が有効化されました。
良さそうです。

![20210302-1640.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/ecc4238f-6f0d-a3f6-cc37-c27d0c72973b.jpeg)

タイムスタンプを含むインデックスフィールドを選択します。
Time fieldのプルダウンから選択します。
"@timestamp"を選択し、"Create index pattern"を押します。

![20210302-1645.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/70e82c2c-a798-788d-d03f-5d8a2da2a344.jpeg)

どうやら、ちゃんと登録できたようです。
Discoverに移動して、見てみることにします。

![20210302-1647.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/b8c91da0-87f2-d5e2-0ac0-8375e812c10d.jpeg)

時間の範囲を調整してあげると、ちゃんと見えました。
見たことある画面だw

![20210302-1649.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/38937274-f5cc-d318-7053-3a9df49a332b.jpeg)

## まとめ

コンテナって便利だな・・・。
あとは、これで色々お勉強してみます。
構築もお勉強だけど、ELKで何ができるかを考えてみるのもお勉強です。


[^1]: 私は、user:user 指定でエラーがでました。*chown: user: illegal group name* になったので、myname:staff としています。今のところ、これでエラーは出ていません。Macを利用しています。
[^2]: 元々 data/elk/log/nginx:/var/log/nginx を指定したのですが、そうすると *Error response from daemon* が返ってきてしまいました。フルパスを指定する必要があると理解したので、記載の通りフルパスを記載することでエラーを解消しています。参考→[docker runでhost osのディレクトリをマウントする際に注意すること](https://qiita.com/bananaumai/items/131c337a32b7a690a405)
[^3]: すぐにURLで確認に行くと、「まだだよ」って叱られます。コーヒーを一口飲んで、落ち着いてからアクセスしてください。