ELK手把手带你搭建(Filebeat + Kafka+Logstash+ElasticSeaarch+Kibana)

背景:

鉴于当前测试环境在日志管理方面遭遇的困境,如日志无法持久化保存、服务重启导致的历史记录丢失,以及数据库日志查询效率低下等问题,我计划在本地搭建一套由Filebeat、Kafka、Elasticsearch、Logstash和Kibana组成的日志分析系统(ELK Stack),以全面优化我们的日志管理流程。

通过这套ELK Stack系统,我们期望实现以下关键目标:

  1. 日志持久化保存:利用Elasticsearch的强大存储能力,确保所有日志数据都能被安全、可靠地保存,不再因服务重启而丢失历史记录。

  2. 高效搜索与分析:Elasticsearch的分布式搜索引擎将提供快速且强大的数据检索和分析能力,让我们能够迅速定位并分析问题,提高故障排查效率。

  3. 可视化展示:Kibana的图形化界面将直观地展示日志数据,帮助我们更好地理解系统行为,发现潜在问题,并做出及时响应。

几年前,我有幸与公司的技术专家一起搭建过ELK系统,积累了丰富的实践经验。因此,我先在本地搭建并测试这套系统,为测试环境的日志管理带来显著的改进。

通过本地搭建ELK系统,我们可以先验证其效果,并根据实际情况进行调整和优化。一旦验证成功,我们可以考虑将其部署到测试环境中,以提升整个团队的日志管理效率。

Filebeat:

  • 作用:轻量级的日志数据收集器,专门用于转发和集中日志数据。

  • 特性:

    • 监控指定的日志文件或位置,实时收集日志事件。

    • 支持多种输入类型,如日志文件、syslog、Redis等。

    • 作为服务器上的代理安装,确保日志数据的实时性和完整性。

Kafka:

  • 作用:作为分布式消息队列,用于实时数据流的传输和处理。

  • 特性:

    • 分布式、高吞吐、可扩展的消息队列服务。

    • 支持大量的实时数据处理和分析,确保数据的可靠性和持久性。

    • 可以作为Filebeat的输出端,实时接收Filebeat采集的数据。

Logstash:

  • 作用:作为数据收集引擎,负责数据的过滤、解析和转换。

  • 特性:

    • 实时管道功能,支持从多个数据源获取数据,并对其进行转换。

    • 过滤器能够解析各个事件,识别已命名的字段以构建结构,并将它们转换成通用格式。

Elasticsearch:

  • 作用:作为分布式搜索引擎,提供高性能的日志数据存储和检索功能。

  • 特性:

    • 分布式、可扩展的搜索和分析引擎。

    • 提供强大的全文搜索、结构化搜索和分析功能。

    • 支持PB级数据的存储和检索,确保数据的快速访问和高效处理。

Kibana:

  • 作用:作为数据可视化工具,提供日志数据的可视化展示和分析功能

  • 特性:

    • 提供了强大的搜索和查询功能,支持多种查询方式。

    • 提供了丰富的可视化图表和仪表板,帮助用户更好地理解数据。

    • 支持与Elasticsearch的无缝集成,实现数据的实时展示和分析。

项目配置log4j

所需依赖:注意要排除掉[logback]的依赖

<!-- Log4j 2 核心包 -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.17.2</version>
            </dependency>
            <!-- Log4j 2 API -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>2.17.2</version>
            </dependency>
            <!-- Log4j 2 和 SLF4J 绑定 -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
                <version>2.17.2</version>
            </dependency>

log4j2.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="ERROR" monitorInterval="5">
    <Properties>
        <Property name="logPath">/Library/javaWork/logs/cloud2024/log</Property>  <!-- 日志存储目录 -->
        <Property name="fileName">cloud2024</Property>  <!-- 日志名称 -->
    </Properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>

        <RollingFile name="fileB" fileName="${logPath}/${fileName}.log"
                     filePattern="${logPath}/${fileName}_%d{yyyy-MM-dd}.log">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss:SSS} [%p] - %l - %m%n"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
    </Appenders>

    <Loggers>
<!--        <Root level="info" includeLocation="false">-->
<!--            <AppenderRef ref="Console"/>-->
<!--        </Root>-->
        <Logger name="com.syl.cloud_2024" level="info" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="fileB"/>
        </Logger>
    </Loggers>
</Configuration>

我们先造几条日志数据

查看日志文件

将日志文件上传服务器

到此处日志数据已经就位,接下来我们需要做的就是让filebeat读取日志数据。


Filebeat篇:

下载:curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.10.0-linux-arm64.tar.gz

解压:tat -zxvf filebeat-7.10.0-linux-arm64.tar.gz

修改文件名:mv filebeat-7.10.0-linux-arm64 filebeat-7.10.0

目录:

[root@shenyulong filebeat-7.10.0]# ll
总用量 104924
drwxr-x---.  3 root root       60 5月  29 02:13 data
-rw-r--r--.  1 root root  3703475 11月 10 2020 fields.yml
-rwxr-xr-x.  1 root root 94984074 11月 10 2020 filebeat
-rw-r--r--.  1 root root   134504 11月 10 2020 filebeat.reference.yml
-rwxr--r--.  1 root root     1677 5月  21 12:13 filebeat.sh
-rw-------.  1 root root     9034 5月  21 12:58 filebeat.yml
drwxr-xr-x.  3 root root       15 11月 10 2020 kibana
-rw-r--r--.  1 root root    13675 11月 10 2020 LICENSE.txt
drwx------.  2 root root      148 5月  29 02:13 logs
drwxr-xr-x. 66 root root     4096 11月 10 2020 module
drwxr-xr-x.  2 root root     4096 11月 10 2020 modules.d
-rw-r--r--.  1 root root  8566190 11月 10 2020 NOTICE.txt
-rw-r--r--.  1 root root      814 11月 10 2020 README.md

文件介绍:

  • /data下有个registry目录,作用是:Filebeat会将自己处理日志文件的进度信息写入到registry文件中,以保证filebeat在重启之后能够接着处理未处理过的数据,而无需从头开始**(如果测试中读取的是写死的日志文件,并不会动态添加日志,测试时候在每次filebeat启动前,可以删除/data下的registry目录 rm -rf registry ,这样每次重启,filebeat都会去重新加载日志。——》方便测试,也仅限于测试时候使用)**

  • filebeat 为启动文件

  • filebeat.yml 为配置输出文件

  • logs 为filebeat启动日志目录

启动:./filebeat -c /yeYingXuan/app/filebeat/filebeat-7.10.0/filebeat.yml -e

每次启动都要输这么大一串,为了方便,我们写一个启动脚本filebeat.sh

#!/bin/bash

if [[ $# != 1 ]] || [[ $1 != 'start' && $1 != 'stop' && $1 != 'log'  && $1 != 'slow' && $1 != 'moniter' && $1 != 'rmlog' ]]
then
  echo  "    输入参数有误   !!! "
  echo  "    接收参数为 start | stop | log | moniter  "
fi

function start(){
  pid=`ps -ef|grep filebeat|grep -v 'grep'|grep -v 'filebeat.sh'|awk -F ' ' '{print $2}'`

  if [ ! -z $pid ]
  then
    echo "已经在运行中 正在停止  ...."
    kill $pid
    sleep 10s
  fi
  run
}

function run(){
    echo "开始启动 ....  ...."
    nohup /yeYingXuan/app/filebeat/filebeat-7.10.0/filebeat -c /yeYingXuan/app/filebeat/filebeat-7.10.0/filebeat.yml  >/dev/null 2>&1 &
    echo "启动成功"
}


function stop(){
  pid=`ps -ef|grep filebeat|grep -v 'grep'|grep -v 'filebeat.sh'|awk -F ' ' '{print $2}'`

  if [ ! -z $pid ]
  then
    echo "开始停止进程 ...   ..."
    kill $pid
  else
    echo '未找到 filebeat 相关进程 请检查是否运行中'
  fi
}

function log(){
  tail -f  /data/filebeat/filebeat/logs/filebeat
}

function moniter(){
  pid=`ps -ef|grep filebeat|grep -v 'grep'|grep -v 'filebeat.sh'|awk -F ' ' '{print $2}'`

  if [ -z $pid  ]
  then
    run
        else
    echo "filebeat 进程已经在运行中。。。。。。"
  fi
}

function rmlog(){
  cd  /data/filebeat/filebeat/logs &&
  find .  -name  'file*' -mmin +180 -exec rm -rf {} \;
}

case $1 in

  start)
    start;;
  stop)
    stop;;
  log)
    log;;
  moniter)
    moniter;;
  rmlog)
    rmlog;;
esac

配置输入源与输出源:

输入源为我们要要读取哪个文件的数据。

输出源可以输出到控制台、logstash、kafka等,但是不能同时配置输出多个位置,这里我们先配置输出到控制台测试读取数据是否成功,然后再改成输出到logstash。(输出到kafka这里就先不演示了,kafka的配置我下面已经列出来了。)

[root@shenyulong filebeat-7.10.0]# vi filebeat.yml

# ============================== Filebeat inputs ===============================

filebeat.inputs:
- type: log

  # Change to true to enable this input configuration.
  enabled: true

  # Paths that should be crawled and fetched. Glob based paths.
  paths:
    - /yeYingXuan/app/log/*.log #要读取的文件目录,我这里读取了log下的所有.log文件。
输出到文件(方法一)
#output.file: 
#  path: "/yeYingXuan/app/filebeat"
#  filename: "filebeat_test.log"

#输出到文件(方法二)
#output:
#  file:
#    path: "/yeYingXuan/app/filebeat"
#    filename: "filebeat_test.log"
#    rotate_every_kb: 1000
#    number_of_files: 7

#输出到控制台(方法一)
#output:
#  console:
#    pretty: true
#输出到控制台(方法二)
#output.console:
#  enable: true
# ============================== Filebeat modules ==============================
#默认的
filebeat.config.modules:
  # Glob pattern for configuration loading
  path: ${path.config}/modules.d/*.yml

  # Set to true to enable config reloading
  reload.enabled: true

  # Period on which files under path should be checked for changes
  reload.period: 10s
# ------------------------------ Logstash Output -------------------------------
#输出到logstash
#output.logstash:
#  hosts: ["localhost:5044"]
#--------------------------------- kafka Output --------------------------------
#输出到kafka(使用时修改对应的kafka机器和topic(topic在kafka创建))
output.kafka:
  hosts: ["*.*.*.*:8422","*.*.*.*:8422","*.*.*.*:8422"]
  topic: yeYingXuanLogTest
  enabled: true
  #username: "yeYingXuan_kafka"
  #password: "**********"

因为我们要看控制台有没有读取到数据,所以这里先不用启动脚本后台执行。

[root@shenyulong filebeat-7.10.0]# ./filebeat -c /yeYingXuan/app/filebeat/filebeat-7.10.0/filebeat.yml -e

查看控制台结果:

可以看到已经读取到了日志数据,证明到此为止filebeat已经配置成功,将输出源改成输出到logstarch。

接下来我们来配置logstarch。


logstarch篇:

下载:

curl -L -O https://artifacts.elastic.co/downloads/logstash/logstash-7.10.0-linux-aarch64.tar.gz

解压:

[root@shenyulong logstash]# tar -zxvf logstash-7.10.0-linux-aarch64.tar.gz

修改文件名

[root@shenyulong logstash]# mv logstash-7.10.0-linux-aarch64.tar.gz logstash-7.10.0

目录:

我这里就只列主要的配置目录config了。

config目录


-rw-r--r--. 1 root wheel  2019 11月 10 2020 jvm.options
-rw-r--r--. 1 root wheel  9097 11月 10 2020 log4j2.properties
-rw-r--r--. 1 root root   1908 5月  29 03:58 logstarch.config
-rw-r--r--. 1 root wheel   342 11月 10 2020 logstash-sample.conf
-rw-r--r--. 1 root wheel 11194 11月 10 2020 logstash.yml
-rw-r--r--. 1 root wheel  3693 11月 10 2020 pipelines.yml
-rw-r--r--. 1 root root   1449 5月  29 03:59 rubyLogParse.rb
-rw-r--r--. 1 root wheel  1696 11月 10 2020 startup.options
-rw-r--r--. 1 root root   1054 5月  29 01:42 templete_log.json

主要的几个文件介绍:

logstarch.config:需要自己创建,作用是配置输入源、输出源、过滤器、格式化日期、调用格式化日志配置。

rubyLogParse.rb:需要自己创建,作用为logstash解析处理日志逻辑的配置文件。

templete_log.json:需要自己创建,作用为入es时候的模板文件。

详细配置:

logstarch.config配置:输入员可以配置为kafka和filebeat,我这里没用kafka,配置为filebeat,配置为kafka为输入源的配置我也写了,因为用不上我这先给注释掉。输出源可以配置为输出到控制台、es,这里输出源2个可以共存

input {
  beats {
    # filebeat的端口是5044,从filebeat里读取数据。
    port => 5044
  }
   #kafka{
   #  id => "kfk43"  #无关键作用,唯一即可
    #kafka机器
   #  bootstrap_servers=>["*.*.*.*:8422,*.*.*.*:8422,*.*.*.*:8422"]
    #从哪个topic获取消息
   #  topics => "yeYingXuanLogTest"
    #消费者名(订阅者topics的消费者)
   #  group_id =>"c_yeYingXuanLogTest"
   #  consumer_threads => 10 #消费线程数,集群中所有logstash相加最好等于 topic 分区数
    #以下3个默认
   #  auto_offset_reset => "latest" 
   #  decorate_events => false 
   #  codec => json {
   #           charset => "UTF-8"
   #       }
   #}
}

filter {
  #执行解析逻辑
  ruby{
     id=>"ls43"
     #指向rubyLogParse.rb 指向解析日志
     path =>"/yeYingXuan/app/logstash/logstash-7.10.0/config/rubyLogParse.rb"
  }

  #格式化日期
  date{
    match=>["requestTime","yyyy-MM-dd HH:mm:ss"]
    target =>"@timestamp"
    locale=>"en"
    timezone =>"+00:00"
  }
  #删除多余字段,减少es的存储空间(不想要哪个字段就在此去除)
  #mutate{
    #  remove_field => ["host","log","ecs","agent","@version","input","message","tags"]
  #}
}

output {
   # 在这里配置 Logstash 要发送数据的地方,例如 Elasticsearch
   stdout { codec => rubydebug } #---》输出到控制台,方便看日志

   elasticsearch{
       codec => plain{charset => "UTF-8"}

       #  %{+YYYY-MM-dd} 和%{+YYYY.MM.dd}都行,具体看你要设置成什么样
       index => "yeyingxuan-farmlog-%{+YYYY-MM-dd}" #字母大写会报错

       #es机器
       hosts => [ "http://localhost:9200" ]
       manage_template => true #开启logstash自动管理模板功能
       template_overwrite => true
       #模板名,取的是templete_log.json 文件里的"index_patterns" : ["yeYingXuan*"]
       template_name => "yeYingXuan"
       #指向模板文件路径
       template => "/yeYingXuan/app/logstash/logstash-7.10.0/config/templete_log.json"
       #es用户名/密码(es如果没有设置用户名可以不写)
       user => "elastic"
       password => "*******"
   }
}

rubyLogParse.rb配置:

#解析日志(event.set是最终展示的结果,logdata是采集到的日志)
def farmLog(event,logdata)
  #根据%分割日志(1.url 2.请求时间 3.用户id 4.农场id 5.请求报文 5.返回报文)
  log = logdata.split("%")
  #打印log
  # print "#{log[1]}"  #控制台输出
  #获取接口url
  urlArray = log[1].split(":")
  event.set("url", urlArray[1])
  #获取用户id
  userIdArray = log[3].split(":")
  event.set("userId", userIdArray[1])
  #获取农场id
  farmIdArray = log[4].split(":")
  event.set("farmId", farmIdArray[1])
  #获取请求报文
  reqMessageArray = log[5].split(":")
  event.set("reqMessage", reqMessageArray[1])
  #获取返回报文
  respMessageArray = log[6].split(":")
  event.set("respMessage", respMessageArray[1])
end



def filter(event)
  #取出日志信息(就当这里是固定的,取'message'就能取到日志)
  logdata=event.get('message')
  # print "------打印logdata------ #{logdata}"
  #如果日志不是短信日志,缓存监控日志,缓存日志 Access nodechanged
  #解析日志级别和请求时间,并保存到event对象中
  # logleve=logdata[(logdata.index('[')+1)...logdata.index(']')]
  # event.set('logleve',logleve)#截取日志级别
  # event.set('requestTime',logdata[0,logdata.index(' - [')])
  #我这里只取日志里包含'farmLog'的日志数据。
  if(logdata.include?'farmLog')
    #执行解析接口逻辑
    farmLog event,logdata
  end
  return [event]
end

templete_log.json配置:配置入es时候的字段类型。

{
    "index_patterns": [
        "yeYingXuan*"
    ],
    "settings": {
        "index": {
            "max_result_window": "10000",
            "refresh_interval": "10s",
            "number_of_shards": "5",
            "translog": {
                "flush_threshold_size": "500m",
                "sync_interval": "5s",
                "durability": "async"
            },
            "number_of_replicas": "1"
        }
    },
    "mappings": {
        "properties": {
            "host_name": {
                "type": "keyword"
            },
            "requestTime": {
                "type": "date",
                "format": "yyyy-MM-dd HH:mm:ss"
            },
            "userId": {
                "type": "integer"
            },
            "farmId": {
                "type": "integer"
            },
            "url": {
                "type": "keyword"
            },
            "reqMessage": {
                "type": "keyword"
            },
            "respMessage": {
                "type": "keyword"
            }
        }
    }
}

启动:

[root@shenyulong logstash-7.10.0]# bin/logstash -f config/logstarch.config

因为配置了输出源为控制台,这里我们验证下是否配置成功,可以看到已经成功的解析了我们日志数据。


下面为了节省时间,就直接下载docker镜像了

ES下载:

docker pull docker.elastic.co/elasticsearch/elasticsearch:8.3.2

启动:

docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" -e "ELASTIC_PASSWORD=changeme" docker.elastic.co/elasticsearch/elasticsearch:8.3.2

启动后请求路径:https://*.*.*.*:9200/

用户名:elastic

密码:******

获取Elasticsearch容器的IP地址:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' elasticsearch

检查Elasticsearch的健康状态:

curl -k -u elastic:changeme -X GET "https://localhost:9200/_cluster/health"

 HTTPS 改为 HTTP,需要禁用 HTTP 和传输层的 SSL。

进入容器
[root@shenyulong ~]# sudo docker exec -it a39909d75826 /bin/bash
elasticsearch@a39909d75826:~$
elasticsearch@a39909d75826:~$ vi config/elasticsearch.yml

因为开启ssl的话启动Kibana的时候会校验证书,这里为了方便,先将配置ssl禁用,这4处改为false

重启容器

[root@shenyulong ~]# docker restart a39909d75826

安装Kibana:

[root@shenyulong ~]# docker pull docker.elastic.co/kibana/kibana:8.3.2

运行容器:

[root@shenyulong ~]# docker run -d --name kibana -p 5601:5601 -e "ELASTICSEARCH_HOSTS=http://localhost:9200" docker.elastic.co/kibana/kibana:8.3.2

启动成功后访问:http://*.*.*.*:5601

可以看到我们日志数据已经成功的插入到了es中。

  • 15
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值