简单的ELK搭建

1. 前言

针对nginx的访问日志需要进行一个近实时的监控,以便统计用户的访问情况,包括用户的请求IP,请求数据等。因为服务器是和负载均衡用的是阿里云的,阿里云本身也有提供针对负载均衡的日志统计功能,但是作为一个通用日志其是有严重缺陷的:

  • 无法收集用户自定义的请求头(我们的实际情况是通过一个自定义的请求头来做用户的身份识别,请求头有用户的唯一识别信息
  • 无法获取到用户的请求数据($request_body) (很多时候,当出现异常访问的时候,是需要通过查询用户的访问数据的,特别像搜索这种业务模块时

由于存在上面比较严重的缺点,基本上阿里云的日志对我来说就有点鸡肋(食之无味,弃之可惜,你不得不同意他除了上面两点缺点外,日志的其他方面都是做得不错的)。因此我决定自己动手搭建符合自己业务的ELK日志服务。

之前我是有搭建过ELK的经验的,但是没在生产环境试过,起初在搭建的时候我考虑到可能会有以下几个问题:

  1. Elasticsearch对内存的占用情况
  2. 收集nginx访问日志,相当于需要打开nginx的access日志开关,硬盘的读写情况,硬盘的占用,会不会影响到用户。
  3. 日志收集对应用服务器的影响

我现在还是在一两台服务器开启了日志收集,做一个灰度测试。

2. Elasticsearch搭建

2.1 Elasticsearch下载安装

Elasticsearch的安装比较简单,直接下载解压缩即可

  • 官网地址:https://www.elastic.co/cn/downloads/elasticsearch
### 下载
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.4.2-linux-x86_64.tar.gz

### 解压缩:
tar -zxvf elasticsearch-7.4.2-linux-x86_64.tar.gz

2.2 Elasticsearch配置

1. 修改cluster-name和node-name

cluster.name: my-application
node.name: node-1
node.master: true
node.data: true

2. 修改网络相关

network.host: 0.0.0.0  ## 0.0.0.0允许所有的ip,这里我是为了方便,后面可以根据实际情况填写
http.port: 9200  ## default
transport.tcp.port: 9300  ## defalut
在这里插入图片描述

3. 修改head插件的跨域问题

# 以下的两个配置是为了解决跨域问题,在head插件访问es的时候报跨域了
http.cors.enabled: true
http.cors.allow-origin: "*"

4. 发现配置

# Pass an initial list of hosts to perform discovery when this node is started:
# The default list of hosts is ["127.0.0.1", "[::1]"]
discovery.seed_hosts: ["192.168.1.57"]  ## 可被发现的节点IP集合
cluster.initial_master_nodes: ["node-1", "node-2"]

5. 解决es启动时的报错问题,.ElasticSearch集群启动错误,错误的原因是:因为Centos6不支持SecComp,而ES默认bootstrap.system_call_filter为true进行检测,所以导致检测失败

bootstrap.memory_lock: false
bootstrap.system_call_filter: false

2.3 问题

1. 外网访问不了9200的Elasticsearch?

  1. 配置防火墙端口
  2. 修改elasticsearch.yml,主要是要修改host(我改成0.0.0.0,方便调试,后期稳定之后会再修改)

2. 启动报错

  • vm.max_map_count过小,java虚拟机的virtual memory过小

在/etc/sysctl.conf最后加入一行vm.max_map_count=262144数量根据实际情况定


在这里插入图片描述
  • max user threads过小(root和dves两个用户的max user threads不一样)

针对这个问题,可以通过ulimit -a查看目前可支持的max user threads

在这里插入图片描述

修改 max user process

Linux系统为每一个用户都设置了一个最大进程数,这个特性可以让我们控制服务器上现有用户可以创建的进程数量

  1. 修改方式1:

修改/etc/security/limits.conf文件,添加以下配置

## 针对所有用户的可开启最大线程数为4096
*  soft      nproc      4096
*  hard      nproc      4096
  1. 修改方式2:

修改/etc/security/limits.d/90-nproc.conf文件,添加以下配置(先把其他默认的给注释掉):

*          soft    nproc     4096  ## 非root用户配置为4096,这个对es来说够用了
root       soft    nproc     unlimited  ## root用户配置最大 128354

针对这两种修改方式解释下,我是在 /etc/security/limits.d/90-nproc.conf这个文件下修改的。对于max user process的配置,Linux系统默认先读取/etc/security/limits.conf中的信息,如果/etc/security/limits.d/目录下还有配置文件的话,也会依次遍历读取,最终/etc/security/limits.d/的配置会覆盖/etc/security/limits.conf的相同配置信息

3. FileBeat搭建

3.1 Filebeat下载安装

curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.4.2-x86_64.rpm

rpm -vi filebeat-7.4.2-x86_64.rpm

安装完成,filebeat命令已配置到service服务中,配置文件在/etc/filebeat,日志文件在/var/log/filebeat/filebeat,注意,每次重启filebeat的时候,该日志文件都会重新生成,这个时候若如果你是通过tail命令来观察的,需要结束当前的tail命令再重复执行一次tail命令 tail -900f filebeat

3.2 Filebeat收集nginx访问日志

3.2.1 nginx的访问日志格式及配置

nginx访问日志是如何配置的,我这里不细说,我只是说下我是如何配置的,如果对nginx的访问日志配置不熟悉的,可以查看这个:ngx_http_log_module

1. 日志格式

因为我们最终要通过Kibana进行展示的,我们需要对访问日志的每个字段都进行解析,所以我们就需要确定nginx的日志是json格式的

## 这个是写在http模块的
log_format json_main  '{"@times" : "$time_iso8601",' ## 该time作为Kibana的date类型,在创建Kibana的index_pattern时作为时间筛选的key
                        '"userAgent" : "$http_user_agent",'
                        '"remoteAddr" : "$remote_addr", '
                        '"realIp" : "$http_x_forwarded_for", '
                        '"requestUri" : "$request", '
                        '"status" : "$status", '
                        '"referer" : "$http_referer", '
                        '"requestTime" : "$request_time", '
                        '"requestBody" : "$request_body", '  ## 请求数据
                        '"domoCustom" :  "$http_domo_custom"}';  ## 自定义请求头
2. 打开请求日志

对map模块有兴趣的可以查看这里:ngx_http_map_module

## 这个在server模块
access_log /opt/nginx/logs/requestLog.log  json_main  if=$myUri;

## /opt/nginx/logs/requestLog.log:这个是日志收集的地方,若该日志不存在,在reload或重启nginx的是,会自动创建
## json_main:`log_format`定义的日志格式名
## if=$myUri:一个判断,如果`$myUri`为0或者空字符串,则该日志不收集。这个的作用可以过滤掉一些我们不想收集的日志信息,我是根据请求头来设置的。

## 这个写在http模块,使用map这个内置模块,可以通过判断`$request`这个
## 内置变量是否符合下面的判断,然后把0或1赋值给`$myUri`.
## 这里我的用法就是,如果是OPTIONS请求为0不记录日志信息,
## 如果是`/api/qiqyu`这个第三方的请求也为0不记录日志信息
## 其他的`/api/`正则的则为1记录日志信息
## 非上面集中情况的一律为0不记录相应的日志信息
 map $request $myUri {
       ~OPTIONS 0;
       ~/api/qiyu/ 0;
       ~/api/ 1;
       default 0;
  }

reloadnginx之后就能在/opt/nginx/logs/requestLog.log这个文件夹下看到相应的日志了

在这里插入图片描述

3.3 Filebeat配置

3.3.1 基本配置文件配置

在这里插入图片描述
vim /etc/filebeat/filebeat.yml 
1. Filebeat inputs
- type: log

  # Change to true to enable this input configuration.
  enabled: true  ## 打开开关
  exclude_lines: ['^DBG']  ## 忽略的行
  # Paths that should be crawled and fetched. Glob based paths.
  paths:
    #- /var/log/*.log
    - /opt/nginx/logs/requestLog.log  ## 配置从哪里按行读取日志
        #- c:\programdata\elasticsearch\logs\*
  ## 如果要让filebeat输入json格式的数据,除了nginx的日志本身是json格式
  ## 的外,还必须在filebeat中配置一下设置
  json.keys_under_root: true
  json.overwrite_keys: true
  json.add_error_key: true
  json.message_key: message  ## 如果message在启动的时候报错,可以改成"json"(带双引号)  
2. Elasticsearch template setting
setup.ilm.enabled: false  ## 这个必须要配置成false,否则自定义index就不会生效
setup.template.enabled: false  ## 关掉filebeat默认的es模板
setup.template.overwrite: true ## 表示我们自定义的模板和index会覆盖默认的
setup.template.fields: "/etc/filebeat/self/fields.yml"  ## 自定义的fields.yml,这个文件不熟悉的话就别瞎折腾了,我直接从原来的copy了一份而已
setup.template.name: "nginx-access-log"  ## 模板名,这个和后面要创建的es模板名保持一致
setup.template.pattern: "nginx-access-log-*"  ## 模板对应的pattern,也是对应的index,这些都是有规律的。因为你模板名是`nginx-access-log`,则你接下来的自定义索引名就最好是`nginx-access-log-%{[agent.version]}-%{+yyyy.MM.dd}`,pattern的正则就是`nginx-access-log-*`
3. Dashboards(这个配置可不配,主要是看你的filebeat是否安装了默认看板,这个安装后会生效的前提是:你必须使用filebeat的默认模板,默认索引,一旦你执行了上面第二步,这里的配置就不会生效)
setup.dashboards.enabled: true
setup.dashboards.index: "nginx-access-log-*"
4. Kibana
setup.kibana:
  host: "192.168.1.57:5601"
  # Kibana Host
  # Scheme and port can be left out and will be set to the default (http and 5601)
  # In case you specify and additional path, the scheme is required: http://localhost:5601/path
  # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
  #host: "localhost:5601"
5. Outputs(Elasticsearch)
#-------------------------- Elasticsearch output ------------------------------
output.elasticsearch:
  # Array of hosts to connect to.
  hosts: ["192.168.1.57:9200"]
  ## 这里的index的前缀要和上面第二步配置的模板名保持一致,而且,index的名字中不能包含大写字母,这是我的教训来着
  index: "nginx-access-log-%{[agent.version]}-%{+yyyy.MM.dd}"
  # Optional protocol and basic auth credentials.
  #protocol: "https"
  #username: "elastic"
  #password: "changeme"

3.3.2 启用nginx模块

其实对于filebeat中,它提供了多个模块,比如nginx,mysql等,这些能够让我们快速地上手filebeat。但是我一直搞不懂这些模块的用途是什么,明明我可以在filebeat.yml中配置的。nginx的模块格式如下:

我虽然安装了该模块,但是该模块我是关掉的,一方面是我对该模块的理解不够,我不启用该模块也能正常收集日志,另一方面,开启该模块的时候,在收集日志的时候会不定时地报错Provided Grok expressions do not match field value:

# Module: nginx
# Docs: https://www.elastic.co/guide/en/beats/filebeat/7.4/filebeat-module-nginx.html

- module: nginx
  # Access logs
  access:
    enabled: false
    var.paths: ["/opt/nginx/logs/requestLog.log"]

   # Set custom paths for the log files. If left empty,
    # Filebeat will choose the paths depending on your OS.
    #var.paths:

  # Error logs
  error:
    enabled: false

    # Set custom paths for the log files. If left empty,
    # Filebeat will choose the paths depending on your OS.
    #var.paths:
安装过程

在配置好filebeat.ymt后执行如下命令:

filebeat modules enable nginx

3.3.3 启动filebeat模块

filebeat setup
service filebeat start

4. Kibana搭建

4.1 Kibana下载安装

注意:如果es是7版本,那么kibana的版本也要是7,两者之间的大版本要互相对应

wget https://artifacts.elastic.co/downloads/kibana/kibana-7.4.2-linux-x86_64.tar.gz

## 解压缩后即可使用
tar -zxvf kibana-7.4.2-linux-x86_64.tar.gz

4.2 Kibana配置

vim kibana.yml
## 端口号,默认5601
#server.port: 5601
## 指定kibana指定的IP
server.host: "192.168.1.57"
## 因为我的kibana和Elasticsearch是在同一台机器上的,所以我不需要去配置es的IP和端口等信息,kibana会自动在本机寻找
#elasticsearch.hosts: ["http://localhost:9200"]

4.2.1 自定义Elasticsearch的template

这个template_nameindex_patterns要和前面我们在Elasticsearch中配置的一致。除了template_nameindex_patterns要修改外,还有一个要修改的地方就是mapping,这个因人而异,我觉得默认的mapping输出太多我不需要用到的东西,所以才去简化的,其余的都保持默认。新建好template后重启filebeat即可。重启filebeat之前建议把nginx的访问日志也清空掉,免得有脏数据影响

mapping信息:
{
  "_meta": {
    "beat": "filebeat",
    "version": "7.4.2"
  },
  "dynamic_templates": [
    {
      "labels": {
        "path_match": "labels.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "container.labels": {
        "path_match": "container.labels.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "dns.answers": {
        "path_match": "dns.answers.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "fields": {
        "path_match": "fields.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "docker.container.labels": {
        "path_match": "docker.container.labels.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "kubernetes.labels.*": {
        "path_match": "kubernetes.labels.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "*"
      }
    },
    {
      "kubernetes.annotations.*": {
        "path_match": "kubernetes.annotations.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "*"
      }
    },
    {
      "docker.attrs": {
        "path_match": "docker.attrs.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "cef.extensions": {
        "path_match": "cef.extensions.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "kibana.log.meta": {
        "path_match": "kibana.log.meta.*",
        "mapping": {
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    },
    {
      "strings_as_keyword": {
        "mapping": {
          "ignore_above": 1024,
          "type": "keyword"
        },
        "match_mapping_type": "string"
      }
    }
  ],
  ## 这里是指是否要指定一个key作为date类型来进行时间筛选,如果不为true,
  ## 后面你就无法根据@times进行时间筛选
  "date_detection": true
}
在这里插入图片描述
在这里插入图片描述

4.2.2 devtool工具查询

在未建立kibana的index_pattern之前,我们是无法在discover发现面板上去查看自己的数据的,这个时候我们并不着急去创建index_pattern,我们要先验证一下日式数据是否已成功收集。打开kibana的dev tool

在这里插入图片描述
1. 查看目前es中的索引,确认我们的自定义索引是否已生成
get _cat/indices?v

这个索引出现了表明索引已自动生成了


在这里插入图片描述
2. 查看该索引目前的数据,是否符合我们预期
GET /nginx-access-log-7.4.2-2019.11.18/_search

数据结果是json格式的,而且我们需要的数据都有,符合我们的预期。


在这里插入图片描述

4.2.3 自定义index_pattern

在上面的步骤确认好之后,就可以创建kibana的index_pattern

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2.3 Discover功能

选择刚我们创建的index_pattern就可以看到和我们index_pattern格式相对应的数据了

在这里插入图片描述

4.2.4 Visualize功能

新建一个可视化的图表,它里面帮我们内嵌了多个图表,但数据源都不是我们自定义的数据,可以参考,但是没多大意义,我们可以自己创建。


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2.5 Dashboard功能

多个 Visualize放在一起就是一个面板,这里不多赘述,没什么技术含量

5. 参考链接

开始使用Filebeat
快速开始Elasticsearch
Es的官网教学
自定义index template
Filebeat自定义index的一个坑
Filebeat模块与配置
Linux修改max user threads
ElkStack运维手册
Es中文手册
nginx中文地址

6. 总结

搭建这个简单的ELK还是花费了我一些时间的,一方面主要是我太久没接触ES,另一方面我对filebeat和kibana一直都是一知半解的状态。在搭建的过程中,没有像我上面写得那么顺利,一路磕磕碰碰,遇到很多问题,最后通过查询大量资料加上自己的理解才终于搞定。大家如果在搭建的时候有不明白的可以直接联系[email protected]这个邮箱

你可能感兴趣的:(简单的ELK搭建)