EFK (Elasticsearch + Fluentd + Kibana) を用いたELBアクセスログ解析基盤の作成

業務でEC2インスタンス上に短時間で作成する必要があったので、備忘録

AWSの構成図は一部省略しています。

## 構成

- t2.medium (vCPU: 2, Mem: 4GB, EBS: 30GB) x1

![YVlCypB.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258445/b30c5a8b-5245-c58e-b472-45fb551eea56.jpeg)


## 構築手順

### ELBのログ書き出し設定

サービス->EC2->ロードバランサー->対象のELB を選択  
説明タブの属性にあるアクセスログの設定からアクセスログを有効にし、出力間隔及びS3のバケットを指定する。

### Elasticsearch + Fluentd + Kibanaのインストール

#### Elasticsearch, Kibana

今回はAMIとしてAmazon Linux 2 (RHELベース) を選択したので、RPMリポジトリからインストールする。
<https://www.elastic.co/guide/en/elasticsearch/reference/current//rpm.html>  
<https://www.elastic.co/guide/en/kibana/current/rpm.html>

PGPキーのインポート

``` bash
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
```

`/etc/yum.repos.d/elasticsearch.repo` を作成し、以下を記述する。

```repo
[elasticsearch-7.x]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
```

同様に、 `/etc/yum.repos.d/kibana.repo` を作成し、以下を記述する。

```repo
[kibana-7.x]
name=Kibana repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
```

インストール

```bash
sudo yum install elasticsearch
sudo yum install kibana
```

#### Fluentd

<https://docs.fluentd.org/installation/install-by-rpm>

インストール前にファイルディスクリプタの上限数を上げ、ネットワークカーネルパラメータを調整する
<https://docs.fluentd.org/installation/before-install>

インストール

```bash
curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent3.sh | sh
```

### nginxのインストール

```bash
sudo amazon-linux-extras install nginx1.12
```

### EFK, nginxの設定

#### /etc/elasticsearch/elasticsearch.yml

```yml
bootstrap.memory_lock: true
network.host: 0.0.0.0
transport.host: localhost
transport.tcp.port: 9300
```

#### /etc/elasticsearch/jvm.options

```options
-Xms1g # インスタンスのメモリ容量の1/4程度を割り当てておく
-Xmx1g
```

#### /etc/td-agent/td-agent.conf

```conf
# ソースを指定する
# プラグインはfluent-plugin-elb-logを使用 (https://github.com/shinsaka/fluent-plugin-elb-log)
# sudo td-agent install fluent-plugin-elb-logでインストールする
<source>
  @type elb_log
  region ap-northeast-1
  access_key_id XXXXXXXXXXXXXXXXXXXX # AmazonS3ReadOnlyAccessをアタッチしたIAMユーザを作成しておく
  secret_access_key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  s3_bucketname log-elb-accesslogs-tkgl
  s3_prefix AWSLogs
  refresh_interval 300
  timestamp_file /tmp/elb_last_at.dat
  buf_file /tmp/fluentd-elblog.tmpfile
  tag tkgl
</source>
...
...
<match tkgl.**>
  @type elasticsearch
  type_name access_log
  host 0.0.0.0
  port 9200
  logstash_format true
  logstash_prefix tkgl
  include_tag_key true
  tag_key @log_name
  <buffer>
    @type file
    path /var/log/td-agent/buffer/elb_log.buf
    chunk_limit_size 256m
    flush_interval 30s
    flush_thread_count 2
    queued_chunk_limit_size 5
    total_limit_size 2g
  </buffer>
</match>
...
...
```

#### /etc/nginx/nginx.conf

```conf
user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile             on;
    client_max_body_size 300M;
    send_timeout         300s;
    keepalive_timeout    65;

    server {
        listen 80;
        server_name kibana;

        location / {
            proxy_pass http://localhost:5601;
            proxy_ignore_client_abort on;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            rewrite ^/(.*)$ /$1 break;
        }

        location /es/ {
                proxy_pass http://localhost:9200/;
        }
    }
}
```

### 起動

```bash
# 自動起動設定
sudo systemctl enable elasticsearch.service
sudo systemctl enable kibana.service
sudo systemctl enable td-agent.service
sudo systemctl enable nginx.service
# 起動
sudo systemctl start elasticsearch.service
sudo systemctl start kibana.service
sudo systemctl start td-agent.service
sudo systemctl start nginx.service
```

インストール、設定および起動が終わったら
<http://ec2-{ip-address}.ap-northeast-1.compute.amazonaws.com>
にアクセスする。

## 運用上の注意点

### fluentdのバッファ

`chunk_limit_size` , `flush_interval` を適切に設定しないとバッファーオーバーフローが発生するので注意する

参考

<https://docs.fluentd.org/configuration/buffer-section>

<http://clavier.hatenablog.com/entry/2019/02/17/191958>

```conf
<buffer>
  @type file
  path /var/log/td-agent/buffer/elb_log.buf
  chunk_limit_size 256m
  flush_interval 30s
  flush_thread_count 2
  queued_chunk_limit_size 5
  total_limit_size 2g
</buffer>
```

### logの定期削除

今回のようにストレージ容量が少ない場合は、td-agentのlogによってストレージが圧迫されるので、crontabで定期的に削除しておく

```crontab
50 3 * * * tmpwatch -m 24 -x /var/log/td-agent/buffer /var/log/td-agent
50 3 * * * sudo find /tmp -type f -print | xargs sudo rm
```

### インデックスのロールオーバー

index (日単位) はおおよそ250MB~2GBほどあるので、ロールオーバーの設定も忘れずに設定する。

<https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-rollover-index.html>