Edited at

Dockerで、DatabaseからElasticsearchにLogstashを使ってデータを流してみた

こんにちは。

Web・iOSエンジニアの三浦です。

今回は、DatabaseからElasticsearchへ、Logstashを使ってデータを流す処理をDocker上で実現してみました。

ちなみに今回説明するコードは、以下のgithubで公開しています。

https://github.com/takayuki-miura0203/docker-elastic-sample


準備


環境

Dockerが実行できる環境であれば大丈夫です。


実装してみる


Elasticsearch

Databaseからデータを移す先です。


Dockerfile

Dockerfileでは、公式のイメージを入れるだけです。


FROM docker.elastic.co/elasticsearch/elasticsearch:7.3.0


docker-compose.yml

テストのため、シングルノードで実行します。

elasticsearch:

build: ./elasticsearch
container_name: elasticsearch
environment:
discovery.type: single-node
ports:
- 9200:9200
- 9300:9300


Kibana

データの確認などをするため、Kibanaも入れます。


Dockerfile

こちらも、Dockerfileでは公式のイメージを入れるだけです。

FROM docker.elastic.co/kibana/kibana:7.3.0


docker-compose.yml

Kibanaに関しては、 docker-compose.yml でも特別なことはしません。

kibana:

build: ./kibana
container_name: kibana
ports:
- 5601:5601


MySQL

Elasticsearchへ移すデータを入れます。


Dockerfile

今回は初期データを入れたいため、MySQLが公式で提供しているサンプルデータである world.sql の入った initdb.d ディレクトリを、 /docker-entrypoint-initdb.d ディレクトリとしてコピーするようにします。

DockerのMySQLは、 /docker-entrypoint-initdb.d に入っているsqlファイルを起動時に実行してくれます。

FROM mysql:8.0.17

COPY ./initdb.d /docker-entrypoint-initdb.d

https://github.com/takayuki-miura0203/docker-elastic-sample/tree/master/mysql/initdb.d


docker-compose.yml

ROOTユーザのパスワードを適当に決め、TZも一応入れておきます。

mysql:

build: ./mysql
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: root
TZ: 'Asia/Tokyo'
ports:
- 3306:3306
- 33060:33060


Logstash

DatabaseからElasticsearchへデータを移すアプリケーションです。


Dockerfile

公式イメージの pull に加え、データを移す処理を書いた設定ファイルを内包する pipeline ディレクトリを所定のディレクトリにコピーします。

この際、PCが重くなる対策として、デフォルトで存在した設定ファイルは削除しておきます。

また今回はDBからデータを取得するため、必要となるJDBCライブラリ( mysql-connector-java-8.0.17.jar )も公式サイトからダウンロードしておき、イメージにコピーします。

なお、どうやらJDK11への対応の関係でJDBCがうまく動かないようなので、Logstashは最新版ではなく少し昔のものを使っています。

FROM docker.elastic.co/logstash/logstash:6.8.2

RUN rm -rf /usr/share/logstash/pipeline
COPY pipeline /usr/share/logstash/pipeline
COPY mysql-connector-java-8.0.17.jar /usr/share/logstash/mysql-connector-java-8.0.17.jar


pipeline

データを移す処理に関しては、今回はシンプルにDBの指定テーブルのデータをElasticsearchへ移すだけの処理を書きました。

なおElasticsearchのホストは、Dockerで名前を指定している elasticsearch です。

input {

jdbc {
jdbc_driver_library => "/usr/share/logstash/mysql-connector-java-8.0.17.jar"
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://mysql:3306/world"
jdbc_default_timezone => "Asia/Tokyo"
jdbc_user => "root"
jdbc_password => "root"
jdbc_default_timezone => "Asia/Tokyo"
statement => "SELECT * FROM city"
}
}

output {
elasticsearch {
hosts => ["elasticsearch"]
index => "city"
}
}

https://github.com/takayuki-miura0203/docker-elastic-sample/tree/master/logstash/pipeline


docker-compose.yml

docker-compose.yml では、特別なことは何もしません。

logstash:

build: ./logstash
container_name: logstash
ports:
- 5044:5044
- 9600:9600


実行!


コンテナ起動・実行

今回は実行も簡単にできるよう Makefile を作ってみました。

.PHONY: start

start:
docker-compose up --build

.PHONY: prune
prune:
docker system prune -a --volumes

以下からコンテナの起動・処理の実行ができます。

make start


結果を見てみる

Kibana上で、以下のようにデータが入っていることが確認できました!

{

"took" : 836,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4079,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "city",
"_type" : "_doc",
"_id" : "tB1NhmwB5V7ePKeX7Lgo",
"_score" : 1.0,
"_source" : {
"@version" : "1",
"countrycode" : "BRA",
"district" : "Rio de Janeiro",
"@timestamp" : "2019-08-12T14:48:57.725Z",
"name" : "Macaé",
"id" : 376,
"population" : 125597
}
},
{
"_index" : "city",
"_type" : "_doc",
"_id" : "tR1NhmwB5V7ePKeX7Lgp",
"_score" : 1.0,
"_source" : {
"@version" : "1",
"countrycode" : "BRA",
"district" : "Minas Gerais",
"@timestamp" : "2019-08-12T14:48:57.725Z",
"name" : "Teófilo Otoni",
"id" : 377,
"population" : 124489
}
},
{
"_index" : "city",
"_type" : "_doc",
"_id" : "th1NhmwB5V7ePKeX7Lgq",
"_score" : 1.0,
"_source" : {
"@version" : "1",
"countrycode" : "BRA",
"district" : "São Paulo",
"@timestamp" : "2019-08-12T14:48:57.725Z",
"name" : "Moji-Guaçu",
"id" : 378,
"population" : 123782
}
},
{
"_index" : "city",
"_type" : "_doc",
"_id" : "tx1NhmwB5V7ePKeX7Lgq",
"_score" : 1.0,
"_source" : {
"@version" : "1",
"countrycode" : "BRA",
"district" : "Tocantins",
"@timestamp" : "2019-08-12T14:48:57.725Z",
"name" : "Palmas",
"id" : 379,
"population" : 121919
}
},
{
"_index" : "city",
"_type" : "_doc",
"_id" : "uB1NhmwB5V7ePKeX7Lgq",
"_score" : 1.0,
"_source" : {
"@version" : "1",
"countrycode" : "BRA",
"district" : "São Paulo",
"@timestamp" : "2019-08-12T14:48:57.725Z",
"name" : "Pindamonhangaba",
"id" : 380,
"population" : 121904
}
}
]
}
}


さいごに

Elasticsearch、Kibana、MySQL、Databaseという、それだけ聞くとなかなかに実装が重そうな内容でしたが、やってみたら案外あっさりできました(typoに気づかず悩んだりはしましたが…w)。

Production用に作ったわけではないので色々と簡素ですが、これなら今後Dockerで色々と遊べそうです。

なおこれを動かすと処理の負荷が結構大きいので、PCが重くなったりなどは注意が必要です。


参考文献

以下のサイトを参考にさせていただきました。

ありがとうございました!

https://catalina1344.hatenablog.jp/entry/2019/01/20/170821

https://www.elastic.co/guide/en/elasticsearch/reference/7.3/docker.html#_pulling_the_image

https://www.elastic.co/guide/en/logstash/current/docker.html

https://www.elastic.co/guide/en/kibana/current/docker.html

https://qiita.com/sugikeitter/items/f3b2c57bf8bbdc47a8bc

https://qiita.com/shione/items/dfa956a47b6632d8b3b3

https://qiita.com/astrsk_hori/items/e3d6c237d68be1a6f548

https://budougumi0617.github.io/2018/05/20/create-instant-mysql-by-docker/

https://qiita.com/A-Kira/items/f401aea261693c395966

https://qiita.com/S-T/items/923cf689ee5f44525457

https://qiita.com/NagaokaKenichi/items/ae037963b33a85df33f5

https://github.com/dimMaryanto93/docker-logstash-input-jdbc-plugin-mysql