[03] EFK (Elasticsearch + Fluentd + Kibana) の構築 ... Dockerコンテナの立ち上げ(説明あり)


|本シリーズのトップページ|
|:--|
|https://qiita.com/robozushi10/items/68dc5f8c2df38f160fda|

# はじめに

職場[^1] で「CI/CD ログ」や「CLI および Webアプリログ」の収集と可視化の導入の話が出てきた.
また、自宅で K8s の学習をする中で Fluentd という単語が頻繁に出てきていた.

そこで自宅の Ubuntu 18.04 マシンで docker-compose を用いて、
下図・下表のような Elasticsearch + Fluentd + Kibana (EFK) 環境を構築して検証し、
これらソフトの知見を得ることにした.

本項では以下を記す.
・**docker-compose.yml を使って下図の立ち上げるための設定の詳細を挙げる**

なお、Proxy下でセットアップする場合は
[[04] EFK (Elasticsearch + Fluentd + Kibana) の構築 ... Dockerコンテナの立ち上げ(Proxyサーバ下)](https://qiita.com/robozushi10/items/cdbd7bc22ddf3d631e36) が参考になるかも知れない.

# 構成


## 図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/957f2884-bcf2-a8d1-379b-7a425c69c492.png)


## 表

| No | サービス | ホスト側ポート | コンテナ側ポート | 備考 |
|:--|:--|:--|:--|:--|
| 1 | Nginx | 21337 | 80 | 採用バージョン v1.20.0.<br/>Fluentd のテストのために導入しているだけである.<br/>本表 No 2 の Fluentd(24224) へログを配送する. |
| 2 | Fluentd | 24224 | 24224 | 採用バージョン v1.13.1.<br/>受信したログを本表  No 3 の Fluentd(34224)へ転送する. |
| 3 | Fluentd | 34224 | 34224 | 採用バージョン v1.13.1.<br/>受信したログを Elasticsearch へ書き込みする.|
| 4 | Elasticsearch | 29200 | 29200 | 採用バージョン v7.14.<br/>ログ格納のためのデータストア.<br/>日本語検索をするための analysis-kuromoji 導入あり. |
| 5 | Kibana | 29601 | 29601 | 採用バージョン v7.14.<br/>Elasticsearch の視覚化 |

## 留意次項

次の設定は職場環境を想定したためである.
>・Fluentd を 2つ配置していること
・Elasticsearch のコンテナ側ポートを 9200 以外にしていること.
・Kibana のコンテナ側ポートを 5601 以外にしていること.

　

# 手順

## 1. ファイル構成

コード全文を Git clone で取得する

```
 $ git clone -b Qiita-02 git@github.com:robozushi10/qiita-efk.git
```

```bash
$ cd qiita-efk.git
$ tree . --charset=c
.
|-- PV
|   |-- elasticsearch
|   |   `-- config
|   |       `-- elasticsearch.yml ... Elasticsearch の挙動パラメータ定義
|   |-- fluentd
|   |   |-- etc
|   |   |   `-- fluent.conf ......... Fluentd 24224ポートでの待ち受け定義
|   |   `-- log ..................... バッファログ出力先ディレクトリ
|   |-- fluentd2
|   |   |-- etc
|   |   |   `-- fluent.conf ......... Fluentd 34224ポートでの待ち受け定義
|   |   `-- log ..................... バッファログ出力先ディレクトリ
|   `-- kibana
|       `-- config
|           `-- kibana.yml .......... Kibana の挙動パラメータ定義
|-- README.md
|-- assets
|   |-- elasticsearch
|   |   `-- Dockerfile .............. 日本語検索のための analysis-kuromoji のインストールあり
|   |-- fluentd2
|   |   `-- Dockerfile .............. Elasticsearch プラグインのインストールあり
|   `-- nginx
|       `-- Dockerfile .............. jwilder/dockerize を使って Fluentd, Elasticsearch, Kibana の起動を待つ
|                                     K8s での ReadinessProbe の挙動に近いはず
`-- docker-compose.yml
```

## 2. 各ファイルの詳細

ファイル全文は以下から入手できる.　ここでは重要と思われる点についてのみ記す.

```bash
$ git clone -b Qiita-02 git@github.com:robozushi10/qiita-efk.git
```

### docker-compose.yml

留意点をコード内にコメントとして記した.

#### docker-compose.yml の Nginx について

```yaml
略
#   ⬇️ Nginx は Fluentd のテストのために導入しただけである
  nginx:
    image: nginx:1.20.0
    build: assets/nginx
    container_name: myfld_nginx
    ports:
      - "21337:80"
#   ⬇️ ログ出力先を fluentd にする
    logging:
      driver: "fluentd"
      options:
        fluentd-address: "localhost:24224"
        tag: "docker.{{.Name}}"
#   ⬇️ jwilder/dockerize コマンドを使って、0.5秒周期で最大2分間まで、
#      Fluentd, Elasticsearch, Kibana の起動を待つ.　HTTP 応答 200 なら起動完了とみなす.
#      なお、jwilder/dockerize は Dockerfile の中でインストールをしている.
    command: >
      dockerize -wait tcp://fluentd:24224 -wait tcp://fluentd2:34224 -wait tcp://kibana:29601 -wait tcp://elasticsearch:29200 -timeout 2m -wait-retry-interval 0.5s
      /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
    depends_on:
      - fluentd
      - elasticsearch
      - kibana
略
```

#### docker-compose.yml の Fluentd について

```yaml
  fluentd:
    image: fluent/fluentd:v1.13-1
    container_name: myfld_fluentd
    restart: always
    command: >
      /usr/bin/fluentd -c /fluentd/etc/fluent.conf -v
    ports:
      - "127.0.0.1:24224:24224"
      - "127.0.0.1:24224:24224/udp"
    volumes:
#   ⬇️ バッファリングしたデータファイルが保存される
      - ./PV/fluentd/log:/fluentd/log
#   ⬇️ fluent.conf の配置先である.
#      fluent.conf の中で 34224 への転送設定や転送周期、フィルタ条件などを定義している.
      - ./PV/fluentd/etc:/fluentd/etc
  fluentd2:
    image: fluent/fluentd:v1.13-1
    build: assets/fluentd2
    container_name: myfld_fluentd2
    restart: always
    command: >
      /usr/bin/fluentd -c /fluentd/etc/fluent.conf -v
    ports:
      - "127.0.0.1:34224:34224"
      - "127.0.0.1:34224:34224/udp"
    volumes:
      - ./PV/fluentd2/log:/fluentd/log
#   ⬇️ fluent.conf の配置先である.
#      fluent.conf の中で 34224 からのログ転送を許可している.
      - ./PV/fluentd2/etc:/fluentd/etc
```

#### docker-compose.yml の Elasticsearch について

```yaml
略
  elasticsearch:
    image: elasticsearch:7.14.0
    build: assets/elasticsearch
    container_name: myfld_elasticsearch_fluentd2
    ports:
#     ⬇️ コンテナ側ポートを 29200 にするためには、ここの定義を変えるだけでは不十分だった.
#        そのために、./PV/elasticsearch/config/elasticsearch.yml で 29200 を指定した.
      - "29200:29200"
    environment:
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
#     ⬇️ 公式手順では JVM パラメータは環境変数で設定できるようだが、当方の場合は切り替えできず.
#        docker-compose.yml の記載ミスの疑いが高いが、仕方なく設定ファイル elasticsearch.yml
#        を配置する方法にした.
      - ./PV/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
#     ⬇️ ローカルボリュームを使うと Java で Exception が生じてしまう. (2021/08 時点では理由不明)
#        外付け SSD でマウントしているからなのだろうか. 本記事とは全く別のコンテナでも同現象が起きた.
#     - ./PV/elasticsearch/data:/usr/share/elasticsearch/data
      - myfld_elasticsearch_fluentd2_vol:/usr/share/elasticsearch/data
#     - "./PV/elasticsearch/config/jvm.options.d:/usr/share/elasticsearch/config/jvm.options.d/"
    depends_on:
      - fluentd
      - fluentd2
略
volumes:
  myfld_elasticsearch_fluentd2_vol:
```

#### docker-compose.yml の Kibana について

```yaml
略
  kibana:
    image: kibana:7.14.0
    container_name: myfld_kibana_fluentd2
    ports:
#     ⬇️ コンテナ側ポートを 29601 にするためには、ここの定義を変えるだけでは不十分だった.
#        そのために、./PV/kibana/config/kibana.yml で 29601 を指定した.
      - "29601:29601"
#     ⬇️ 環境変数だと Kibana サーバのポート変更ができず.
#        そのためにホスト側から /usr/share/kibana/config/kibana.yml をマウントしている.
#   environment:
#     - ELASTICSEARCH_URL=http://elasticsearch:29200
    volumes:
      - ./PV/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
    depends_on:
      - fluentd
      - fluentd2
      - elasticsearch

```


### assets/elasticsearch/Dockerfile

```dockerfile
## FROM elasticsearch:7.14.0

## プロキシサーバを使う場合
# ENV http_proxy="http://proxy.co.jp:8080"  
# ENV https_proxy="http://proxy.co.jp:8080"

# ⬇️ 下記コマンドを使って日本語検索プラグイン analysis-kuromoji をインストールした.
RUN elasticsearch-plugin install analysis-kuromoji

```

### assets/fluentd2/Dockerfile

Fluentd の Elasticsearch プラグインをインストールする.

```dockerfile
FROM fluent/fluentd:v1.13-1

USER root

RUN gem install fluent-plugin-elasticsearch

```

### assets/nginx/Dockerfile

コンテナ起動確認ツールである jwilder/dockerize をインストールする

```dockerfile
FROM nginx:1.20.0-alpine

## プロキシサーバを使う場合
# ENV http_proxy="http://proxy.co.jp:8080"  
# ENV https_proxy="http://proxy.co.jp:8080"

ENV DOCKERIZE_VERSION v0.6.1
RUN apk add --no-cache openssl \
 && wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
 && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
 && rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz

```

### PV/elasticsearch/config/elasticsearch.yml

```yaml
## 公式ドキュメント: https://www.elastic.co/guide/en/elasticsearch/reference/7.14/important-settings.htm
## 参考記事: http://www.tech-joy.work/article/a20180527115811.html

## ⬇️ 今回は Elasticsearch コンテナは 1個なので single-node と記述する.
## [doc] https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-discovery-settings.html
discovery.type: "single-node"

## ⬇️ ヒープのみ使用しスワップは使わない.
##    Dockerでの運用だとどうなるのか不明だが、true としている人が多いので定義をしてみる.
##    swapoff -a を恒久設定しておく.
bootstrap.memory_lock: true 

## ⬇️ クラスタ名. 目的に応じたクラスタ名が良いとはある.
cluster.name: "docker-cluster"

## ⬇️ どの NIC から待ち受けするかを定義する. 0.0.0.0 の場合は全ての NIC となる. 
## [doc] https://www.elastic.co/guide/en/elasticsearch/reference/7.14/modules-network.html
network.host: 0.0.0.0

## ⬇️ HTTP Client との通信用ポート. 指定が無ければ 9200-9300 のポートを使う.
## [doc] https://www.elastic.co/guide/en/elasticsearch/reference/7.14/modules-network.html
http.port: 29200

## ⬇️ 「xpack.monitoring.enabled: true」は deprecated とある.
##     代わりに下記を使えば良いのだと思う.
## [doc] https://www.elastic.co/guide/en/elasticsearch/reference/current/monitoring-settings.html
xpack.monitoring.collection.enabled: true

## ⬇️ watcher は通知に関する設定である.
## [doc] https://www.elastic.co/guide/en/elasticsearch/reference/7.14/notification-settings.html
xpack.watcher.enabled: true

## ⬇️ インデックス削除のときに「*」による指定を認めない(true). 
## [doc] https://www.elastic.co/guide/en/elasticsearch/reference/7.14/index-management-settings.html
action.destructive_requires_name: true

```

### PV/fluentd/etc/fluent.conf

24224 ポートからの入力に対する挙動を定義する

```xml
## ⬇️ 24224 ポートからの入力を待ち受ける
<source>
  @type forward
  port 24224
</source>

## ⬇️ docker-compose.yml にてタグを定義していたはずである
<match docker.myfld_nginx> #.......... フィルタ条件のタグを「docker.myfld_nginx」に絞ってしまう
  @type forward
  buffer_type file #.................................... ファイルバッファにする
  buffer_path /fluentd/log/fluentd-nginx.*.buffer #..... バッファファイルの出力先
  flush_interval 1s #................................... 1秒ごとにバッファをフラッシュする
  <server>
    name aggregate2
    host fluentd2 #..................................... 転送先マシンの名前
    port 34224 #........................................ 転送先のポート
  </server>
</match>
```

### PV/fluentd2/etc/fluent.conf

34224 ポートからの入力を監視し、該当するタグであれば標準出力させる

```xml
<source>
  @type forward
  port 34224
</source>

<match docker.**>
  @type stdout
</match>

```


### PV/kibana/config/kibana.yml

docker-compose.yml にて環境変数を設定してみたが挙動変わらず.
そのために設定ファイルに直書きした.

```yaml
#
# ** THIS IS AN AUTO-GENERATED FILE **
#

# Default Kibana configuration for docker target
server.host: "0"
server.port: "29601"
server.shutdownTimeout: "5s"
elasticsearch.hosts: [ "http://elasticsearch:29200" ]

```

　

## 3. Dockerイメージビルドとコンテナ起動を行う

```bash
$ cd qiita-efk.git
$ docker-compose build --no-cache
$ docker-compose up -d
```

## 4. Kibana にアクセスする

上記 3 でのコンテナ起動が完了するまで (4分間ほど) 待機してから
次の URL にアクセスして Kibana の Dev Tools が起動していれば OK.

・`http://localhost:29601/app/dev_tools#/console`


## 5. Nginx のログが Fluentd 34224ポート に配送されていることを確認する

Fluentd の挙動確認になってしまうが、記しておく.

### 5-1. Fluentd 34224 ポートの標準出力を監視する

```bash
$ docker-compose -f logs fluentd2
```

### 5-2. WEB-UI から `http://localhost:21337` にアクセスする

上記 5-1 のコンソールに対して、Nginx のアクセスログが出力されていることを確認する。
　

以上

# 参考書籍およびサイト

|書籍|
|:---|
|[nginx実践入門](https://gihyo.jp/book/2016/978-4-7741-7866-0)|
|[「Docker/Kubernetes 実践コンテナ開発入門  山田 明憲」](https://gihyo.jp/book/2018/978-4-297-10033-9)|
|[データ分析基盤構築入門［Fluentd，Elasticsearch，Kibanaによるログ収集と可視化］](https://gihyo.jp/book/2017/978-4-7741-9218-5)|
|[検索だけじゃない Elasticsearch 入門+](https://booth.pm/ja/items/1031664)|


|URL|一言|
|:--|:---|
|https://qiita.com/sanyamarseille/items/1c4c31547502791ecac6||
|https://www.elastic.co/guide/en/elastic-stack-get-started/current/get-started-docker.html||
|https://qiita.com/suzuki_y/items/6365799485fa3973b916||
|https://qiita.com/sugikeitter/items/f3b2c57bf8bbdc47a8bc||
|https://github.com/sugikeitter/elasticsearch-kibana-docker/blob/master/docker-compose.yml||
|https://gitya107.hatenablog.com/entry/2018/06/15/170334||
|http://ittoo.jugem.jp/?eid=737||
|https://qiita.com/kaibadash@github/items/9cfb532696dc8711e408|日本語検索を可能にする|
|https://qiita.com/mserizawa/items/8335d39cacb87f12b678|日本語検索を可能にする|
|https://github.com/deviantony/docker-elk|ELK を構築するための docker-compose が公開されている|
|https://dev.classmethod.jp/articles/es-01/|index, document, type の説明が簡潔に RDMS に例えられていて良かった|
|http://www.tech-joy.work/article/a20180527115811.html|/etc/elasticsearch/elasticsearch.yml の記述例と説明あり|
|https://qiita.com/Esfahan/items/3c07bfbb57c7098e9531|3台に Elasticsearch を導入した場合の手順あり|
|https://stackoverflow.com/questions/52621299/date-is-not-appending-to-elasticsearch-index-name-while-using-td-agent|fluent.conf で %Y%m%d 展開できない問題の対策である|
|https://wyukawa.hatenablog.com/entry/2019/07/03/162511|Elasticsearch 7 からはタイプが無くなるので、fluent.conf での記述方法が記されている|

　


[^1]: オンプレ環境での組込み機器開発向け DevOps 業務