在Docker中搭建ElasticStack环境,用于将与“新冠疫情”相关的推文进行标签云处理的讨论

建立环境

$ cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

已完成的标签云

TagCloud.png

弹性堆栈环境部署

安装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的主页正常显示,所以看起来没有问题。

kibanaTop.png

对Logstash的操作进行验证

尽管可以按照以下步骤来进行Hello World…但是这次我已经确认从Logstash到ElasticSearch的索引已经被导入,因此跳过了操作确认。如果您想要进行确认操作,请参考这里。

公式步骤:Logstash 你好世界。

如果ElasticStack的启动成功,您可以从Kibana的GUI上的Index Management页面确认是否已创建以下索引。

IndexManagement.png

创建可视化

直觉地操作屏幕,创建可视化,完成!

TagCloud.png
广告
将在 10 秒后关闭
bannerAds