ELK是Elasticsearch、Logstash、Kibana的简称,这三者是核心套件,但并非全部。
  Elasticsearch是实时全文搜索和分析引擎,提供搜集、分析、存储数据三大功能;是一套开放REST和JAVA API等结构提供高效搜索功能,可扩展的分布式系统。它构建于Apache Lucene搜索引擎库之上。
  Logstash是一个用来搜集、分析、过滤日志的工具。它支持几乎任何类型的日志,包括系统日志、错误日志和自定义应用程序日志。它可以从许多来源接收日志,这些来源包括 syslog、消息传递(例如 RabbitMQ)和JMX,它能够以多种方式输出数据,包括电子邮件、websockets和Elasticsearch。
  Kibana是一个基于Web的图形界面,用于搜索、分析和可视化存储在 Elasticsearch指标中的日志数据。它利用Elasticsearch的REST接口来检索数据,不仅允许用户创建他们自己的数据的定制仪表板视图,还允许他们以特殊的方式查询和过滤数据。

ELK架构

  通常来说,只使用这三个组件就可以进行日志收集了,不过在企业实际生产中,需要用到ELK做集中日志收集的话,日志的产生量都是惊人的,所以通常情况下会需要缓存层来防止elasticsearch被压垮。架构如下图所示。(也可以通过filebeat来收集日志。)
ELK架构

ELK的部署

  需要注意的是,ELK的这三个组件版本要一致,否则可能会出现一些不必要的问题。我们这里选用最新版本7.5.1为例,演示主机均为ubuntu1804。

Elasticsearch

  我们这里用两台主机来搭建一个elasticsearch集群,一般来说因为他的选举机制,elasticsearch集群都是3、5、7奇数个,不过2台主机也可以使用,我们这里节约主机使用两台主机做演示,IP分别为192.168.32.41192.168.32.42

  官网下载链接为https://www.elastic.co/cn/downloads/elasticsearch
  我们这里选择deb安装包安装,也可以选用源码tar包自己解压安装。

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.5.1-amd64.deb

  这个版本的deb包是自带java环境(openjdk11)的,如果主机已经预制java环境,可以去官网下载no-java的版本,使用jdk8的时候有warning,说未来版本将不支持jdk8,建议使用jdk11及以上。

dpkg -i elasticsearch-7.5.1-amd64.deb

  elasticsearch的配置文件路径为/etc/elasticsearch/elasticsearch.yml,需要修改的不多,将集群主机IP设置好就可以了,如下所示

root@elasticsearch1:~# grep "^[a-Z]" /etc/elasticsearch/elasticsearch.yml
cluster.name: ELK-CLuster      #集群名称,名称相同即属于是同一个集群
node.name: node-1                 #本机在集群内的节点名称
path.data: /elasticsearch/data
path.logs: /elasticsearch/logs
bootstrap.memory_lock: true   #服务启动的时候锁定足够的内存, 防止数据写入swap
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: ["192.168.32.41","192.168.32.42"]
cluster.initial_master_nodes: ["node-1","node-2"]

  我这里是单独创建了一个日志路径和数据路径,方便管理,并修改属主赋予权限。

mkdir -p /elasticsearch/{data,logs}
chown -R elasticsearch:elasticsearch /elasticsearch

  除了在配置文件中设置bootstrap.memory_lock: true以外,还需要在启动配置文件中设置允许无限制使用内存,否则启动检查就会报错,导致服务起不来。

vim /usr/lib/systemd/system/elasticsearch.service
LimitMEMLOCK=infinity

  而且根据官方文档https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html,最大30G 以内的内存。
  在一般使用中,使用最大内存和最小内存都设置为2G就可以了。

vim /etc/elasticsearch/jvm.options
-Xms2g
-Xmx2g

  另一台主机也同样配置,记得修改node.name,之后就可以启动elasticsearch了。

systemctl enable --now elasticsearch

  在任意主机使用curl命令可以检查集群的健康状态。

curl -sXGET http://192.168.32.41:9200/_cluster/health?pretty=true

  获取到的是一个 json 格式的返回值,那就可以通过 python 对其中的信息进行分析,例如对 status 进行分析,如果等于 green(绿色)就是运行在正常,等于yellow(黄色)表示副本分片丢失, red(红色)表示主分片丢失。
  至此,elasticsearch服务的部署就算是完成了。

Logstash

  logstash也是一个基于java的插件式服务,很多功能都是依靠于插件来实现的,我们安装官方的安装包,大部分常用插件都是已经预置了,如果还有其他的功能需求,就需要去官网或者github下载插件了。这些之后再说,我们先去官网上将Logstash7.5.1安装包下载下来并部署上。

wget https://artifacts.elastic.co/downloads/logstash/logstash-7.5.1.deb

  logstash也同样需要java环境

apt update
apt install openjdk-8-jdk

  或者安装oracle的jdk,生产环境还是推荐使用oracle公司的jdk,更加稳定。然后安装logstash

dpkg -i logstash-7.5.1.deb

  对于logstash的配置也很少,不做修改也可以使用,不过我们这里同样还是修改一下数据目录和日志目录

root@logstash1:~# grep "^[a-Z]" /etc/logstash/logstash.yml
path.data: /logstash/data
path.logs: /logstash/logs

  修改属主

mkdir -p /logstash/{data,logs}
chown -R /logstash

  logstash的默认执行程序路径为/usr/share/logstash/bin/logstash,这其实也是一个shell脚本文件,脚本中调用java的类库。

root@logstash1:~# /usr/share/logstash/bin/logstash --help
Thread.exclusive is deprecated, use Thread::Mutex
WARNING: Could not find logstash.yml which is typically located in 
$LS_HOME/config or /etc/logstash. You can specify the path using --path.settings.
 Continuing using the defaults
Usage:
    bin/logstash [OPTIONS]

Options:
    -n, --node.name NAME          Specify the name of this logstash instance, 
                                  if no value is given
                                  it will default to the current hostname.
                                   (default: "logstash1")
    -f, --path.config CONFIG_PATH Load the logstash config from a specific file
                                  or directory.  If a directory is given, all
                                  files in that directory will be concatenated
                                  in lexicographical order and then parsed as a
                                  single config file. You can also specify
                                  wildcards (globs) and any matched files will
                                  be loaded in the order described above.
    -e, --config.string CONFIG_STRING Use the given string as the configuration
                                  data. Same syntax as the config file. If no
                                  input is specified, then the following is
                                  used as the default input:
                                  "input { stdin { type => stdin } }"
                                  and if no output is specified, then the
                                  following is used as the default output:
                                  "output { stdout { codec => rubydebug } }"
                                  If you wish to use both defaults, please use
                                  the empty string for the '-e' flag.
                                   (default: nil)

  不过常用的选项也就-e-f,分别是通过命令行指定参数或者通过文件来指定配置参数。我们可以使用命令来测试

/usr/share/logstash/bin/logstash -e 'input { stdin{} } output { stdout{ codec => rubydebug }}' 

输出日志
  通过标准输入输入信息,并通过标准输出返回日志信息。同样,我们也可以调用input的file插件和output的file插件实现从文件中读取数据,或者写入文件。这样就可以实现对日志文件的抓取了。我们可以先尝试抓取系统日志如syslog

/usr/share/logstash/bin/logstash -e 'input { file { path => "/var/log/syslog"} } output { stdout{ codec => rubydebug }}' 

  哈,系统日志如果太多,估计会刷屏的。
  不过刚才那些都只是一些基本用法而已,而实际生产中,我们肯定不能使用命令行来手动获取数据,我们需要的是一个可靠的服务,来帮我们自动抓取日志并筛选过滤,这就需要我们使用配置文件来设置了。
  例如我们要做的抓取本机的nginx的访问日志、错误日志还有系统日志,并传递至之前配好的elasticsearch中。
  那就在路径/etc/logstash/conf.d/目录下,创建一个新的配置文件,使用systemd启动时会自动读取conf.d下的配置文件。

vim /etc/logstash/conf.d/nginx.conf
input {
  file { 
    path => "/var/log/syslog"
    stat_interval => 3
    start_position => "beginning"
    type => "syslog"
  }
  file { 
    path => "/apps/nginx/logs/access_json.log"
    stat_interval => 3
    start_position => "beginning"
    codec => "json"
    type => "nginx_accesslog"
  }
  file { 
    path => "/apps/nginx/logs/error.log"
    stat_interval => 3
    start_position => "beginning"
    type => "nginx_errorlog"
  }
}

output {
  if [type] == "syslog" {
  elasticsearch {
    hosts => ["192.168.32.41:9200"]
    index => "syslog-%{+YYYY.MM.dd}"
  }}
  if [type] == "nginx_accesslog" {
  elasticsearch {
    hosts => ["192.168.32.41:9200"]
    index => "nginx_accesslog-%{+YYYY.MM.dd}
  }}
  if [type] == "nginx_errorlog" {
  elasticsearch {
    hosts => ["192.168.32.41:9200"]
    index => "nginx_accesslog-%{+YYYY.MM.dd}
  }}
}

  logstash支持条件判断,多输入以及多输出,设定type规则,来将每一类日志分类在不同的索引,且支持java的时间变量,可以实现根据日期归档每一天的日志,方便查看和统计。
  我们可以使用命令来测试脚本的语法是否正确,如果不加-t可以直接以前台进程的方式启动logstash,不过会占据终端,但测试的时候还是蛮方便的。

/usr/share/logstash/bin/logstash -f /etc/log/logstash/conf,d/nginx.conf -t

  不过仅仅是这样,是无法统计具体访问时间、访问ip及访问路径的详细信息的,我们需要将nginx的日志序列化,或者说是储存为json格式。
  所以修改nginx的配置文件,将日志格式修改一下。

http {

    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    log_format access_json '{"@timestamp":"$time_iso8601",'
        '"host":"$server_addr",'
        '"clientip":"$remote_addr",'
        '"size":$body_bytes_sent,'
        '"responsetime":$request_time,'
        '"upstreamtime":"$upstream_response_time",'
        '"upstreamhost":"$upstream_addr",'
        '"http_host":"$host",'
        '"uri":"$uri",'
        '"domain":"$host",'
        '"xff":"$http_x_forwarded_for",'
        '"referer":"$http_referer",'
        '"tcp_xff":"$proxy_protocol_addr",'
        '"http_user_agent":"$http_user_agent",'
        '"status":"$status"}';

    access_log  /apps/nginx/logs/access_json.log  access_json;

  PS:加入的属性名称不要有type,否则会影响到logstash做type判断。然后记得在配置文件中注明输入信息为json格式。看到如下信息,则说明日志被成功拆解。

{
    "http_user_agent" => "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
               "path" => "/apps/nginx/logs/access_json.log",
         "@timestamp" => 2020-01-03T08:17:47.000Z,
       "upstreamhost" => "-",
                "xff" => "-",
       "responsetime" => 0.0,
               "size" => 0,
             "status" => "304",
          "http_host" => "192.168.32.51",
           "clientip" => "192.168.32.1",
             "domain" => "192.168.32.51",
            "tcp_xff" => "",
               "host" => "192.168.32.51",
           "@version" => "1",
                "uri" => "/index.html",
            "referer" => "-",
       "upstreamtime" => "-"
}

  使用systemctl enable --now logstash启动logstash服务,过一会,日志就写入elasticsearch服务器中了,最好将/etc/systemd/system/logstash.service文件的中启动用户组都改为root,避免因为权限问题,导致无法读取数据。
  我记得之前遇到过一次,命令行可以正常使用logstash,不过使用systemd启动就一直报错,logstash: could not find java; set JAVA_HOME or ensure java is in PATH,明明环境变量都是正常的,后来在/usr/share/logstash/bin/logstash脚本文件中加了一个JAVA_HOME=/usr/local/jdk环境变量就好了,而之后配的时候就没有遇到这个问题了,这就很奇怪了。

Kibana

  日志信息都已经写到elasticsearch服务器中了,不过我们怎么才可以看到具体的日志信息呢?这就需要借助日志展示工具Kibana了。
  虽然elasticsearch可视化工具也有不少,例如head、kopf、cerebro等等,不过他们都是监控elasticsearch集群状态的,对日志做展示分析的还是首推开源的官方组件Kibana。
  同样下载kibana7.5.1版本

https://artifacts.elastic.co/downloads/kibana/kibana-7.5.1-amd64.deb

  配置上也很简单,设置监听IP及端口,设置elasticsearch主机地址,最后再将语言环境改为中文就可以启动kibana服务了。

root@kibana1:~# grep "^[a-Z]" /etc/kibana/kibana.yml
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://192.168.32.41:9200"]
i18n.locale: "zh-CN"

  浏览器访问kibana主机的5601端口。
  创建索引模式,依次添加索引。
kibana
  然后点左边第一个(最上面)的那个discover图标,就可以看到数据了。点击更改,选择对应的索引,还可以创建各种视图等一系列功能这里就不再详细讲解了。都比较简单。
  至此ELK的初步部署就算完成了。


一个低调的男人