Docker-composeを使ってEmbulk,Elasticsearch,Kibana環境を構築する

データ分析してたら、どうしても必要になるのがデータ分析基盤。
データ分析屋的には、データの加工とか、綺麗なレポートを作る時間とかに、あまり時間を割かず、なるべく分析に注力できる環境を構築したい。

ってことで、構築してみた。

※個人の忘備録用に書いた記事。３か月ぶりに書いた本人が読んでも意味不明だった時点でお察し

##構築環境
- Mac (macOS High Siera)
- Docker for mac [Version 18.06.0-ce-mac70 (26399)]

##構築するもの
- Embulk (ver 0.9.7)
- elasticsearch (ver 6.3.2)
- kibana (ver 6.3.2)

## Docker-compose

### 構成
詳細はhttps://github.com/k-ken-t4g/docker-compose-EEK を参照。

```
.
├── docker-compose.yml
├──embulk
│   └── Dockerfile-embulk
├── elasticsearch
│   └── nikkeiTemplate.json #nikkei225.csvのMapping Template設定
└── log
    ├── nikkei225.csv # elasticsearchに入れたいcsv
    ├── config.yml # embulkでnikkei225.csvを取り込むための設定
    └── seed.yml # config.ymlの自動生成元ファイル
```

### docker-compose.yml
以下のDocker-Hubに同名のイメージが存在するが、非推奨とのこと。過去のQiita記事だと以下のイメージを使っている場合もある。
- https://hub.docker.com/_/elasticsearch/
- https://hub.docker.com/_/kibana/

今回はElastic社のDockerレジストリ(https://www.docker.elastic.co) を使用している。

以下を参考にした
- [Dockerコンテナ間で双方向通信させる](https://qiita.com/skyis/items/c85f2f60f4f73045e6bd)
- [Install Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html)
- [Running Kibana on Docker](https://www.elastic.co/guide/en/kibana/current/docker.html)

```docker-compose.yml
version: '2'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
    expose:
      - 9200
    ports:
      - "9200:9200"
      - "9300:9300"
    tty: true
    environment:
      discovery.type: single-node

  kibana:
    image: docker.elastic.co/kibana/kibana:6.3.2
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200

  embulk:
    volumes:
      - ./log:/root/logs
    build:
      context : ./embulk
      dockerfile: Dockerfile-embulk
    tty: true
```

### Embulk
Embulkは公式Docker imageがないので、[EmbulkのDockerコンテナを作ってみる](https://qiita.com/reflet/items/beb67359d6796a0c8b78) を参考に構築。参考にした記事との違いは以下の３点。
 - `embulk-output-elasticsearch`プラグインを導入したこと
 - `digdag`を導入しようとした（途中面倒になったので、コメントアウト）
 - マウントするためのディレクトリを作成

```Dockerfile-embulk
FROM java:8

# system update
RUN apt-get -y update && apt-get -y upgrade && \
	apt-get install -y --no-install-recommends jruby
# locale（任意）
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8

# timezone (Asia/Tokyo)
ENV TZ JST-9

# etc
ENV TERM xterm

# tools
RUN apt-get install -y vim git zip unzip less wget

# embulk
RUN curl -o /usr/local/bin/embulk --create-dirs -L "http://dl.embulk.org/embulk-latest.jar" && \
    chmod +x /usr/local/bin/embulk

# Get Digdag and create new user "digdag"
#RUN curl -o /usr/local/bin/digdag --create-dirs -L "https://dl.digdag.io/digdag-latest" #&& \
#    chmod +x /usr/local/bin/digdag && \
#    apt-get clean && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* && \
#    adduser --shell /sbin/nologin --disabled-password --gecos "" digdag

#Get Embulk Plugins
RUN  embulk gem install embulk-output-elasticsearch

WORKDIR /root

RUN mkdir /root/logs
```

### ※追記（2019/07/17）
[最適な Java の Docker イメージを選びたい](https://k11i.biz/blog/2018/05/17/base-docker-images-for-java/)によると、

> 前は Docker Hub の java のリポジトリで提供されていましたが、このリポジトリは deprecated になっています。現在のリポジトリは openjdk です。

また[OpenJDKのDockerfile](https://github.com/docker-library/openjdk/blob/43078a246d7620f518412f458cc689ac869389ac/8/jre/slim/Dockerfile)を読むと、`apt-get`を実行するには`set -eux`を枕詞にする必要があるみたいです（理由はよく分かっていない）

なので、こういう感じになります。

```Dockerfile-embulk
FROM openjdk:8

##　省略

RUN set -eux; \
     apt-get -y update && apt-get -y upgrade ;\
     apt-get install -y --no-install-recommends jruby
```


## 起動
`docker-compose-EEK`のディレクトリに移動して`docker-compose`で起動するだけで、環境が立ち上がる。

```bash
$ docker-compose up --build
```

## 使い方

`log`フォルダにelasticsearchにプッシュしたいデータのcsvを置いて、`Embulk`のdockerコンテナから実行して使う[^1]。

### サンプルデータ

`k-ken-t4g/docker-compose-EEK/log/nikkei225.csv`は以下のpythonを実行して集めたものを使った。内容は日経平均株価、ダウ平均株価と円/ドル為替の2008年1月1日からのデータ。今(2018年11月現在)は`pandas_datareader.data`が使えないので、過去に自分が取ってきたものを使用[^2]

``` python
import datetime
import pandas_datareader.data as web

start = datetime.datetime(2008, 1, 1)
nikkei225 = web.DataReader(["NIKKEI225","DJIA","DEXJPUS"], "fred", start) 
nikkei225.to_csv("nikkei225.csv")
```

### Elasticsearch MappingTemplate設定
割と地味なつまずきポイント。今回は日ごとにインデックスを分けることもないので、適当に設定。

- [Elasticsearch Reference [6.x] » Mapping](https://www.elastic.co/guide/en/elasticsearch/reference/6.x/mapping.html)
- [Elasticsearch Reference [6.3] » Indices APIs » Index Templates](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html)
- [データ分析基盤構築入門［Fluentd，Elasticsearch，Kibanaによるログ収集と可視化］](http://gihyo.jp/book/2017/978-4-7741-9218-5)

```nikkeiTemplate.json
{
  "template": "nikkei225*",
  "mappings": {
    "nikkei_schema":{
      "properties": {
          "NIKKEI225": { "type": "double" },
          "DATE": {"format" : "YYYY-MM-dd", "type": "date" },
          "DJIA": { "type": "double" },
          "DEXJPUS": { "type": "double" }
      }
    }
  }
}
```

設定方法は`localhost:5601`(`kibana`) にアクセスして、 `DEVTOOLS` をクリック。`Console`で上記を入力。

### Embulkを使ってelasticsearchにデータをプッシュ
`Embulk`のコンテナの中に入って以下のコマンドを実行すれば、`nikkei225.csv`のデータが`elasticsearch`に格納される。

```
$ docker exec -it docker-compose-efk_embulk_1 bash
[root@5b7d05cac814:~# cd logs/
root@5b7d05cac814:~/logs# embulk run config.yml 
```

`config.yml`の設定で、出力先ノードのホストが`nodes: - {host : elasticsearch, port: 9200}`なのが地味にトラップだった。

```config.yml
in:
  type: file
  path_prefix: ./nikkei225.csv
  parser:
    charset: ISO-8859-2
    newline: LF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: DATE, type: timestamp, format: '%Y-%m-%d'}
    - {name: NIKKEI225, type: double}
    - {name: DJIA, type: double}
    - {name: DEXJPUS, type: double}
out:
  type: elasticsearch
  nodes:
  - {host : elasticsearch, port: 9200}
  index: nikkei225-test
  index_type: nikkei_schema
```

`config.yml`は一から作るのは大変なので、`embulk guess`コマンドを使って自動生成するのが楽な方法。

```
$ embulk guess seed.yml -o {任意のyamlファイル名}
```

### Kibanaでイケてるダッシュボード作る
ここまで書いて疲れてきたので、適当にググってイケてるダッシュボード作ってください。

## 課題
- 今の設定だと、いちいち`Embulk`のコンテナに入らないと`elasticsearch`にデータをpushできない
    - `digdag`とかで、データが更新されると勝手にpushする構成にしたい。
    - [docker-composeを使ってmysqlからbigqueryにデータを送る](https://cross-black777.hatenablog.com/entry/2017/04/08/203100)が参考になりそう。
- Embulkがfluetdみたいにデータを一箇所のサーバーに集約する機能があるか調べる(多分ある)
- `k8s`で構築したい
    - 現状、上の構成は1サーバーにしか使わないので、優先度は低め。

## github
https://github.com/k-ken-t4g/docker-compose-EEK に今回のプロジェクトを公開しています。
`git clone`して`docker-compose up -d`すれば環境が構築されるはず。


## 参考文献/サイト
- [データ分析基盤構築入門［Fluentd，Elasticsearch，Kibanaによるログ収集と可視化］](http://gihyo.jp/book/2017/978-4-7741-9218-5)
- [【Docker】FluentdとElasticsearchとKibanaの環境構築](https://qiita.com/narumi_/items/ec1c4cbbc65ec26b46f8)
- [【Embulk】使い方あれこれ](https://qiita.com/da-sugi/items/13d4ead19c86d783ebb4)
- [Embulk + Elasticsearch + kibana + OpenStreetMapでお手軽に地理情報を可視化](https://qiita.com/terukizm/items/46b531b7fcc7a5f6f436)


[^1]: 実用性を考えると、あまりよくない運用。マウント位置はサーバーによってデータが集積されているディレクトリに設定するのが吉

[^2]: `pandas_datareader.data`のバージョンを落とせば使えるとのこと