ELK
ELK是一套开源的日志分析系统,主要由elasticsearch+logstash+Kibana三款软件组成。
下载地址: https://www.elastic.co/cn/downloads/
先简单了解这三款软件工具:
elasticsearch(简称ES): 一种文档型数据库, 可以直接存放日志信息
logstash: 日志采集,过滤,输出工具
**Kibana: 图形化展示工具
ELK使用的基本流程为:
- logstash安装到需要被采集日志的服务器(如nginx服务器)上采集日志,并输出给elasticsearch
- elasticsearch可以做分布式集群来存放大量日志信息,并可以通过相关语句命令查看
- kibana连接elasticsearch, 将日志信息进行图形化的展示
- 运维管理员通过web浏览器访问kibana就可以有目标地筛选查看日志,并画图展示
EFK
因为logstash程序占用资源高,对应用服务器(如nginx)造成了过高负载压力,所以官方开发filebeat这种轻量级的日志采集工具来替代logstash。
filebeat: 轻量级日志采集工具,相对于logstash来说占用资源少。
ELFK
在EFK架构中,logstash完全没有用到。其实logstash除了采集日志外,还有日志过滤(日志格式化处理)的功能。我们可以将ELFK结合起来使用。
小结:
- filebeat是轻量级的日志采集工具
- logstash也可以采集日志,但太占资源,可用于日志过滤(日志格式化处理)
- elasticsearch可做分布式集群来实现存放大量数据,是一种文档型数据库,也是一种搜索引擎
- kibana可以将ES集群中的数据进行可视化查看
一、环境准备
说明: 以上条件为在8G内存的物理机环境中模拟,如果物理机配置好的情况下可适当添加更多台来模拟
1, 配置静态IP
2, 配置主机名及主机名绑定
# hostnamectl set-hostname xxx
# vim /etc/hosts
10.1.1.11 kibana
10.1.1.12 es
10.1.1.13 logstash
10.1.1.14 filebeat
3, 关闭防火墙和selinux
# systemctl stop firewalld
# systemctl disable firewalld
# iptables -F
# setenforce 0
setenforce: SELinux is disabled
4, 时间同步
# systemctl restart ntpd
# systemctl enable ntpd
5, yum源(centos安装完系统后的默认yum源就OK)
二、ES集群部署
Elasticsearch(简称ES)是一个开源的分布式搜索引擎(在这里用于搜索日志),Elasticsearch还是一个分布式文档数据库。所以可以使用多台服务器来实现ES集群。
集群节点介绍
集群节点类型主要分为master节点与data节点:
- master节点:主要负责集群中索引的创建, 删除以及索引分片的Rebalance等操作.
- data节点: 主要负责集群中数据的索引和检索.
因为目前还没有讨论索引是什么,所以简单理解成master节点用于管理,data节点用于放数据。
- data节点负载压力大,master节点压力相对较小
- 可以将master与data做在一起,也可以分开
- 搭建集群时可以使用master.node: True或master.node: False来指定是否为master节点
- 搭建集群时可以使用data.node: True或data.node: False来指定是否为data节点
集群部署过程
1, 所有es节点上安装jdk
因为es是java开发的软件, 需要jdk. 在所有es节点上确认安装openjdk.
# rpm -qa |grep openjdk
java-1.8.0-openjdk-headless-1.8.0.161-2.b14.el7.x86_64
java-1.8.0-openjdk-1.8.0.161-2.b14.el7.x86_64
# java -version
openjdk version "1.8.0_161"
OpenJDK Runtime Environment (build 1.8.0_161-b14)
OpenJDK 64-Bit Server VM (build 25.161-b14, mixed mode)
2, 所有es节点上安装es
上传或下载软件包到所有es节点,直接使用rpm命令安装
# rpm -ivh elasticsearch-7.6.0-x86_64.rpm
3, 分别配置es
配置结果如下:
# egrep -vn '#' /etc/elasticsearch/elasticsearch.yml
17:cluster.name: elk-cluster
23:node.name: 10.1.1.11
33:path.data: /var/lib/elasticsearch
37:path.logs: /var/log/elasticsearch
55:network.host: 0.0.0.0
59:http.port: 9200
68:discovery.seed_hosts: ["10.1.1.11", "10.1.1.12", "10.1.1.13"]
72:cluster.initial_master_nodes: ["10.1.1.11", "10.1.1.12", "10.1.1.13"]
参数说明:
参数 | 说明 |
---|---|
cluster.name | 集群名, 3个节点同一个名 |
node.name | 节点名称,不是IP(每个节点名称不一样) |
path.data | 数据目录 |
path.logs | ES自己的日志目录 |
network.host | 服务监听的范围, 0.0.0.0表示所有IP都可以访问 |
http.port | 9200是给logstash,kibana等连接使用的端口 |
discovery.seed_hosts | 组成集群的节点IP列表 |
cluster.initial_master_nodes | 初始能成为master节点的IP列表(默认会自动选一个做为master) |
4, 所有es节点启动服务
# systemctl start elasticsearch
# systemctl enable elasticsearch
# netstat -ntlup |grep java
tcp6 0 0 :::9200 :::* LISTEN 63544/java
tcp6 0 0 :::9300 :::* LISTEN 63544/java
端口说明:
- 9200则是数据传输端口,被kibana,logstash等连接
- 9300端口是集群通信端口, 组建集群用
5, 查看集群状态
使用curl命令或浏览器访问查看集群状态(10.1.1.12可换成任意集群节点IP)
# curl http://10.1.1.12:9200/_cluster/health?pretty
{
"cluster_name" : "elk-cluster", # 集群名
"status" : "green", # 集群状态,green代表集群OK
"timed_out" : false,
"number_of_nodes" : 3, # 集群总节点数
"number_of_data_nodes" : 3, # 数据节点数
"active_primary_shards" : 0,
"active_shards" : 0,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
说明:
-
http://10.1.1.12:9200/_cluster/health?pretty为查看ES集群状态的API,前面可不加http://开头
-
结果格式为**json格式(用key: value**键值对来表示数据)
6, 查看集群节点状态
使用curl命令或浏览器访问查看集群节点状态(10.1.1.12可换成任意集群节点IP)
# curl 10.1.1.12:9200/_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
10.1.1.12 29 93 0 0.00 0.01 0.05 dilm * 10.1.1.12
10.1.1.13 14 89 0 0.00 0.01 0.05 dilm - 10.1.1.13
10.1.1.11 21 99 0 0.00 0.01 0.05 dilm - 10.1.1.11
说明:
- master列中带*号的表示为master节点
10.1.1.12:9200/_cat/nodes?v
为查看集群节点状态的API, 可以不加http://开头
三、ES基础使用
ES基础概念
每条日志数据都是很长的,ES可以直接把很长的日志行存放进去,需要用到以下概念:
概念 | 说明 |
---|---|
Document(文档) | 一条日志记录数据称为一个Document,简称doc(类似mysql里的数据行) |
Index(索引) | 若干个Document构建一个Index(类似mysql里的database) |
Type(类型) | 一个Index可以定义一种或多种类型,将文档逻辑分组(类似mysql里的table) |
Field(字段) | 一条日志存放进去会放在一个字段里,默认为message字段(类似mysql里的field) |
Shards(分片) | ES可将Index分成多个分片, 并自动分配到集群data节点中用于数据的LB |
Replicas(副本) | 可以将index做副本,用于数据的HA |
为了便于理解,我们和mysql这种关系型数据库做一个对比:
关系型数据库(如mysql,oracle等) | elasticsearch |
---|---|
database或schema | index |
table | type |
row | document |
column或field | field |
ES基础API操作
前面我们通过http://10.1.1.12:9200/_cluster/health?pretty查看ES集群状态,其实就是它的一种API操作。
什么是API?
API(Application Programming Interface)应用程序编程接口,就是无需访问程序源码或理解内部工作机制就能实现一些相关功能的接口。你可以简单来理解成就是操作ES的命令。
RestFul API格式
curl -X <verb> ‘<protocol>://<host>:<port>/<path>?<query_string>’-d ‘<body>’
参数 | 描述 |
---|---|
verb | HTTP方法,比如GET、POST、PUT、HEAD、DELETE |
host | ES集群中的任意节点主机名 |
port | ES HTTP服务端口,默认9200 |
path | 索引路径 |
query_string | 可选的查询请求参数。例如?pretty参数将返回JSON格式数据 |
-d | 里面放一个GET的JSON格式请求主体 |
body | 自己写的 JSON格式的请求主体 |
ES有大量的API
更多API参考: https://www.elastic.co/guide/en/elasticsearch/reference/7.6/index.html
查看索引
使用curl命令或浏览器访问查看索引(10.1.1.12可换成任意集群节点IP)
# curl http://10.1.1.12:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
说明:
- 默认没有任何索引
新增索引
参考文档: https://www.elastic.co/guide/en/elasticsearch/reference/7.6/indices-create-index.html
新建1个默认分片数的索引
# curl -X PUT http://10.1.1.12:9200/index1
{"acknowledged":true,"shards_acknowledged":true,"index":"index1"}
说明:
- 此命令在任意与ES网络能通,并且安装了curl命令的机器上操作即可
- index1为自定义的索引名称
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-93ij7VNn-1602933201435)(ELK图片/7.png)]
新建1个指定分片的索引
# curl -X PUT "10.1.1.12:9200/index2?pretty" -H 'Content-Type: application/json' -d'
{
"settings" : {
"index" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
}
'
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z97ntVP6-1602933201437)(ELK图片/8.png)]
删除索引
# curl -X DELETE http://10.1.1.12:9200/index1
{"acknowledged":true}
查看索引分片
# curl 10.1.1.11:9200/_cat/shards/index2?v
index shard prirep state docs store ip node
index2 2 p STARTED 0 283b 10.1.1.12 10.1.1.12
index2 2 r STARTED 0 283b 10.1.1.13 10.1.1.13
index2 1 p STARTED 0 283b 10.1.1.11 10.1.1.11
index2 1 r STARTED 0 283b 10.1.1.13 10.1.1.13
index2 0 r STARTED 0 283b 10.1.1.11 10.1.1.11
index2 0 p STARTED 0 283b 10.1.1.12 10.1.1.12
说明:
- 3个分片分别用0,1,2表示,并且分别都有1个副本
- 从上面结果中可以查看到,3个分片与副本自动分布在不同节点中
四、ES集群节点高可用
测试过程
以3节点集群为例来测试
1, 使用init 0
关闭10.1.1.13这个节点后,观察集群状态:
# curl http://10.1.1.11:9200/_cluster/health?pretty
{
"cluster_name" : "elk-cluster",
"status" : "green", 集群状态OK
"timed_out" : false,
"number_of_nodes" : 2, 3个节点变为2个节点
"number_of_data_nodes" : 2, 3个数据节点变为2个数据节点
"active_primary_shards" : 3,
"active_shards" : 6,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
2, 继续观察索引分片情况
发现3个分片自动的由3个节点分配到2个节点上
# curl 10.1.1.11:9200/_cat/shards/index2?v
index shard prirep state docs store ip node
index2 2 r STARTED 0 283b 10.1.1.11 10.1.1.11
index2 2 p STARTED 0 283b 10.1.1.12 10.1.1.12
index2 1 p STARTED 0 283b 10.1.1.11 10.1.1.11
index2 1 r STARTED 0 283b 10.1.1.12 10.1.1.12
index2 0 r STARTED 0 283b 10.1.1.11 10.1.1.11
index2 0 p STARTED 0 283b 10.1.1.12 10.1.1.12
3, 再使用init 0
关闭10.1.1.12节点后,观察集群节点状态
发现集群完蛋了
# curl http://10.1.1.11:9200/_cluster/health?pretty
{
"error" : {
"root_cause" : [
{
"type" : "master_not_discovered_exception",
"reason" : null
}
],
"type" : "master_not_discovered_exception",
"reason" : null
},
"status" : 503
}
4, 再启动10.1.1.12与10.1.1.13这两个节点后,观察集群节点状态
发现集群又恢复到3节点正常状态了
# curl http://10.1.1.11:9200/_cluster/health?pretty
{
"cluster_name" : "elk-cluster",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 3,
"active_shards" : 6,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
5, 继续观察索引分片情况
发现3个分片又自动分配回3个节点了
# curl 10.1.1.11:9200/_cat/shards/index2?v
index shard prirep state docs store ip node
index2 2 p STARTED 0 283b 10.1.1.11 10.1.1.11
index2 2 r STARTED 0 283b 10.1.1.12 10.1.1.12
index2 1 p STARTED 0 283b 10.1.1.11 10.1.1.11
index2 1 r STARTED 0 283b 10.1.1.13 10.1.1.13
index2 0 p STARTED 0 283b 10.1.1.12 10.1.1.12
index2 0 r STARTED 0 283b 10.1.1.13 10.1.1.13
测试结论
- 只要ES集群没有挂掉,分片会自动在集群节点去平衡
- 3节点集群中,挂掉1个节点,剩下2个节点继续正常提供服务(集群高可用)
- 3节点集群中,挂掉2个节点,则集群也挂了
五、logstash
logstash简介
logstash是一个开源的数据采集工具,通过数据源采集数据.然后进行过滤,并自定义格式输出到目的地。
数据分为:
- 结构化数据 如:mysql数据库里的表等
- 半结构化数据 如: xml,yaml,json等
- 非结构化数据 如:文档,图片,音频,视频等
logstash可以采集任何格式的数据,当然我们这里主要是讨论采集系统日志,服务日志等日志类型数据。
官方产品介绍:https://www.elastic.co/cn/products/logstash
input插件: 用于导入日志源 (配置必须)
https://www.elastic.co/guide/en/logstash/current/input-plugins.html
filter插件: 用于过滤(不是配置必须的)
https://www.elastic.co/guide/en/logstash/current/filter-plugins.html
output插件: 用于导出(配置必须)
https://www.elastic.co/guide/en/logstash/current/output-plugins.html
logstash部署
1, 在logstash服务器上确认openjdk安装
[root@logstash ~]# java -version
openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
2, 在logstash服务器上传并使用rpm安装logstash
[root@logstash ~]# rpm -ivh logstash-7.6.0.rpm
3, 配置logstash主配置文件
[root@logstash ~]# egrep -vn '#|^$' /etc/logstash/logstash.yml
28:path.data: /var/lib/logstash
208:path.logs: /var/log/logstash
4, 对启动命令做软链接
[root@logstash ~]# ln -s /usr/share/logstash/bin/logstash /bin/logstash
- 因为启动命令不在$PATH环境变量中,所以做软件到/bin/下方便直接使用
logstash启动测试
1, 编写测试配置文件
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
stdin {
}
}
filter {
}
output {
stdout {
}
}
说明:
- input{}与output{}必写, filter{}可以不写
- input中的stdin{}为众多input插件中的一个,表示从标准输入(也就是键盘输入)收集数据
- output中的stdout{}为众多output插件中的一个,表示收集的数据输出到标准输出(也就是当前终端)
2, 启动
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
说明:
- –path.settings 指定主配置文件目录,不指定会有警告信息
- -f 指定收集数据配置文件
- 此命令启动较慢,需要半分钟左右。最后一句信息看到Successfully表示启动成功
- 此命令没有加后台符号,会占用终端
3, 测试
haha
{
"message" => "haha",
"@timestamp" => 2020-03-21T11:31:26.406Z,
"host" => "logstash",
"@version" => "1"
}
sfsdfdsa
{
"message" => "sfsdfdsa",
"@timestamp" => 2020-03-21T11:31:33.667Z,
"host" => "logstash",
"@version" => "1"
}
说明:
- 输入任何信息都会成为message字段的值,并在当前终端显示
- @timestamp,host,@version为默认添加的字段
4, 关闭
测试完后,关闭。方法以下2种任选:
- ctrl+c 因为占用终端启动,直接ctrl+c就可以关闭进程
- ps -ef |grep java查找进程pid,然后kill杀死进程
logstash采集日志
1, 编写收集日志配置文件
这里以/var/log/messages日志为例,只定义input输入和output输出,不考虑过滤
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
file {
path => "/var/log/messages"
start_position => "beginning"
}
}
output {
elasticsearch {
hosts => ["10.1.1.12:9200"]
index => "logstash-%{+YYYY.MM.dd}"
}
}
说明:
-
file是众多input插件中的一个,用于收集本地日志文件
-
path指定收集的日志路径
-
start_position => "beginning"表示从日志最开头收集,默认是从最后收集
-
elasticsearch是众多output插件中的一个,用于将收集的数据输出给elasticsearch
-
hosts => [“10.1.1.12:9200”] 也可以指定多个es节点IP
-
index指定收集后的索引名称,+YYYY.MM.dd是日期,每天都会随着时间变化而变化
2, 启动
[root@logstash ~]# logstash --path.settings /etc/logstash -f &
- 使用&符号方便启动后可以继续使用命令验证
3, 验证索引
[root@logstash ~]# wc -l /var/log/messages
3525 /var/log/messages
拓展验证
- 索引里的docs数量会随着日志增加而增加
- 即使关闭logstash进程,日志有变化,再启动logstash进程也会把日志的更新都收集到ES。
logstash采集多日志源
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
file {
path => "/var/log/messages"
start_position => "beginning"
type => "messages"
}
file {
path => "/var/log/yum.log"
start_position => "beginning"
type => "yum"
}
}
filter {
}
output {
if [type] == "messages" {
elasticsearch {
hosts => ["10.1.1.12:9200","10.1.1.11:9200","10.1.1.13:9200"]
index => "logstash-%{+YYYY-MM-dd}"
}
}
if [type] == "yum" {
elasticsearch {
hosts => ["10.1.1.12:9200","10.1.1.11:9200","10.1.1.13:9200"]
index => "logstash-yum-%{+YYYY-MM-dd}"
}
}
}
说明:
- 收集messages日志, 索引名为logstash-%{+YYYY-MM-dd}
- 收集yum日志,索引名为logstash-yum-%{+YYYY-MM-dd}
- /var/log/yum.log为空,是不会产生索引的。可以使用
yum install XXX
安装软件使yum日志产生记录
思考: 也可以把2个日志收集成1个索引,想想怎么做?
六、kibana
Kibana是一个开源的可视化平台,可以图形查看与管理ES集群中的索引数据。
文档路径: https://www.elastic.co/guide/en/kibana/current/setup.html
kibana部署
1, 安装kibana
在kibana服务器上传或者下载软件包后,直接rpm命令安装
[root@kibana ~]# rpm -ivh kibana-7.6.0-x86_64.rpm
2, 配置kibana
配置完后的结果如下
[root@kibana ~]# egrep -vn '#|^$' /etc/kibana/kibana.yml
2:server.port: 5601
7:server.host: "0.0.0.0"
28:elasticsearch.hosts: ["http://10.1.1.11:9200", "http://10.1.1.12:9200", "http://10.1.1.13:9200"]
97:logging.dest: /var/log/kibana.log
115:i18n.locale: "zh-CN"
参数说明:
参数 | 说明 |
---|---|
server.port | kibana监听端口,默认为5601,运维人员可通过浏览器访问此端口 |
server.host | kibana监听IP, 0.0.0.0表示运维人员从任何源IP都可通过浏览器访问此端口 |
elasticsearch.hosts | 指定kibana连接es的地址,可以写任意ES节点IP, 也可以写多个 |
logging.dest | 指定kibana日志路径,可以查看此日志进行kibana排错(此日志必须手动建立) |
i18n.locale | 指定为中文 |
3, 手动建立日志,并修改owner和group属性
[root@kibana ~]# touch /var/log/kibana.log
[root@kibana ~]# chown kibana.kibana /var/log/kibana.log
4, 启动kibana服务,并验证端口
[root@kibana ~]# systemctl start kibana
[root@kibana ~]# systemctl enable kibana
[root@kibana ~]# lsof -i:5601
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 10420 kibana 11u IPv4 111974 0t0 TCP *:esmagent (LISTEN)
**4, 通过浏览器访问 http://kibana服务器IP:5601
索引管理
查看索引模式
可选字段
筛选条件
时间范围
七、filebeat收集nginx日志
因为logstash消耗内存等资源太高,如果在要采集的服务上都安装logstash,这样对应用服务器的压力增加。所以我们要用轻量级的采集工具才更高效,更省资源。
1, 关闭logstash进程
在logstash服务器上操作
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
注意: 不要直接pkill java,因为我们实验架构中,logstash上也跑了elasticsearch,所以pkill java会都杀掉
2, 配置logstash
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
beats {
port => 5044
}
}
output {
elasticsearch {
hosts => ["10.1.1.12:9200","10.1.1.11:9200","10.1.1.13:9200"]
index => "filebeat-%{+YYYY.MM.dd}"
}
stdout {
}
}
说明:
- beats是一个input插件,代表不是收集本地日志,而是收集filebeat传过来的日志
- 5044端口是默认filebeat连接过来的端口
- output中用了elasticsearch与stdout两个插件,这样可以实现双输出
- 使用stdout的目的仅是为了方便,在logstash服务器终端上就可以确认是否日志能正常传输过来
3, 启动logstash
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
确认5044端口
[root@logstash ~]# netstat -ntlup |grep :5044
tcp6 0 0 :::5044 :::* LISTEN 26374/java
4, 安装nginx
注意: 在filebeat服务器上安装,filebeat收集nginx日志,它们要在同一台服务器上
[root@filebeat ~]# yum install epel-release -y
[root@filebeat ~]# yum install nginx -y
[root@filebeat ~]# systemctl restart nginx
[root@filebeat ~]# systemctl enable nginx
5, 安装filebeat
[root@filebeat ~]# rpm -ivh filebeat-7.6.0-x86_64.rpm
6, 配置filebeat
[root@filebeat ~]# egrep -vn '#|^$' /etc/filebeat/filebeat.yml
15:filebeat.inputs:
21:- type: log
24: enabled: true
27: paths:
28: - /var/log/nginx/access.log
68:filebeat.config.modules:
70: path: ${path.config}/modules.d/*.yml
73: reload.enabled: false
80:setup.template.settings:
81: index.number_of_shards: 1
117:setup.kibana:
161:output.logstash:
163: hosts: ["10.1.1.13:5044"]
179:processors:
180: - add_host_metadata: ~
181: - add_cloud_metadata: ~
182: - add_docker_metadata: ~
183: - add_kubernetes_metadata: ~
重要参数说明:
-
24行由false改为true,表示开启收集
-
28行指定收集的日志路径,这里指定的是nginx的访问日志
-
161行表示收集日志信息输出给logstash
-
163行指定logstash的IP与接收端口(注意此行要满足YAML格式,不能顶格)
拓展写法: 可以多行来指定多个日志一起收集(需要符合YAML格式),也可以用*.log写法来匹配,如:
27: paths:
28: - /var/log/nginx/access.log
29: - /var/log/*.log
7, 启动filebeat
[root@filebeat ~]# systemctl restart filebeat
[root@filebeat ~]# systemctl enable filebeat
8, 测试
a, 通过浏览器或者curl命令访问nginx,让其产生日志
# curl 10.1.1.14
b, 验证nginx产生了访问日志
[root@filebeat ~]# cat /var/log/nginx/access.log |wc -l
9
c, 验证传输连接
日志产生后,就会产生tcp连接(filebeat的随机端口连接logstash的5044端口)
[root@filebeat ~]# netstat -nt |grep 5044
tcp 0 0 10.1.1.14:53942 10.1.1.13:5044 ESTABLISHED
注意: 如果没有持续新的日志产生,此连接过段时间会消失
d, 使用kibana验证索引内容
拓展练习
1, 可开2台或2台以上的nginx进行收集,收集成同一个索引,在kibana中筛选查看
2, EFK(不使用logstash)
[root@filebeat ~]# egrep -vn '#|^$' /etc/filebeat/filebeat.yml
15:filebeat.inputs:
21:- type: log
24: enabled: true
27: paths:
28: - /var/log/nginx/access.log
68:filebeat.config.modules:
70: path: ${path.config}/modules.d/*.yml
73: reload.enabled: false
80:setup.template.settings:
81: index.number_of_shards: 1
117:setup.kibana:
148 output.elasticsearch:
150 hosts: ["10.1.1.12:9200"]
179:processors:
180: - add_host_metadata: ~
181: - add_cloud_metadata: ~
182: - add_docker_metadata: ~
183: - add_kubernetes_metadata: ~
说明:
- 与ELFK最主要的区别在148行与150行,直接输出给ES,而不是给logstash。
八、logstash的filter插件
- EFK架构中不需要logstash。
- 而ELFK中logstash不使用filter插件的话,logstash就显得多余了
- 所以我们需要学习filter插件来了解logstash的强大。
参考: https://www.elastic.co/guide/en/logstash/current/filter-plugins.html
logstash有众多的过滤插件,很难全部讲解应用到。在这里主要讲解几个后面案例会用到的filter插件。
json插件
参考: https://www.elastic.co/guide/en/logstash/current/plugins-filters-json.html
- JSON解析过滤器
- 将json格式(key-value键值对)中的key转换成新字段,value转换成字段对应的值
案例: json过滤
1, 先关闭logstash进程
如果是后台启动logstash就使用下面命令关闭,不是后台启动直接ctrl+c就可以了
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
2, 配置logstash
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
stdin {
}
}
filter {
json {
source => "message"
}
}
output {
stdout {
}
}
说明:
- 在前面logstash启动测试章节中讨论过, 标准输入的信息都会默认成为message字段的值
- 这里的过滤配置意义为: 只要标准输入的信息是json格式,则将key转成新字段,value转成对应的值
3, 启动logstash进程
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
4, 验证
- 标准输入为haha(非json格式),则输出报错
haha
[2020-03-28T12:34:32,407][WARN ][logstash.filters.json ][main] Error parsing json {:source=>"message", :raw=>"haha", :exception=>#<LogStash::Json::ParserError: Unrecognized token 'haha': was expecting ('true', 'false' or 'null')
at [Source: (byte[])"haha"; line: 1, column: 9]>}
{
"@version" => "1",
"@timestamp" => 2020-03-28T04:34:32.276Z,
"host" => "logstash",
"message" => "haha",
"tags" => [
[0] "_jsonparsefailure"
]
}
- 标准输入为json格式,则被过滤拆分成了字段与值
{"ip":"10.1.1.1","hostname":"haha"} # 输入的json信息
{
"@version" => "1",
"host" => "logstash",
"@timestamp" => 2020-03-28T04:36:31.503Z,
"ip" => "10.1.1.1", # 过滤出来的字段
"message" => "{\"ip\":\"10.1.1.1\",\"hostname\":\"haha\"}", # 原message字段
"hostname" => "haha" # 过滤出来的字段
}
小结:
后面案例中: nginx日志格式可以改成json格式。那么搜集到的nginx日志可以通过json插件过滤,就可以很轻松的把长长的日志拆分成多个字段,然后我们就可以在kibana中方便对字段进行查看,筛选,统计等。
grok插件
json插件只能对json格式进行过滤处理,那么一般的日志格式如何进行截取过滤呢?通常情况下可以使用awk,sed等命令进行处理,在ELK中,我们可以通过grok插件来实现。
- grok自带了100多个模式(类似正则表达式),可以直接拿来使用
- 也可以自己定义模式
查看开源匹配模式: https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns
本地目录也有很多文件定义了匹配模式:
[root@logstash ~]# ls /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.1.2/patterns/
假设有如下一行日志:
55.3.244.1 GET /index.html 15824 0.043
我们希望将其对应截取成5列,并分别对应字段client
,method
,request
,bytes
,duration
案例1: 自带模式过滤
1, 先关闭logstash进程
如果是后台启动logstash就使用下面命令关闭,不是后台启动直接ctrl+c就可以了
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
2, 配置logstash
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
stdin {
}
}
filter {
grok {
match => {
"message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}"
}
}
}
output {
stdout {
}
}
说明:
- 标准输入的信息都会转成message字段的值,message字段的值会被grok过滤再拆分成多个字段
- %{IP:client}中的IP就是模式名(相当于是自带的可以匹配IP地址的正则表达式)
- %{IP:client}中的client是字段名,将匹配到的IP地址作为client字段的值
- 以此类推, 分别使用IP,WORD,URIPATHPARAM,NUMBER这4个模式截取日志
3, 启动logstash进程
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
4, 验证
- 标准输入以下内容,看结果
55.3.244.1 GET /index.html 15824 0.043 # 输入的日志行
{
"duration" => "0.043", # 过滤出来的字段
"message" => "55.3.244.1 GET /index.html 15824 0.043",
"bytes" => "15824", # 过滤出来的字段
"host" => "logstash",
"@timestamp" => 2020-03-28T09:35:32.147Z,
"client" => "55.3.244.1", # 过滤出来的字段
"@version" => "1",
"method" => "GET", # 过滤出来的字段
"request" => "/index.html" # 过滤出来的字段
}
注意:
- 如果格式与grok配置的模式不匹配,则无法过滤
案例2: 自定义模式过滤
如果你是一个正则表达式高手,完全可以自已来定义模式进行过滤。
1, 先关闭logstash进程
如果是后台启动logstash就使用下面命令关闭,不是后台启动直接ctrl+c就可以了
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
2, 创建自定义模式
[root@logstash ~]# vim /opt/patterns
ID [0-9]{3,5}
说明:
- ID为自定义的模式名称
- [0-9]{3,5}为正则,表示匹配3到5个数字
3, 配置logstash
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
stdin {
}
}
filter {
grok {
patterns_dir =>"/opt/patterns"
match => {
"message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration} %{ID:id}"
}
}
}
output {
stdout {
}
}
说明:
- patterns_dir =>"/opt/patterns" 表示加载自定义模式文件,这样才能使用自定义的模式
- %{ID:id}就是将自定义的模式进行使用
4, 启动logstash进程
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
5, 验证
55.3.244.1 GET /index.html 15824 0.043 6666 # 输入的信息
{
"@version" => "1",
"message" => "55.3.244.1 GET /index.html 15824 0.043 6666",
"duration" => "0.043",
"id" => "6666", # 截取3到5个数字,一共4个全截取到
"bytes" => "15824",
"@timestamp" => 2020-03-28T09:54:16.767Z,
"host" => "logstash",
"client" => "55.3.244.1",
"method" => "GET",
"request" => "/index.html"
}
55.3.244.1 GET /index.html 15824 0.043 6666666 # 输入的信息
{
"@version" => "1",
"message" => "55.3.244.1 GET /index.html 15824 0.043 6666666",
"duration" => "0.043",
"id" => "66666", # 最多只截取5个数字
"bytes" => "15824",
"@timestamp" => 2020-03-28T09:54:27.803Z,
"host" => "logstash",
"client" => "55.3.244.1",
"method" => "GET",
"request" => "/index.html"
}
小结:
我们可以将收集的httpd,nginx,mysql等各种不同格式的日志统一收集,然后使用grok进行匹配过滤,相当于是logstash帮我们做了awk,sed截取。然后我们就可以在kibana中方便对字段进行查看,筛选,统计等。
geoip插件
geoip(geography IP)插件是通过IP地址库信息对IP进行分析,得到IP地址的地理位置信息,如:
- 国家
- 城市
- 经度
- 纬度
等等。
grok过滤到的IP字段,通过geoip插件分析IP地理位置信息,再通过kibana画图可得到客户源IP地址分布地图。
案例: IP地理信息分析
1, 下载并解压IP地址库
开源IP地址库下载地址: https://dev.maxmind.com/geoip/geoip2/geolite2/,需要申请账号才能下载
可直接将共享的IP地址库文件上传到logstash服务器
[root@logstash ~]# tar xf GeoLite2-City_20200324.tar.gz
[root@logstash ~]# cp GeoLite2-City_20200324/GeoLite2-City.mmdb /opt/
[root@logstash ~]# ls /opt/GeoLite2-City.mmdb
/opt/GeoLite2-City.mmdb
2, 先关闭logstash进程
如果是后台启动logstash就使用下面命令关闭,不是后台启动直接ctrl+c就可以了
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
3, 配置logstash
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
stdin {
}
}
filter {
grok {
match => {
"message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}"
}
}
geoip {
source => "client"
database => "/opt/GeoLite2-City.mmdb"
}
}
output {
stdout {
}
}
说明:
- source => "client"表示以grok匹配后的client字段进行geoip分析
- database指定开源的geoip地址库
4, 启动logstash进程
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
5, 验证
202.106.0.20 GET /index.html 123 0.331 # 输入的信息
{
"@version" => "1",
"duration" => "0.331",
"host" => "logstash",
"method" => "GET",
"request" => "/index.html",
"geoip" => {
"location" => {
"lon" => 116.3889,
"lat" => 39.9288
},
"timezone" => "Asia/Shanghai",
"latitude" => 39.9288, # geoip分析得到的纬度信息
"continent_code" => "AS",
"ip" => "202.106.0.20",
"country_name" => "China", # geoip分析得到的国家名
"country_code2" => "CN",
"region_code" => "BJ",
"city_name" => "Beijing", # geoip分析得到的城市名
"country_code3" => "CN",
"region_name" => "Beijing",
"longitude" => 116.3889 # geoip分析得到的纬度信息
},
"@timestamp" => 2020-03-28T10:56:22.552Z,
"client" => "202.106.0.20",
"bytes" => "123",
"message" => "202.106.0.20 GET /index.html 123 0.331"
}
九、综合案例一
说明:
- 大量收集的日志传给logstash,logstash处理压力大,可中间加消息队列来做缓冲
- 大型架构可用kafka做消息队列,在这里我们使用redis即可
- redis在此架构中的作用是: 将收集的日志排队,再传给logstash来处理,让logstash能够抗住压力
ELFK分析json格式nginx日志
1, nginx配置
在nginx服务器(与filebeat同1台)上操作
a, 安装nginx(已经安装过就再次确认一下)
[root@filebeat ~]# yum install epel-release -y
[root@filebeat ~]# yum install nginx -y
b, 配置nginx日志格式为json格式(在http与server配置段间)
[root@filebeat ~]# vim /etc/nginx/nginx.conf
http {
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 json '{ "@timestamp": "$time_iso8601", ' # 加上json格式配置
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"body_bytes_sent": "$body_bytes_sent", '
'"request_time": "$request_time", '
'"status": "$status", '
'"request_uri": "$request_uri", '
'"request_method": "$request_method", '
'"http_referer": "$http_referer", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_user_agent": "$http_user_agent"}';
access_log /var/log/nginx/access.log json; # 把main格式换为json格式
c, 重启nginx服务
[root@filebeat ~]# rm /var/log/nginx/access* -rf
[root@filebeat ~]# systemctl restart nginx
[root@filebeat ~]# systemctl enable nginx
注意: 要先把nginx访问日志删除,重启后会自动产生,以免以前格式的日志会影响json格式日志
d, 使用浏览器或curl命令随意访问nginx几次,然后确认日志格式为json
[root@filebeat ~]# tail -1 /var/log/nginx/access.log
{ "@timestamp": "2020-03-28T19:14:28+08:00", "remote_addr": "10.1.1.1", "remote_user": "-", "body_bytes_sent": "0", "request_time": "0.000", "status": "304", "request_uri": "/", "request_method": "GET", "http_referer": "-", "http_x_forwarded_for": "-", "http_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"}
2, filebeat配置
在filebeat上操作(与nginx必须同一台服务器)
a, 安装filebeat
过程省略(前面已经安装过,如果环境没了,请参考前面章节自行安装)
b,配置filebeat输出给redis
配置结果如下
[root@filebeat ~]# egrep -vn '#|^$' /etc/filebeat/filebeat.yml
15:filebeat.inputs:
21:- type: log
24: enabled: true
27: paths:
28: - /var/log/nginx/access.log
68:filebeat.config.modules:
70: path: ${path.config}/modules.d/*.yml
73: reload.enabled: false
80:setup.template.settings:
81: index.number_of_shards: 1
117:setup.kibana:
164:output.redis:
165: hosts: ["10.1.1.14"]
166: password: "123456"
167: key: "nginx_log"
168: db: 0
169: datatype: list
185:processors:
186: - add_host_metadata: ~
187: - add_cloud_metadata: ~
188: - add_docker_metadata: ~
189: - add_kubernetes_metadata: ~
说明:
- 24行为true表示打开日志收集
- 28行为收集的nginx日志路径
- 164-169行为收集的日志输出给redis
c, 重启filebeat服务
[root@filebeat ~]# systemctl restart filebeat
[root@filebeat ~]# systemctl enable filebeat
3, redis配置
a, 在redis服务器上安装redis
因环境机器较多原因,这里是把redis,nginx,filebeat都放在同一台(有条件可另起一台做redis服务器)
[root@filebeat ~]# yum install epel-release -y
[root@filebeat ~]# yum install redis -y
b, 配置redis
[root@filebeat ~]# vim /etc/redis.conf
61 bind 0.0.0.0
480 requirepass 123456
说明:
- 61行修改为监听所有IP,这样filebeat可以是任何IP都可以连过来
- 480为redis登录密码
c, 重启redis服务
[root@filebeat ~]# systemctl restart redis
[root@filebeat ~]# systemctl enable redis
d, 连接redis验证
[root@filebeat ~]# redis-cli -h 10.1.1.14 -a 123456
10.1.1.14:6379> keys *
1) "nginx_log"
10.1.1.14:6379> llen nginx_log
(integer) 6
10.1.1.14:6379> quit
说明: llen nginx_log
得到的数字6表示当前nginx日志有6条记录,都被传到redis中排除等待
4, logstash配置
a, 先关闭logstash进程
如果是后台启动logstash就使用下面命令关闭,不是后台启动直接ctrl+c就可以了
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
b, 配置logstash,input插件为redis,output插件为elasticsearch
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
redis {
host => "10.1.1.14"
port => 6379
password => "123456"
db => "0"
data_type => "list"
key => "nginx_log"
}
}
filter {
json {
source => "message"
}
}
output {
elasticsearch {
hosts => ["http://10.1.1.12:9200"]
index => "elfk1-%{+YYYY.MM.dd}"
}
stdout {
}
}
说明:
- input输入插件为redis,相关配置与redis服务器要对应
- 过滤插件使用json,把key-value转换成多个字段
- output输出插件为elasticsearch与stdout双输出(stdout只是为了实验方便测试)
c, 启动logstash进程
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
5, kibana验证
访问kibana,创建索引模式(过程省略,请参考前面章节内容)
结果如下:
6, kibana画图
将想要查看的日志数据画成图形,便于更直观查看
请再访问几次nginx服务, 然后做以下画图
7, kibana仪表盘
如果想一次查看多张图,可以将其加入到dashboard(仪表盘),统一方便查看。
十、综合案例二
ELFK+grok+geoip
接着上个案例的环境继续
1, 关闭logstash进程
在logstash服务器上操作
如果是后台启动logstash就使用下面命令关闭,不是后台启动直接ctrl+c就可以了
[root@logstash ~]# ps -ef |grep java |grep logstash |awk '{print $2}' |xargs kill -9
2, nginx配置
a, 配置nginx日志格式由json改回为main, 原json日志格式配置段可以删除
在nginx服务器上操作(本例与filebeat,redis为同一台)
[root@filebeat ~]# vim /etc/nginx/nginx.conf
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
b, 重启nginx服务
[root@filebeat ~]# rm /var/log/nginx/access* -rf
[root@filebeat ~]# systemctl restart nginx
[root@filebeat ~]# systemctl enable nginx
注意: 要先把nginx访问日志删除,重启后会自动产生,以免以前格式的日志会影响
c, 使用浏览器或curl命令随意访问nginx几次,然后确认日志格式为原来的正常格式
[root@filebeat ~]# tail -1 /var/log/nginx/access.log
10.1.1.1 - - [28/Mar/2020:21:05:32 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
3, filebeat配置
保持和综合案例1一样,完全不用变
4, redis配置
保持和综合案例1一样,完全不用变
验证一下
[root@filebeat ~]# redis-cli -h 10.1.1.14 -a 123456
10.1.1.14:6379> keys *
1) "nginx_log"
10.1.1.14:6379> llen nginx_log
(integer) 3
10.1.1.14:6379> quit
5, logstash配置
a, 配置logstash
[root@logstash ~]# vim /etc/logstash/conf.d/test.conf
input {
redis {
host => "10.1.1.14"
port => 6379
password => "123456"
db => "0"
data_type => "list"
key => "nginx_log"
}
}
filter {
grok {
match => {
"message" => "%{IPV4:remote_addr} - (%{USERNAME:remote_user}|-) \[%{HTTPDATE:time_local}\] \"%{WORD:request_method} %{URIPATHPARAM:request_uri} HTTP/%{NUMBER:http_protocol}\" %{NUMBER:http_status} %{NUMBER:body_bytes_sent} \"%{GREEDYDATA:http_referer}\" \"%{GREEDYDATA:http_user_agent}\" \"(%{IPV4:http_x_forwarded_for}|-)\""
}
overwrite => ["message"]
}
geoip {
source => "remote_addr"
target => "geoip"
database => "/opt/GeoLite2-City.mmdb"
add_field => ["[geoip][coordinates]", "%{[geoip][longitude]}"]
add_field => ["[geoip][coordinates]", "%{[geoip][latitude]}"]
}
mutate {
convert => ["[geoip][coordinates]", "float"]
}
}
output {
elasticsearch {
hosts => ["http://10.1.1.12:9200"]
index => "logstash-nginx-%{+YYYY.MM.dd}"
}
stdout {
}
}
说明:
-
grok插件过滤默认格式的nginx日志
-
geoip插件的target字段中的geoip可用于划坐标地图信息
-
geoip插件的add_field字段用于获取经度与纬度信息
-
mutate插件的convert用于把经纬度改为float浮点数
-
注意: 索引名一定要以logstash开头,否则后面画地图认不出来(有点坑)
b, 启动logstash进程
[root@logstash ~]# logstash --path.settings /etc/logstash -f /etc/logstash/conf.d/test.conf
c, 模拟公网客户端访问
因为geoip分析的是公网IP,我们现在实现环境中没有真正的公网客户端,所以可以使用vi编辑模拟公网IP
方法为: vim 打开日志,使用yy复制日志行,再p粘贴N行,把第1列的IP改成任意公网IP
[root@filebeat ~]# vim /var/log/nginx/access.log
100.1.1.1 - - [28/Mar/2020:21:05:31 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
101.1.1.1 - - [28/Mar/2020:21:05:32 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
102.1.1.1 - - [28/Mar/2020:21:05:32 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
103.1.1.1 - - [28/Mar/2020:21:05:32 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
104.1.1.1 - - [28/Mar/2020:21:05:32 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
105.1.1.1 - - [28/Mar/2020:21:05:32 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" "-"
.......
.......
.......
6, kibana验证
创建索引模式过程省略,结果如下
7, kibana画图