2019你该掌握的开源日志管理平台ELK STACK

 

转载于https://www.vtlab.io/?p=217

企业级开源日志管理平台ELK VS GRAYLOG一文中,我简单阐述了日志管理平台对技术人员的重要性,并把ELK Stack和Graylog进行了标记。本篇作为“企业级开源日志管理平台”的延伸,基于我在生产环境中的使用经验,向读者介绍ELK Stack的安装与配置。不足之处,还望指正。

架构

Beats工具收集各节的日志,以list数据结构存储在Redis中,Logstash从Redis消费这些数据并在条件匹配及规则过滤后,输出到Elasticsearch,最终通过kibana展示给用户。
architecture

环境介绍

Elastic Stack的产品被设计成需要一起使用,并且版本同步发布,以简化安装和升级过程。本次安装,采用最新的6.5通用版。完整堆栈包括:
1. Beats 6.5
2. Elasticsearch 6.5
3. Elasticsearch Hadoop 6.5(不在本次介绍范围)
4. Kibana 6.5
5. Logstash 6.5
操作系统CentOS7.5,JDK需要8及以上版本。
官方介绍的安装途径包括:tar包安装、rpm包安装、docker安装、yum仓库安装,我使用RPM包安装。

系统设置

Elasticsearch默认监听127.0.0.1,这显然无法跨主机交互。当我们对网络相关配置进行修改后,Elasticsearch由开发模式切换为生产模式,会在启动时进行一系列安全检查,以防出现配置不当导致的问题。
这些检查主要包括:
1. max_map_count:Elasticsearch默认使用混合的NioFs( 注:非阻塞文件系统)和MMapFs( 注:内存映射文件系统)存储索引。请确保你配置的最大映射数量,以便有足够的虚拟内存可用于mmapped文件。此值设置不当,启动Elasticsearch时日志会输出以下错误:
[1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

解决方法:

# vim /etc/sysctl.conf
vm.max_map_count=262144
# sysctl -p
Shell
  1. 修改最大文件描述符
# vim /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
Shell
  1. 修改最大线程数
# vim /etc/security/limits.conf
* soft nproc 4096
* hard nproc 4096
Shell

注意:通过RPM包或YUM形式安装,Elasticsearch会自动优化这些参数,如果采用tar包的形式安装,除了手动修改这些配置,还需要创建启动Elasticsearch程序的系统用户,Elasticsearch不允许以root身份运行。

安装

安装顺序:
1. Elasticsearch
2. Kibana
3. Logstash
4. Beats

安装Elasticsearch

  1. 导入Elasticsearch PGP key,使用Elasticsearch签名密钥(PGP key D88E42B4,可从https://pgp.mit.edu获得)和fingerprint对所有包进行签名:
# rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
Shell
  1. 下载安装RPM包
# wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.rpm
# wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.rpm.sha512
# sha512sum -c elasticsearch-6.5.4.rpm.sha512 #比较RPM包的SHA和应输出的已发布校验和,输出 elasticsearch-6.5.4.rpm: OK
# rpm --install elasticsearch-6.5.4.rpm
Shell
  1. 配置文件
    Elasticsearch包含三个配置文件:
    elasticsearch.yml:配置Elasticsearch
    jvm.options:设置Elasticsearch堆栈大小,对JVM进行优化
    log4j2.properties:定义Elasticsearch日志
    这些文件的默认位置取决于安装方式。tar包形式的配置文件目录$ES_HOME/config,RPM包默认位置/etc/elasticsearch/。
    elasticsearch.yml文件采用yaml格式,以修改路径为例:
path:
    data: /var/lib/elasticsearch
    logs: /var/log/elasticsearch
or
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
YAML

elasticsearch.yml文件也支持环境变量,引用环境变量的方法${…},例如:

node.name: ${HOSTNAME}
network.host: ${ES_NETWORK_HOST}
YAML

jvm.options文件包含以下格式:
行分割;
空行被忽略;
以#开头表示注释;
以-开头的行被视为独立于JVM版本,此项配置会影响所有版本的JVM;
数字开头,后面跟一个:和一个-号的行,只会影响匹配此数字的JVM版本,例如:8:-Xmx2g,只会影响JDK8;
数字开头跟一个-号再跟一个数字再跟一个:,定义两个版本之间,且包含这两个版本,例如8-9:-Xmx2g,影响JDK8,JDK9。
注意:在配置中,应保证JVM堆栈min和max的值相同,Xms表示总堆栈空间的初始值,XmX表示总堆栈空间的最大值。

# cat /etc/elasticsearch/elasticsearch.yml

cluster.name: vtlab  #集群名称,只有cluster.name相同时,节点才能加入集群。请设置为具有描述性的名字。不建议在不同环境中使用相同的集群名。
node.name: vtlab01  #节点描述名称,默认情况下,Elasticsearch将使用随机生成的UUID的前7个字符作为节点id。设为服务器的主机名 node.name: ${HOSTNAME}
node.attr.rack: r1  #指定节点的部落属性,机架位置,比集群范围更大。
path.data: /var/lib/elasticsearch  #Elasticsearch的数据文件存放目录 如果是默认位置,在将Elasticsearch升级到新版本时,很可能会把数据删除。
path.logs: /var/log/elasticsearch  #日志目录
bootstrap.memory_lock: true  #启动后锁定内存,禁用swap交换,提高ES性能。伴随这个参数还需要调整其他配置,后面讨论。
network.host: 0.0.0.0  #指定监听的地址
http.port: 9200  #监听的WEB端口
discovery.zen.ping.unicast.hosts:  #默认网络配置中,Elasticsearch将绑定到回环地址,并扫描9300-9305端口,试图连接同一台服务器上的其他节点,可以自动发现并加入集群。
    - 10.0.0.46:9300  #此端口为TCP传输端口,用于集群内节点发现、节点间信息传输、ES Java API也是通过此端口传输数据,transport.tcp.port定义。9200为HTTP端口。
    - 10.0.0.28:9300
    - 10.0.0.29:9300
    - host1.vtlab.io
discovery.zen.minimum_master_nodes: 2  #为防止数据丢失,discovery.zen.minimum_master_nodes设置至关重要,主节点的最小选举数。避免脑裂,应将此值设为(master_eligible_nodes / 2) + 1,换言之,如果有3个节点,(3/2)+1 or 2
#以下选项仅在完全重启集群时生效
#本地网关模块在整个群集重新启动时存储群集状态和分片数据。
#以下静态设置必须在每个主节点上设置,控制新选择的主节点在试图恢复集群状态和集群数据之前应该等待多长时间:
gateway.expected_nodes: 0  #集群中预期的(数据或主)节点数量。一旦加入集群的节点数量达到预期,本地碎片的恢复就会开始。默认值为0
gateway.expected_master_nodes: 0  #集群中预期的主节点数量。一旦加入集群的主节点数量达到预期,本地碎片的恢复就会开始。默认值为0
gateway.expected_data_nodes: 0  #集群中预期的数据节点数量。一旦预期的数据节点数量加入集群,本地碎片的恢复就会开始。默认值为0
gateway.recover_after_time: 5  #如果没有达到预期的节点数量,则恢复过程将等待配置的时间量,然后再尝试恢复。如果配置了一个expected_nodes设置,则默认值为5m。
gateway.recover_after_nodes: 1  #只要有这么多数据或主节点加入集群,就可以恢复。
gateway.recover_after_master_nodes: 1  #只要有这么多主节点加入集群,就可以恢复。
gateway.recover_after_data_nodes: 1  #只要有这么多数据节点加入集群,就可以恢复。
action.destructive_requires_name: true  #禁用通过api以通配符删除所有索引。删除索引时需要指定被删除的索引名称。
YAML

配置文件中,我将bootstrap.memory_lock的值设为了true,启动时遇到了以下错误:
Elasticsearch process memory locking failed
解决此问题,还需要修改三个地方:
1. /etc/sysconfig/elasticsearch

ES_JAVA_OPTS="-Xms4g -Xmx4g" 
MAX_LOCKED_MEMORY=unlimited
Shell

替换4g为总内存的一半(Elasticsearch官方建议是主机总内存的一半)
2. /etc/security/limits.conf

elasticsearch soft memlock unlimited
elasticsearch hard memlock unlimited
Shell

需要将elasticsearch替换为运行Elasticsearch程序的用户
3. /usr/lib/systemd/system/elasticsearch.service
取消服务脚本文件/usr/lib/systemd/system/elasticsearch.service中对LimitMEMLOCK=infinity的注释

LimitMEMLOCK=infinity
Shell

然后运行systemctl daemon-reload命令

# systemctl daemon-reload
Shell
  1. 启动节点
# systemctl enable elasticsearch
# systemctl start elasticsearch
Shell

Elasticsearch安装完毕,接下来安装Kibana。

安装Kibana

同样使用RPM的形式安装
1. 安装公钥

# rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
Shell
  1. 下载rpm包
# wget https://artifacts.elastic.co/downloads/kibana/kibana-6.5.4-x86_64.rpm
# sha512sum kibana-6.5.4-x86_64.rpm 
# rpm --install kibana-6.5.4-x86_64.rpm
Shell
  1. 配置文件
    Kibana启动时从/etc/kibana/kibana.yml文件里读取配置信息,配置文件内容如下:
# Default: 5601。定义Kibana后端服务启动时监听的端口。
server.port: 5601
# Default: "localhost"。后端服务监听的地址,需要修改为网卡地址
server.host: "localhost"
# 如果前面有代理,可以指定安装Kibana的路径。
# 使用server.rewriteBasePath设置告诉Kibana是否应从其收到的请求中删除basePath,并防止在启动时发生弃用警告。
# 此设置不能以斜杠(/)结尾。
server.basePath: ""
# Default: false 
# 指定Kibana是否应重写以server.basePath为前缀的请求,或者要求它们由反向代理重写。
# 在Kibana 6.3之前,此设置实际上始终为false,在Kibana 7.0中默认为true
server.rewriteBasePath: false
# Default: 1048576
# 请求服务的最大有效负载,单位字节
server.maxPayloadBytes: 1048576
# Default: "your-hostname"。Kibana服务器的名称,用于显示目的。
server.name: "your-hostname"
# 用于查询的Elasticsearch实例的URL
elasticsearch.url: "http://localhost:9200"
# Default: true
# 值为true时,Kibana使用server.host设置中指定的主机名。值为false时,Kibana使用连接到此Kibana实例的主机的主机名
elasticsearch.preserveHost: true
# Default: ".kibana" 
# Kibana使用此索引名存储Elasticsearch中已保存的搜索、可视化和仪表板。
# 如果索引尚不存在,Kibana会创建一个新索引。
kibana.index: ".kibana"
# 要加载的默认应用程序。
kibana.defaultAppId: "home"
# 如果Elasticsearch设置了认证,Kibana通过这两个选项进行Elasticsearch的验证。
elasticsearch.username: "user"
elasticsearch.password: "pass"
# Default: "false"
# 从Kibana服务器到浏览器的传出请求启用SSL,当设置为True时,server.ssl.certificate and server.ssl.key必须设置
server.ssl.enabled: false
server.ssl.certificate: /path/to/your/server.crt
server.ssl.key: /path/to/your/server.key
# 可选设置,提供PEM格式SSL证书和密钥文件的路径。
# 这些文件用于验证Kibana到Elasticsearch的身份,并需要在Elasticsearch中的xpack.ssl.verification_mode设置为certificate或full
elasticsearch.ssl.certificate: /path/to/your/client.crt
elasticsearch.ssl.key: /path/to/your/client.key
# 可选设置,使您可以为Elasticsearch实例的证书颁发机构指定PEM文件的路径列表。
elasticsearch.ssl.certificateAuthorities: [ "/path/to/your/CA.pem" ]
# 控制Elasticsearch提供的证书验证。有效值为none,certificate和full。完整执行主机名验证,证书不执行
elasticsearch.ssl.verificationMode: full
# Defau:elasticsearch.requestTimeout 设置的值,等待Elasticsearch响应ping的时间,单位ms。
elasticsearch.pingTimeout: 1500
# Default:30000ms
# 等待来自后端或Elasticsearch的响应时间,必须是正整数。单位ms。
elasticsearch.requestTimeout: 30000
# Default: [ 'authorization' ]
# 要发送到Elasticsearch的Kibana客户端标头列表。要不发送客户端标头,请将此值设置为[](空列表)。
elasticsearch.requestHeadersWhitelist: [ authorization ]
# Default: {}
# 要发送到Elasticsearch的标头名称和值。无论elasticsearch.requestHeadersWhitelist配置如何,客户端标头都不能覆盖任何自定义标头。
elasticsearch.customHeaders: {}
# Default: 30000
# 对Elasticsearch等待碎片响应的时间(以毫秒为单位)。设置为0禁用
elasticsearch.shardTimeout: 30000
# Default: 5000
# 在重试之前在Kibana启动时等待Elasticsearch的时间(以毫秒为单位)
elasticsearch.startupTimeout: 5000
# Default false记录发送到Elasticsearch的查询。需要将logging
# 记录发送到Elasticsearch的查询。需要将logging.verbose设置为true。
# 这对于查看当前没有检查器的应用程序生成的查询DSL非常有用,例如Timelion和Monitoring。
elasticsearch.logQueries: false
# PID文件路径
pid.file: /var/run/kibana.pid
# Default: stdout
# 日志输出文件路径
logging.dest: stdout
# Default: false
# 此值设为true时,禁止记录日志
logging.silent: false
# Default: false
# 当设置为true时,仅记录error日志
logging.quiet: false
# Default: false
# 将此值设置为true以记录所有事件,包括系统使用信息和所有请求。
logging.verbose: false
# Default: 5000
# 设置以毫秒为单位的间隔来采样系统和处理性能指标。最小值是100。
ops.interval: 5000
YAML
  1. 启动
# systemctl enable kibana
# systemctl start kibana
Shell

安装Logstash

  1. 下载
# wget https://artifacts.elastic.co/downloads/logstash/logstash-6.5.4.rpm
# rpm --install logstash-6.5.4.rpm
Shell

安装Filebeat

Filebeat客户端是一个轻量级,资源消耗较低的工具,它从服务器的文件中收集日志,并将这些日志转发到Logstash进行处理。
1. 下载filebeat

# wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.5.4-x86_64.rpm
# rpm -vi filebeat-6.5.4-x86_64.rpm
Shell
  1. 配置文件
vim /etc/filebeat/filebeat.yml
# 定义获取日志的路径,可以是目录或文件:
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/messages
  tags: [syslog]
- type: log
  enabled: true
  paths:
    - /data/logs/nginx/vtlab/*.log
  tags: [nginx_access]
# 配置输出
output.redis:
  enable: true                  #默认true,是否开启传输
  hosts: ["10.0.0.26:6379"]     #redis服务的IP、端口
  db: 1                         #选择redis哪个库
  timeout: 5                    #连接redis超时时间,默认5s
  key: filter_index             #数据被传输到redis list的名称
  #password: password           #连接redis的密码,如果redis配置文件中没有设置,则此处不需要填写
YAML
  1. 启动Filebeat
# systemctl enable filebeat.service
# systemctl start filebeat.service
Shell

ELK各组件安装完成,开始日志收集相关的配置。

Logstash pipeline

Logstash管道包含两个必要元素Inputs和Outputs,以及一个可选元素Filter。Inputs接收、消费元数据,Filter根据设定过滤数据,Outputs将数据输出到指定程序,我这里定义的是输出到Elasticsearch。
我配置了Filebeat输出message日志和www.vtlab.io 的访问日志,现在创建Logstash管道接收这些数据。

# vim first-pipeline.conf
# 定义Input
input {
    redis {
        host => "10.0.0.26"
        type => "redis-input"
        data_type => "list"
        db => 1
        key => "filter_index"
        port => 6379
        #password => "password"
    }
}

# 定义Filter
filter{
    if "syslog" in [tags] {
         grok {
            match => {"message" => "%{SYSLOGBASE2}"}
            remove_field => "beat.version"
            remove_field => "beat.name"
        }
    }
    if "nginx_access" in [tags] {
        grok {
            match => { "message" => "%{COMBINEDAPACHELOG}" }
            remove_field => "beat.version"
            remove_field => "beat.name"
        }
        geoip {
           source => "clientip"
          # fields => ["city_name", "country_code2", "country_name", "latitude", "longitude", "region_name"]
          # remove_field => ["[geoip][latitude]", "[geoip][longitude]"]
        }
    }
}

# 定义output
output{
    if "syslog" in [tags] {
        elasticsearch {
            hosts => [ "10.0.0.28:9200","10.0.0.29:9200","10.0.0.46:9200" ]
            index => "message-%{+YYYY.MM.dd}"
        }
    }
    if "nginx_access" in [tags] {
        elasticsearch {
            hosts => [ "10.0.0.28:9200","10.0.0.29:9200","10.0.0.46:9200" ]
            index => "logstash-nginx-%{+YYYY.MM.dd}"
        }
    }
}
YAML

配置文件中,我定义了两个patterns:”message” => “%{SYSLOGBASE2}”与”message” => “%{COMBINEDAPACHELOG}”,一个匹配系统messages日志,一个匹配Nginx访问日志,其他日志类型,就需要不同的Patterns了。ELK提供了很多默认的Patterns,也可以自定义。

定义Patterns

一个简单的方法,通过以下两个步骤实现:
1. 打开Grokdebug discover页面,输入日志内容到文本框,点击discover按钮,如下图:
patterns
2. 打开Grokdebug页面,按图中步骤操作,输出内容就是Patterns。
patterns

启动Logstash

  1. 启动前,检验first-pipeline.conf配置文件的语法是否正确:
# /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/first-pipeline.conf --config.test_and_exit
Configuration OK
[INFO ] 2019-01-07 17:23:32.527 [LogStash::Runner] runner - Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash
Shell

输出中包含以上内容,说明配置文件正确。
2. 启动指定pipeline:
–config.reload.automatic:开启自动加载配置,这样在每次修改配置文件时会自动加载配置文件

# /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/first-pipeline.conf --config.reload.automatic
Shell

Kibana UI

日志流已经通过Filebeat、Redis、Logstash进入了Elasticsearch,我们通过Kibana对Elasticsearch做一些可视化的管理,方便查看日志。

创建索引

登录Kibana页面,在浏览器中输入 http://10.0.0.21:5601 (10.0.0.21为部署Kibana主机的IP地址,5601是Kibana监听的端口),如图:
Kibana
点击“Management”–>“Index Patterns”–>“Create index pattern”,在Index pattern框中填写Index name,也就是我们通过Logstash输出到Elasticsearch时的索引名”message-*”和”logstash-nginx-*”,点击Next step,在“Time Filter field name”中选择“@timestamp”,最后点击“Create index pattern”完成索引创建。
经过以上的步骤,就可以在Kibana的discover中依照索引查看日志了。

通过GeoIP展示用户分布

我在Logstash的filter插件部分进行了GeoIP相关的配置,现在我演示下将用户的分布按照地图展示出来。Kibana的图形化可谓丰富多姿,其他的就交给读者自己探索了。
1. 点击左侧导航栏“Dashboard”–>“Create new dashboard”
2. 点击页面中间的“add”标签,如果之前在Visualize中创建过地图,可以通过搜索名字添加,没有的话,需要先在Visualize中创建
3. 点击“Add new Visualization”,选择Maps下的“Coordinate Map”
4. 选择我们需要创建地图的索引“logstash-nginx”
5. 点击“Geo Coordinates”,选择“Geohash”
6. 点击“Options”调整颜色及图例说明位置
7. 点击页面右上角的“Save”按钮,创建完成
user_map

安全

细心的读者朋友可能已经发现了,登录kibana的时候,页面并没有验证功能,任何能访问Kibana地址的人,都能查询日志,这对我们来说是不可接受的。
改进方法:
1. X-Pack:Kibana本身不提供认证机制,需要通过X-Pack插件来实现。X-Pack是付费插件,可以申请License获取一年期的免费试用。
2. Nginx:通过htpasswd创建用户及密码,进行Kibana认证。

结尾

ELK Stack包含的功能太多了,这里只介绍了些常用功能,足以应付日常所需,更多功能,还需深入探索。

posted @ 2019-01-09 15:48  技术颜良  阅读(1929)  评论(0编辑  收藏  举报