構築環境
$ cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)
完成したタグクラウド
ElasticStack環境構築
Dockerインストール
今回はDocker Composeを利用して、ElasitcStack(ElasticSearch,Kibana,Logstash)環境を構築するため、まずはDockerをインストールした。Dockerのインストール手順に関しては、別途下記の記事で紹介しているため、こちらを参照ください。
Docker Composeインストール
Dockerのインストール完了後、続けてDocker Composeをインストールした。Docker Composeのインストール手順に関しても、別途下記の記事で紹介しているため、こちらを参照ください。
各種設定ファイルの作成
Docker ComposeでElasticStackを起動するために各種設定ファイルを作成した。docker-compose.ymlのみでさくっと起動してもよかったが、今後の拡張性を考えてDockerfileでビルドするように設計することで、プラグインのインストール等がしやすいように設定した。正直、Docker Compose使ってる意味・・・ってぐらいには、面倒なことしてるよね。笑
なお、各種設定ファイルの作成では、下記公式のドキュメントを参考にした。
ディレクトリの構成
$ tree --charset=C
.
|-- docker-compose.yml
|-- elasticsearch
| |-- config
| | `-- elasticsearch.yml
| `-- Dockerfile
|-- kibana
| |-- config
| | `-- kibana.yml
| `-- Dockerfile
`-- logstash
|-- config
| |-- jvm.options
| |-- log4j2.properties
| |-- logstash.yml
| |-- pipelines.yml
| `-- startup.options
|-- Dockerfile
`-- pipeline
`-- twitter_coronavirus.conf
各種設定ファイルの作成
Docker Compose 設定ファイルの作成
version: '3'
services:
elasticsearch:
build: ./elasticsearch/
container_name: elasticsearch
environment:
- node.name=elasticsearch
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
volumes:
- elasticstack:/usr/share/elasticsearch/data
ports:
- 9200:9200
- 9300:9300
networks:
- elasticstack
restart: always
kibana:
build: ./kibana/
container_name: kibana
volumes:
- ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
ports:
- 5601:5601
networks:
- elasticstack
restart: always
logstash:
build: ./logstash/
container_name: logstash
volumes:
- ./logstash/pipeline/:/usr/share/logstash/pipeline/
- ./logstash/config/:/usr/share/logstash/config/
networks:
- elasticstack
restart: always
volumes:
elasticstack:
external: true
networks:
elasticstack:
external: true
メモリ不足でES_JAVA_OPTSを設定した
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
メモリ1GB、CPU2コアの貧弱サーバで環境構築したため、ElasticSearchを起動した直後、メモリ不足でエラーになってしまった。
ElasticSearchのデフォルトJVMヒープは1GBに設定されており、物理RAMの50%以下に設定することが推奨されている。また、最小ヒープと最大ヒープはそれぞれ同一の値で設定することが推奨されている。
一旦、JVMのヒープメモリを128mで設定してみたが、起動できなかった。チューニングの結果、256mで今回は設定した。
メモリチューニングに関しては、以下の公式ドキュメントを参考にした。
公式ドキュメント:ヒープサイズの設定
また、ElasticSearchメモリがスワップされないように設定することを公式が推奨しているため、合わせて以下の設定を追加した。
- bootstrap.memory_lock=true
スワップ無効化の設定に関しては、以下の公式ドキュメントを参考にした。
公式ドキュメント:スワップの無効化
上記でメモリ不足の対策を実施したとはいえ、サーバリソースが限られており、コンテナダウンの恐れがあったため、コンテナが落ちても再起動するように、以下の設定を追加しておいた。
restart: always
Docker Volumeの作成
// Docker Volumeを作成
$ docker volume create elasticstack
elasticstack
// Docker Volumeが作成されていることを確認
$ docker volume ls
DRIVER VOLUME NAME
local elasticstack
Docker Networkの作成
// Docker Networkを作成
$ docker network create elasticstack
0150989c56b3d681bdf03a3377443a04af4e1e0c5e74d1e22154f9a486267fd6
// Docker Networkが作成されていることを確認
$ docker network ls elasticstack
NETWORK ID NAME DRIVER SCOPE
26ff84c0b3aa bridge bridge local
1d9f8f8c280a elasticstack bridge local
a83727599da4 host host local
0b0822de74c4 none null local
ElasticSearch 設定ファイルの作成
FROM docker.elastic.co/elasticsearch/elasticsearch:7.6.2
COPY ./config/elasticsearch.yml /usr/share/elasticsearch/config/elasticsearch.yml
# Install kuromoji plugin
RUN elasticsearch-plugin install analysis-kuromoji
日本語をより高度に解析するために、kuromojiプラグインをインストールする設定とした。これをインストールすることで、日本語の文字列であっても、しっかりと要素分解してくれるようになるため、このプラグインは適用することをおすすめする。
※ 公式ドキュメント:kuromojiプラグイン
network.host: 0.0.0.0
## x-pack settings
xpack.security.enabled: false
# Monitoring function is free for one cluster only.
xpack.monitoring.enabled: true
xpack.graph.enabled: false
xpack.watcher.enabled: false
ElasticSearchのデフォルト設定では、ループバックアドレス(127.0.0.1)のみにバインドしている。単一ノードで構成する場合は、この設定で問題ないのだが・・・今回はDockerのコンテナ上で動作させているため、ループバックアドレスはElasticSearchのコンテナ自身を示してしまう。つまり、KibanaコンテナやLogstashコンテナとの通信が行えなくなってしまう。そこで、全ての通信を受け入れるために、「network.host: 0.0.0.0」を設定した。
※ 公式ドキュメント:network.host
X-PackはElastic社が提供する有償のプラグインであるが、Monitoringだけは無償で提供しているとのことで、設定を有効にしてみた。MonitoringはKibanaのGUIからElasticStackの監視を行うことができる機能である。X-Packの機能の中で唯一無償で利用することができる機能である。ただし、無償利用は1クラスタまでに限るので注意が必要だ。X-PACKについては、ここでは深く触れないので詳しくは調べてみてください。...というか金無くて、触れれない。笑
Kibana 設定ファイルの作成
FROM docker.elastic.co/kibana/kibana:7.6.2
server.name: kibana
server.host: "0"
elasticsearch.hosts: http://elasticsearch:9200
Kibanaのデフォルト設定では、バックエンドサーバの設定がlocalhostになっている。単一ノードで構成する場合は、この設定で問題ないのだが・・・今回はDockerのコンテナ上で動作させているため、バックエンドサーバの指定がコンテナ自信を示してしまう。そこで、外部からの通信を受け付けるために、「server.host: "0"」を設定した。
※ 公式ドキュメント:server.host
Logstash 設定ファイルの作成
FROM docker.elastic.co/logstash/logstash:7.6.2
## JVM configuration
# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space
-Xms1g
-Xmx1g
################################################################
## Expert settings
################################################################
##
## All settings below this section are considered
## expert settings. Don't tamper with them unless
## you understand what you are doing
##
################################################################
## GC configuration
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
## Locale
# Set the locale language
#-Duser.language=en
# Set the locale country
#-Duser.country=US
# Set the locale variant, if any
#-Duser.variant=
## basic
# set the I/O temp directory
#-Djava.io.tmpdir=$HOME
# set to headless, just in case
-Djava.awt.headless=true
# ensure UTF-8 encoding by default (e.g. filenames)
-Dfile.encoding=UTF-8
# use our provided JNA always versus the system one
#-Djna.nosys=true
# Turn on JRuby invokedynamic
-Djruby.compile.invokedynamic=true
# Force Compilation
-Djruby.jit.threshold=0
# Make sure joni regexp interruptability is enabled
-Djruby.regexp.interruptible=true
## heap dumps
# generate a heap dump when an allocation from the Java heap fails
# heap dumps are created in the working directory of the JVM
-XX:+HeapDumpOnOutOfMemoryError
# specify an alternative path for heap dumps
# ensure the directory exists and has sufficient space
#-XX:HeapDumpPath=${LOGSTASH_HOME}/heapdump.hprof
## GC logging
#-XX:+PrintGCDetails
#-XX:+PrintGCTimeStamps
#-XX:+PrintGCDateStamps
#-XX:+PrintClassHistogram
#-XX:+PrintTenuringDistribution
#-XX:+PrintGCApplicationStoppedTime
# log GC status to a file with time stamps
# ensure the directory exists
#-Xloggc:${LS_GC_LOG_FILE}
# Entropy source for randomness
-Djava.security.egd=file:/dev/urandom
# Copy the logging context from parent threads to children
-Dlog4j2.isThreadContextMapInheritable=true
jvm.optionsの設定は何も変更する必要はなかったが、docker-compose.ymlでjvm.optionsを配置するパスをコンテナにマウントする設定にしてしまったため、デフォルトの設定ファイルを配置している。正直かっこいい設定方法じゃなかったが、一旦許容した。
status = error
name = LogstashPropertiesConfig
appender.console.type = Console
appender.console.name = plain_console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n
appender.json_console.type = Console
appender.json_console.name = json_console
appender.json_console.layout.type = JSONLayout
appender.json_console.layout.compact = true
appender.json_console.layout.eventEol = true
rootLogger.level = ${sys:ls.log.level}
rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console
log4j2.propertiesの設定は何も変更する必要はなかったが、docker-compose.ymlでlog4j2.propertiesを配置するパスをコンテナにマウントする設定にしてしまったため、デフォルトの設定ファイルを配置している。正直かっこいい設定方法じゃなかったが、一旦許容した。
http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]
- pipeline.id: coronavirus
path.config: "/usr/share/logstash/pipeline/twitter_coronavirus.conf"
queue.type: persisted
現時点では、同一プロセスで複数のパイプラインを実行することはないが、今後の拡張性を考えてマルチパイプライン設定をしておいた。
※ 公式ドキュメントMultiple Pipelines
################################################################################
# These settings are ONLY used by $LS_HOME/bin/system-install to create a custom
# startup script for Logstash and is not used by Logstash itself. It should
# automagically use the init system (systemd, upstart, sysv, etc.) that your
# Linux distribution uses.
#
# After changing anything here, you need to re-run $LS_HOME/bin/system-install
# as root to push the changes to the init script.
################################################################################
# Override Java location
#JAVACMD=/usr/bin/java
# Set a home directory
LS_HOME=/usr/share/logstash
# logstash settings directory, the path which contains logstash.yml
LS_SETTINGS_DIR=/etc/logstash
# Arguments to pass to logstash
LS_OPTS="--path.settings ${LS_SETTINGS_DIR}"
# Arguments to pass to java
LS_JAVA_OPTS=""
# pidfiles aren't used the same way for upstart and systemd; this is for sysv users.
LS_PIDFILE=/var/run/logstash.pid
# user and group id to be invoked as
LS_USER=logstash
LS_GROUP=logstash
# Enable GC logging by uncommenting the appropriate lines in the GC logging
# section in jvm.options
LS_GC_LOG_FILE=/var/log/logstash/gc.log
# Open file limit
LS_OPEN_FILES=16384
# Nice level
LS_NICE=19
# Change these to have the init script named and described differently
# This is useful when running multiple instances of Logstash on the same
# physical box or vm
SERVICE_NAME="logstash"
SERVICE_DESCRIPTION="logstash"
# If you need to run a command or script before launching Logstash, put it
# between the lines beginning with `read` and `EOM`, and uncomment those lines.
###
## read -r -d '' PRESTART << EOM
## EOM
startup.optionsの設定は何も変更する必要はなかったが、docker-compose.ymlでstartup.optionsを配置するパスをコンテナにマウントする設定にしてしまったため、デフォルトの設定ファイルを配置している。正直かっこいい設定方法じゃなかったが、一旦許容した。
input {
twitter {
consumer_key => "Your Twitter App’s consumer key."
consumer_secret => "Your Twitter App’s consumer secret."
oauth_token => "Your oauth token."
oauth_token_secret => "Your oauth token secret."
keywords => ["コロナ","自粛","緊急事態宣言"]
ignore_retweets => true
full_tweet => true
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200/"]
index => "twitter_coronavirus"
}
}
TwitterAPIを使用して、「コロナ」「自粛」「緊急事態宣言」のワードで検索されたツイートを取得し、最終的にElasticSearchへ出力されるように設定した。
上記3ワードがホット過ぎて、データ量が膨大になり過ぎたため、ignore_retweetsを有効にすることで、リツイートを無視するように設定した。
ElasticStackの起動
Docker Composeによって、ElasticSearch,Kibana,Logstashのコンテナを起動する。
$ docker-compose up -d
Starting elasticsearch ... done
Starting logstash ... done
Starting kibana ... done
コンテナの起動に成功したことを念のため確認してみる。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f58541a00bb elasticstack_elasticsearch "/usr/local/bin/dock…" About a minute ago Up 59 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
c4a64c7c5bee elasticstack_logstash "/usr/local/bin/dock…" About a minute ago Up 59 seconds 5044/tcp, 9600/tcp logstash
1df52608efec elasticstack_kibana "/usr/local/bin/dumb…" About a minute ago Up 59 seconds 0.0.0.0:5601->5601/tcp kibana
コンテナの起動に成功しているため、今度は各種サービスの動作を確認してみる。
ElasticSearchの動作確認
HTTP レスポンスステータスコードが200で返却されているし、構成詳細もしっかりと出力されているから問題なさそうだ。
$ curl -v localhost:9200
* Rebuilt URL to: localhost:9200/
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9200 (#0)
> GET / HTTP/1.1
> Host: localhost:9200
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json; charset=UTF-8
< content-length: 549
<
{
"name" : "elasticsearch",
"cluster_name" : "elasticsearch-cluster",
"cluster_uuid" : "0p2uJ5q3TQay0HkcI6I9kw",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
* Connection #0 to host localhost left intact
Kibanaの動作確認
http://localhost:5601/ にアクセスして、しっかりとKibanaのホーム画面が表示されたから問題なさそうだ。
Logstashの動作確認
以下の手順でHello Worldすることができるが・・・今回はLogstashからElasticSearchにインデックスが取り込まれていることが確認できてしまったので、動作確認をスキップしてしまった。しっかりと動作確認したい方はこちらを参照ください。
公式手順:Logstash Hello World
今回の場合、しっかりとElasticStackの起動に成功していれば、KibanaのGUI上のIndex Management画面から下記のようにインデックスが作成されていることが確認できる。
Visualizationsの作成
あとは直感的に画面を操作してVisualizationsを作成して、完成!!