通俗来讲,ELK 是由 Elasticsearch、Logstash、Kibana 三个开源软件的组成,这三个软件当中,每个软件用于完成不同的功能。
为什么使用 ELK?
ELK 组件在海量日志系统的运维中,可用于解决以下主要问题:
ELK 组件在大数据运维系统中,主要可解决的问题如下:
官方站点:https://www.elastic.co/cn/
架构图:
由于 Logstash 比较耗资源,一般我们不会在应用服务器上直接安装 Logstash 来收集日志,我们可能会采用更轻量级的 Filebeat 来采集日志,但当多台 Filebeat 向 Logstash 传输数据再交给ES入库时,压力会比较大,可以在 Filebeat 和 Logstash 之间加上一层消息队列减轻压力,比如Redis、Kafka。
实验环境:
系统 | 节点 | JDK | Zookeeper | Kafka | Elasticsearch | logstash | kibana |
---|---|---|---|---|---|---|---|
CentOS7.6 | elk-node1 (192.168.100.111) | jdk-8u212 | zookeeper-3.4.14 | kafka_2.12-2.1.0 | elasticsearch-6.8.7 | logstash-6.8.7 | kibana-6.8.7 |
CentOS7.6 | elk-node2 (192.168.100.112) | jdk-8u212 | zookeeper-3.4.14 | kafka_2.12-2.1.0 | elasticsearch-6.8.7 | logstash-6.8.7 | kibana-6.8.7 |
CentOS7.6 | elk-node3 (192.168.100.113) | jdk-8u212 | zookeeper-3.4.14 | kafka_2.12-2.1.0 | elasticsearch-6.8.7 | logstash-6.8.7 | – |
实验准备:
~]# systemctl stop firewalld
~]# systemctl disable firewalld
~]# setenforce 0
~]# sed -i '/SELINUX/s/enforcing/disabled/g' /etc/sysconfig/selinux
~]# cat /etc/hosts
...
192.168.100.111 elk-node1
192.168.100.112 elk-node2
192.168.100.113 elk-node3
下载地址:https://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html
~]# tar xf jdk-8u212-linux-x64.tar.gz -C /usr/local/
~]# cd /usr/local/
~]# ln -sv jdk1.8.0_212/ jdk
~]# echo 'JAVA_HOME=/usr/local/jdk' > /etc/profile.d/jdk.sh
~]# echo 'PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile.d/jdk.sh
~]# . /etc/profile.d/jdk.sh
~]# java -version
java version "1.8.0_212"
Java(TM) SE Runtime Environment (build 1.8.0_212-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode)
下载地址: https://mirrors.tuna.tsinghua.edu.cn/apache/
zookeeper配置参数:http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_configuration
在Zookeeper的官网上有这么一句话:ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. 这大概描述了Zookeeper主要可以干哪些事情:配置管理,名字服务,提供分布式同步以及集群管理。此处我们需要使用Zookeeper来管理Kafka集群。
~]# tar xf zookeeper-3.4.14.tar.gz -C /opt/
~]# cd /opt/
~]# ln -sv zookeeper-3.4.14/ zookeeper
~]# cd zookeeper/conf/
~]# cp zoo_sample.cfg zoo.cfg
~]# cat zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/zookeeper/data
dataLogDir=/opt/zookeeper/log
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
clientPort=2181
server.0=192.168.100.111:2888:3888
server.1=192.168.100.112:2888:3888
server.2=192.168.100.113:2888:3888
~]# mkdir ../{data,log}
~]# echo 0 > ../data/myid #三台zk编号不同,此处为0,其余两台为1、2,与配置中的server.x有关
~]# echo 'ZK_HOME=/opt/zookeeper' > /etc/profile.d/zk.sh
~]# echo 'PATH=$ZK_HOME/bin:$PATH' >> /etc/profile.d/zk.sh
~]# source /etc/profile.d/zk.sh
~]# zkServer.sh start
~]# zkServer.sh status
~]# zkCli.sh -server localhost:2181
配置解析:
下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/kafka/
kafka配置参数:http://kafka.apache.org/documentation/#brokerconfigs
~]# tar xf kafka_2.12-2.1.0.tgz -C /opt/
~]# cd /opt/
~]# ln -sv kafka_2.12-2.1.0/ kafka
~]# cd kafka/config/
~]# cp server.properties server.properties_bak
~]# cat server.properties | grep -v '#' | grep -v "^$"
broker.id=1 #每一个broker在集群中的唯一表示,要求是正数
listeners=PLAINTEXT://192.168.100.111:9092 #监控的kafka端口
num.network.threads=3 #broker处理消息的最大线程数,一般情况下不需要去修改
num.io.threads=8 #broker处理磁盘IO的线程数,数值应该大于你的硬盘数
socket.send.buffer.bytes=102400 #socket的发送缓冲区
socket.receive.buffer.bytes=102400 #socket的接受缓冲区
socket.request.max.bytes=104857600 #socket请求的最大字节数
log.dirs=/opt/kafka/kafka-logs #kafka数据的存放地址,多个地址用逗号分割,多个目录分布在不同磁盘上可以提高读写性能
num.partitions=3 #设置partitions 的个数
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.retention.hours=168 #数据文件保留多长时间,此处为168h,粒度还可设置为分钟,或按照文件大小
log.segment.bytes=1073741824 #topic的分区是以一堆segment文件存储的,这个控制每个segment的大小,会被topic创建时的指定参数覆盖
log.retention.check.interval.ms=300000
zookeeper.connect=192.168.100.111:2181,192.168.100.112:2181,192.168.100.113:2181 #zookeeper集群地址
zookeeper.connection.timeout.ms=6000 #kafka连接Zookeeper的超时时间
group.initial.rebalance.delay.ms=0
~]# echo 'KFK_HOME=/opt/kafka' > /etc/profile.d/kfk.sh
~]# echo 'PATH=$KFK_HOME/bin:$PATH' >> /etc/profile.d/kfk.sh
~]# source /etc/profile.d/kfk.sh
~]# kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties
验证kafka是否可用:
~]# zkCli.sh -server localhost:2181
[zk: localhost:2181(CONNECTED) 0] get /brokers/ids/1
{"listener_security_protocol_map":{"PLAINTEXT":"PLAINTEXT"},"endpoints":["PLAINTEXT://192.168.100.111:9092"],"jmx_port":-1,"host":"192.168.100.111","timestamp":"1591675712330","port":9092,"version":4}
cZxid = 0x10000001a
ctime = Tue Jun 09 00:08:32 EDT 2020
mZxid = 0x10000001a
mtime = Tue Jun 09 00:08:32 EDT 2020
pZxid = 0x10000001a
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x20000a7ad170000
dataLength = 200
numChildren = 0
注: kafka节点默认需要的内存为1G,在工作中可能会调大该参数,可修改kafka-server-start.sh的配置项。找到KAFKA_HEAP_OPTS配置项,例如修改为:export KAFKA_HEAP_OPTS="-Xmx2G -Xms2G"。
下载地址:https://www.elastic.co/cn/downloads/
~]# tar xf elasticsearch-6.8.7.tar.gz -C /opt/
~]# cd /opt/
~]# ln -sv elasticsearch-6.8.7/ elasticsearch
~]# cd elasticsearch/config/
~]# cp elasticsearch.yml elasticsearch.yml_bak
~]# cat elasticsearch.yml
cluster.name: myes #集群名称,一定要一致,当集群内节点启动的时候,默认使用组播(多播),寻找集群中的节点
node.name: elk-node1 #节点名称
path.data: /opt/elasticsearch/data #数据目录
path.logs: /opt/elasticsearch/log #日志目录
bootstrap.memory_lock: true #启动时锁定内存
network.host: 192.168.100.111 #监听IP
transport.tcp.port: 9300 #集群内通信端口,默认9300
http.port: 9200 #服务监听端口,默认9200
discovery.zen.ping.unicast.hosts: ["elk-node2", "elk-node3"] #集群中其他成员,需要能解析,请先做好host
discovery.zen.minimum_master_nodes: 2 #成为master需要的最小票数
~]# cat jvm.options | grep -v '#' | grep -v '^$' | head -n 2 #默认给elasticsearch分配的内存,生产环境需调大此数值
-Xms1g
-Xmx1g
~]# useradd elastic #elasticsearch 5.0后不能使用root启动
~]# echo "123456" | passwd --stdin elastic
~]# chown -R elastic:elastic /opt/elasticsearch/
~]# vim /etc/sysctl.conf #调整系统虚拟内存,否则会启动不了
vm.max_map_count=262144
~]# sysctl -p
~]# tail -n 4 /etc/security/limits.conf #修改用户可使用最大文件描述符 ,锁定内存
* soft nofile 65536
* hard nofile 65536
* soft memlock unlimited
* hard memlock unlimited
若不设置以上两参数,启动时会报错:
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535]
[2]: memory locking requested for elasticsearch process but memory is not locked
[3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
~]# su - elastic #es默认不能使用root启动
~]# cd /opt/elasticsearch/bin
~]# ./opt/elasticsearch/bin/elasticsearch -d #elastic用户
~]# curl http://192.168.100.111:9200/_cat/nodes #查看集群节点信息,*号为集群master
192.168.100.113 18 97 0 0.16 0.10 0.07 mdi - elk-node3
192.168.100.112 13 97 0 0.07 0.14 0.10 mdi * elk-node2
192.168.100.111 26 94 0 0.23 0.68 0.40 mdi - elk-node1
# Master 的职责:统计各 node 节点状态信息、集群状态信息统计、索引的创建和删除、索引分配的管理、关闭 node 节点等
# Slave 的职责:从 master 同步数据、等待机会成为 Master
Elasticsearch-head简介:
在 elasticsearch 5.x 版本以后不再支持直接安装 head 插件,而是需要通过启动一个服务。以下提供两种安装方式:
NPM安装:
~]# yum install -y git npm #NPM 的全称是 Node Package Manager,是随同 NodeJS 一起安装的包管理和分发工具,它很方便让 JavaScript 开发者下载、安装、上传以及管理已经安装的包。
~]# cd /opt/
~]#git clone http://github.com/mobz/elasticsearch-head.git
~]# cd elasticsearch-head/
~]# npm install grunt -save
~]# ll node_modules/grunt #确认生成文件
~]# npm install #执行安装
~]# npm run start & #后台启动服务
~]# cat /opt/elasticsearch/config/elasticsearch.yml | tail -n 2 #开启跨域访问支持,然后重启 elasticsearch 服务
http.cors.enabled: true
http.cors.allow-origin: "*"
Docker安装:
~]# yum install docker -y
~]# systemctl start docker && systemctl enable docker
~]# mkdir -p /etc/docker
~]# tee /etc/docker/daemon.json <<-'EOF' #配置镜像加速,此处配置阿里云镜像加速
{
"registry-mirrors": ["https://nqq67ahg.mirror.aliyuncs.com"]
}
EOF
~]# systemctl daemon-reload
~]# systemctl restart docker
~]# docker run -d -p 9100:9100 mobz/elasticsearch-head:5
~]# cat /opt/elasticsearch/config/elasticsearch.yml | tail -n 2 #开启跨域访问支持,然后重启 elasticsearch 服务
http.cors.enabled: true
http.cors.allow-origin: "*"
默认监听在9100端口,可直接访问。
logstash配置我们后面进行说明
~]# tar xf logstash-6.8.3.tar.gz -C /opt/
~]# cd /opt
~]# ln -sv logstash-6.8.3/ logstash
~]# tar xf kibana-6.8.7-linux-x86_64.tar.gz -C /opt/
~]# cd /opt/
~]# ln -sv kibana-6.8.7-linux-x86_64/ kibana
~]# cd kibana/config/
~]# cp kibana.yml kibana.yml_bak
~]# cat kibana.yml
server.port: 5601
server.host: "192.168.100.111"
server.name: "node1.kibana"
elasticsearch.url: "http://192.168.100.111:9200"
~]# nohup ../bin/kibana & #监听5601端口
写环境变量:
~]# echo 'ES_HOME=/opt/elasticsearch' > /etc/profile.d/elk.sh
~]# echo 'LS_HOME=/opt/logstash' >> /etc/profile.d/elk.sh
~]# echo 'KB_HOME=/opt/kibana' >> /etc/profile.d/elk.sh
~]# echo 'PATH=$ES_HOME/bin:$LS_HOME/bin:$KB_HOME/bin:$PATH' >> /etc/profile.d/elk.sh
~]# source /etc/profile.d/elk.sh
~]# cat /etc/yum.repos.d/nginx.repo #直接使用yum安装
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
~]# yum install -y nginx
~]# cat /etc/nginx/nginx.conf #添加如下配置
http{
...
upstream kibana_server {
server 192.168.100.111:5601;
server 192.168.100.112:5601;
ip_hash;
}
server {
listen 80;
server_name www.kibana.com;
access_log /var/log/nginx/access.log main;
location / {
proxy_pass http://kibana_server;
}
}
...
}
还可以通过Nginx做一些访问控制啥的,这里就不描述了。
此处我们使用 filebeat 收集本地系统日志,写入 kafka,logstash 从 kafka 中读取数据并传给 elasticsearch,从而 kibana 进行展示。
给需要收集日志主机安装filebeat:
~]# tar xf filebeat-6.8.3-linux-x86_64.tar.gz -C /opt/
~]# cd /opt/
~]# ln -sv filebeat-6.8.3-linux-x86_64/ filebeat
此处我们使用 filebeat 收集本地系统日志,写入 kafka,logstash 从 kafka 中读取数据并传给 elasticsearch,从而 kibana 进行展示。
配置启用filebeat:
~]# cat /opt/filebeat/filebeat.yml 修改如下两个配置项
filebeat.inputs: #从哪里收集
- type: log
enabled: true
paths:
- /var/log/messages
output.kafka: #收集的数据写到哪里去
hosts: ["192.168.100.111:9092","192.168.100.112:9092","192.168.100.113:9092"]
topic: messages-topics #写到哪个topics
keep_alive: 10s
nohup ./filebeat -e -c filebeat.yml &
当我们filebeat启用没问题,此时数据就能写到kafka中了。
查看kafka中是否创建了topics:
~]# kafka-topics.sh --list --zookeeper 192.168.100.111:2181,192.168.100.112:2181,192.168.100.113:2181
__consumer_offsets
messages-topics
kafka已有数据,我们还需使用logstash从kafka中读取数据,交给elasticsearch。
logstash-input-kafka配置可参考:https://segmentfault.com/a/1190000016595992
配置启用logstash:
~]# cat /opt/logstash/messages-logstash.conf
input {
kafka {
bootstrap_servers => "192.168.100.111:9092,192.168.100.112:9092,192.168.100.113:9092" #kafka集群地址
group_id => "logstash" #此消费者所属的组的标识符,消费者组是由多个处理器组成的单个逻辑订阅服务器,主题中的消息将分发给具有相同group_id的所有Logstash实例。
auto_offset_reset => "earliest" #如果Kafka中没有初始偏移量,或者偏移量超出范围,自动重置偏移量到最早的偏移量
decorate_events => true #在输出消息的时候会输出自身的信息包括:消费消息的大小,topic 来源以及 consumer 的 group 信息。
topics => ["messages-topics"] #哪个topics取数据
type => "messages" #用于其他插件进行判断
}
}
output {
if [type] == "messages" {
elasticsearch {
hosts => ["192.168.100.111:9200"]
index => "messages-%{+YYYY-MM}" #索引名称
}
}
}
~]# cd /opt/logstash
~]# nohup ./bin/logstash -f messages-logstash.conf &
在kibana添加索引:
至此,我们的日志系统流程就走通了。
上面我们收集了系统日志,现在再加上nginx访问日志。
filebeat配置修改:
~]# cat /opt/filebeat/filebeat.yml #修改如下两个配置项,修改后重启服务
- type: log
enabled: true
paths:
- /var/log/messages
fields:
topics: messages-topics
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
fields:
topics: nginx-access-topics
output.kafka:
hosts: ["192.168.100.111:9092","192.168.100.112:9092","192.168.100.113:9092"]
topic: '%{[fields][topics]}'
keep_alive: 10s
logstash修改配置:
~]# cat messages-logstash.conf #修改如下配置项,修改后重启服务
input {
kafka {
bootstrap_servers => "192.168.100.111:9092,192.168.100.112:9092,192.168.100.113:9092"
group_id => "logstash"
auto_offset_reset => "earliest"
decorate_events => true
topics => ["messages-topics"]
type => "messages"
}
kafka {
bootstrap_servers => "192.168.100.111:9092,192.168.100.112:9092,192.168.100.113:9092"
group_id => "logstash"
auto_offset_reset => "earliest"
decorate_events => true
topics => ["nginx-access-topics"]
type => "nginx-access"
}
}
output {
if [type] == "messages" {
elasticsearch {
hosts => ["192.168.100.111:9200"]
index => "messages-%{+YYYY-MM}"
}
}
if [type] == "nginx-access" {
elasticsearch {
hosts => ["192.168.100.111:9200"]
index => "nginx-access-%{+YYYY-MM}"
}
}
}
至此,我们就能简单实现日志采集、分类、索引、展示等功能了。