在Docker中搭建ElasticStack环境,用于将与“新冠疫情”相关的推文进行标签云处理的讨论
建立环境
$ cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)
已完成的标签云
弹性堆栈环境部署
安装Docker
这次我们使用Docker Compose来构建ElasticStack(ElasticSearch,Kibana,Logstash)环境,首先要安装Docker。关于Docker的安装步骤,请参考以下文章。
Docker安装步骤
安装 Docker Compose
完成安装Docker后,接着安装了Docker Compose。关于Docker Compose的安装步骤,也请参考下面的文章。
Docker Compose安装步骤
创建各种配置文件。
我创建了各种配置文件来使用Docker Compose启动ElasticStack。虽然只需要使用docker-compose.yml来快速启动,但考虑到未来的可扩展性,我设计了Dockerfile来进行构建,以便更容易进行插件安装等配置。说实话,有时候我觉得使用Docker Compose真的有点麻烦呢,哈哈。
此外,在创建各种设置文件时,我参考了以下官方文件。
-
- ElasticSearch公式の設定手順
-
- Kibana公式の設定手順
- Logstash公式の設定手順
目录结构
$ 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内存和2个核心CPU的低性能服务器上搭建环境,因此在启动ElasticSearch后不久,由于内存不足而出现错误。
ElasticSearch的默認JVM堆大小設置為1GB,建議設置為物理RAM的50%以下。同時建議將最小堆和最大堆設置為相同的值。
只要我尝试将JVM的堆内存设置为128m,就无法启动。经过调整后,这次我将其设置为256m。
在内存调优方面,我参考了以下官方文档。
公式文件:设置堆大小
同时,根据官方的推荐,为了防止ElasticSearch内存被交换,我们还添加了以下的配置。
- bootstrap.memory_lock=true
关于禁用掉期交换设置,我参考了以下官方文件。
公式文件:无效化利率互换
虽然已经采取了解决内存不足问题的措施,但由于服务器资源有限,存在容器崩溃的风险。为了保证即使容器崩溃也能重新启动,我们添加了以下设置。
restart: always
创建Docker数据卷
// Docker Volumeを作成
$ docker volume create elasticstack
elasticstack
// Docker Volumeが作成されていることを確認
$ docker volume ls
DRIVER VOLUME NAME
local elasticstack
创建Docker网络
// 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的图形界面来监控ElasticStack的功能。它是X-Pack功能中唯一可以免费使用的功能。然而,免费使用仅限于一个集群,所以需要注意。关于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进行任何更改,但由于错误地将jvm.options配置为挂载到容器中的路径,在docker-compose.yml中,因此配置了默认的设置文件。虽然说实话,这种配置方法并不是很优雅,但暂时我接受了它。
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
在 Docker 组合文件中,我意外地将 log4j2.properties 配置文件的路径设置为了挂载到容器中,尽管不需要对 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
目前,尽管同一进程中并没有执行多个流水线的情况,但考虑到未来的可拓展性,我们已经进行了多流水线的设置。
################################################################################
# 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中。
由於上述三個詞非常熱門,導致數據量變得過大,因此我們啟用了ignore_retweets的功能,以便忽略轉推。
弹性堆栈的启动
使用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 你好世界。
如果ElasticStack的启动成功,您可以从Kibana的GUI上的Index Management页面确认是否已创建以下索引。
创建可视化
直觉地操作屏幕,创建可视化,完成!