使用ELK收集nginx日志
一、工具简介
“ELK”是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch、Logstash 和 Kibana。
- Elasticsearch 是一个搜索和分析引擎。
- Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。
-
Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。
-
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
- Filebeat是一个轻量级的日志收集系统,能够监视指定的日志存放的目录或文件,有更新就自动收集并且发送给logstash或者ES服务器。
二、Centos安装docker
-
移除旧的版本:
sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine
-
安装一些必要的系统工具:
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
-
添加软件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
-
更新 yum 缓存
sudo yum makecache fast
-
安装 Docker-ce
sudo yum -y install docker-ce
-
启动 Docker 后台服务
sudo systemctl start docker
-
测试运行 hello-world
docker run hello-world
三、配置与验证 (elasticsearch运行需要至少2G内存)
-
修改配置文件
vim /etc/sysctl.conf
-
添加或者修改
vm.max_map_count = 262144
使生效
sysctl -p
-
服务安装与运行
安装ELK有很多种方式,比如源码、rpm包,或docker;不过docker又分为了单个安装与ELK打包安装,我们通过docker打包安装,因为这样的方式相比来说最为简单,因为只需要下载镜像,然后运行起来就可以了
- 镜像下载获取获取
-
设置好加速地址之后,就可以开始拉取ELK镜像,参考命令如下
docker pull sebp/elk
-
下载镜像之后可以使用docker的命令来验证是否成功,参考命令如下
docker images
-
执行后docker返回结果如下
REPOSITORY TAG IMAGE ID CREATED SIZE sebp/elk latest 99e6d3f782ad 2 months ago 2.06GB hello-world latest fce289e99eb9 11 months ago 1.84kB
-
- 容器运行
运行此容器的时候,需要将宿主机的端口转发到该容器,其中ES端口为9200,kibana端口为5601,logbate端口为5044;
由于 docker 镜像是只读的,而容器又是随时创建删除,所以建议将配置文件和数据存放在宿主机,便于后期维护,因此还需要将宿主机目录挂载到容器当中。
# 先在宿主机创建挂载目录
cd /opt
mkdir elk-data
cd elk-data
mkdir conf
mkdir elasticsearch-data
mkdir logs
# 编辑nginx配置文件
vim /usr/local/nginx/conf/nginx.conf
- 配置 nginx
下面是 nginx.conf 的配置内容
#user root;
worker_processes 1;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# 对日志格式化成json
log_format json '{"@timestamp":"$time_iso8601",'
'"@version":1,'
'"host":"$server_addr",'
'"client":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,'
'"domain":"$host",'
'"url":"$uri",'
'"status":"$status"}';
# 用于记录谁在什么时候做了什么
access_log /opt/elk-data/logs/access.log json;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
# proxy_pass http://127.0.0.1:8000
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
-
测试 nginx 文件配置的正确性
/usr/local/nginx/sbin/nginx -t
`出现下面这两行代码说明正确
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
- logstash配置
logstash配置主要有三个地方要处理,首先是输入源在什么位置,然后是对数据进行过滤或者格式化,最后是需要将数据输出到什么地方;在下方的配置只做了其中两项,编辑配置文件命令参考如下
-
修改宿主机刚才挂载的目录,在目录下创建conf目录,建立test.conf文件
` vim /opt/elk-data/conf/test.conf`
-
下面是 test.conf 的配置内容
input { file { path => "/opt/logs/access.log" # 填写容器内部log文件路径 codec => "json" } } output { elasticsearch { hosts => ["127.0.0.1:9200"] } stdout { codec => rubydebug } } input { file { path => "/opt/logs/access.log" # 填写容器内部log文件路径 codec => "json" } } output { elasticsearch { hosts => ["127.0.0.1:9200"] } stdout { codec => rubydebug } }
- 启动logstash
前面已经将日志格式与logstash配置好,现在需要启动logstash开始收集日志,logstash挂载到容器内,需要先启动容器
# 开启三个端口传递信息,挂载主机的三个路径下的所有文件,给容器重命名为elk,镜像为sebp/elk
docker run -p 5601:5601 -p 9200:9200 -p 5044:5044 -v /opt/elk-data/conf:/opt/conf -v /opt/elk-data/logs:/opt/logs -v /opt/elk-data/elasticsearch-data:/var/lib/elasticsearch -it -d --name elk sebp/elk
-
启动logstash之前需要先进入容器里面,进入容器参考命令如下:
docker exec -it elk /bin/bash
-
删除02-beats-input.conf 关于ssl的三行设置,否则客户端需要另外配置证书相关配置项(重新创建容器都需要删除这三行设置)
vim /etc/logstash/conf.d/02-beats-input.conf
-
需要关闭自动开启的 logstash,检查logstash,elasticsearch状态,保持elasticsearch开启,logstash关闭
service logstash stop
-
进入容器之后,需要启动logstash来收集数据,启动的时候需要带两个参数进去,第一个是logstash的数据暂存位置,第二个是使用的配置文件,因此构造的命令如下所示:
# 如果配置文件有改动会自动加载
` /opt/logstash/bin/logstash -f /opt/conf/test.conf –config.reload.automatic `
-
另起一个窗口请求nginx:
curl localhost:80
四、绘图配置与展示
当数据导入之后,才可以使用kibana的图形化来查看数据了,所以首先确认一下ES中是否有数据,确认有数据后就可以进行绘图配置,配置完成之后就可以进行筛选日志等操作了。
-
ES数据检查
数据添加到ES服务器当中后,可以通过ES服务提供的URL来查看其中的数据,URL地址如下所示:
http://localhost:9200/_search?pretty
就会看到刚刚产生的日志内容,当看到total数量变大,并在下面的数据项中看到了nginx日志信息时,则代表导入数据成功了。
-
kibana索引配置
通过浏览器访问kibana,URL地址如下
http://127.0.0.1:5601/app/kibana#/management/kibana/index?_g=()
-
点击左侧导航栏的Discover,便可进入创建索引模式界面,可以选择索引查看相对应数据
-
点击左侧导航栏的Management链接,点击页面Index Pattern链接,点击右上方Create index pattern,方框里面输入你创建的索引名字,点击Next step便创建kibana的索引完成,此时再次点击左侧导航栏的Discover链接,便可以看到刚才创建索引的一些视图,数据。
-
在图中有一个input输入框,可以在里面填写筛选所需要的关键词;如果没有筛选出结果,也可检查左侧的时间筛选项是否设置正确,默认显示最近十五分钟产生的数据 。
此处有对应的数据,说明收集成功。
五、filebeat客户端配置
filebeat 是用来转发和集中日志数据的轻量级服务。能监视指定的日志文件和位置。收集日志文件,并将它们转发到logstash或elasticsearch
另装一个虚拟机作为客户端,上面的docker,logstash作为服务器。
部署流程:
-
客户端配置
# filebeat文件配置:filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /usr/local/nginx/logs/access.log # 指定需要收集的日志文件的路径 fields: indexname: nginx-access fields: host_ip: ip #发送本机出口ip,便于服务器端方便筛选 output.logstash: hosts: ["ip:port"] #指定日志服务器的ip:port
-
nginx文件配置(部分配置:json格式化,log存储路径)
/usr/local/nginx/conf/nginx.conf
log_format json '{"@timestamp":"$time_iso8601",' '"@version":1,' '"host":"$server_addr",' '"client":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_time,' '"domain":"$host",' '"url":"$uri",' '"status":"$status"}'; access_log /usr/local/nginx/logs/access.log json;
-
nginx改了配置需要重启下:
/usr/local/nginx/sbin/nginx -s reload
-
-
服务器端配置
# logstash文件配置: input { beats { port => 5044 # 设置专用端口用于接收各个来源的日志 } } output { elasticsearch { index => "log_%{+YYYY.MM.dd}" hosts => ["127.0.0.1:9200"] # 发送到本机的elasticsearch上 } stdout { codec => rubydebug } }
-
客户端启动nginx,filebeat 收集日志,服务端启动logstash,发送并展示日志信息
-
重启启动nginx(如果修改过nginx配置文件,需要重启后再启动)
-
发起请求 :curl localhost:80
-
启动成功后查看日志文件中是否收集到日志
[root@localhost filebeat-7.4.0-linux-x86_64]# cat /usr/local/nginx/logs/access.log {"@timestamp":"2019-12-26T09:22:51+08:00","@version":1,"host":"127.0.0.1","client":"127.0.0.1","size":612,"responsetime":0.000,"domain":"localhost","url":"/index.html","status":"200"}
-
客户端启动 filebeat
./filebeat -e -c filebeat.yml -d "publish"
-
服务端启动logstash
/opt/logstash/bin/logstash -f /opt/conf/logstash.conf --config.reload.automatic
-
查看kibana,确认ES是否收集到
-
filebeat 日志分类,logstash过滤
# nginx.conf配置 user nobody; worker_processes 1; error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #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 logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; log_format json '{"@timestamp":"$time_iso8601",' '"@version":1,' '"host":"$server_addr",' '"client":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_time,' '"domain":"$host",' '"url":"$uri",' '"status":"$status"}'; access_log /usr/local/nginx/logs/access.log json; error_log /usr/local/nginx/logs/error.log; server { listen 80; server_name localhost; \#charset koi8-r; \#access_log logs/host.access.log main; location / { root html; index index.html index.htm; } \#error_page 404 /404.html; \# redirect server error pages to the static page /50x.html \# error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
filebeat.yml配置: filebeat.inputs: - type: log enabled: true paths: - /usr/local/nginx/logs/access.log # 指定需要收集的日志文件的路径 fields: indexname: nginx-access - type: log enabled: true paths: - /usr/local/nginx/logs/error.log # 指定需要收集的日志文件的路径 fields: indexname: nginx-error fields: host_ip: ip #发送本机出口ip,便于服务器端方便筛选 output.logstash: hosts: ["ip:5044"] #指定日志服务器的ip:port
# logstash.conf配置: input { beats { port => 5044 } } filter { mutate { rename => { "[host][name]" => "host" } } if [fields][indexname] == "nginx-error" { grok { match => { "message" => "%{DATESTAMP:datetime}\s+\[%{LOGLEVEL:loglevel}\]\s+%{GREEDYDATA:error_reason}" } } } else if [fields][indexname] == "nginx-access" { grok { match => { "message" => "%{NGINXACCESS}" } } } date { match => [ "timestamp", "YY/MM/dd HH:mm:ss","YYYY-MM-dd HH:mm:ss", "dd/MMM/YYYY:HH:mm:ss Z" ] } mutate { remove_field => ["host", "tags", "@version", "type"] } } output { elasticsearch { action => "index" index => "log_%{+YYYY.MM.dd}" hosts => ["127.0.0.1:9200"] } stdout { codec => rubydebug } }
-
服务端logstash启动:
/opt/logstash/bin/logstash -f /opt/conf/logstash.conf --config.reload.automatic
-
客户端filebeat启动:
./filebeat -e -c filebeat.yml -d "publish"
-
logstash收集并打印出日志:
-
-
kibana显示:
六、常见错误总结及解决方法
- 启动 nginx 后 access.log 收集不到日志
修改配置文件后记得重启才能生效 : /usr/local/nginx/sbin/nginx -s reload
- CentOs的系统时间和本地网络时间不一致(多八小时)
需要配置成NTP同步状态:
-
使用 date 命令,查看系统时间和当前时间是否一致,如果不一致,就需要使用ntp同步标准时间,ntp:网络时间协议(network time protol)
安装:yum install ntp
同步:ntpdate pool.ntp.org
-
使用timedatectl查看是否同步
[root@localhost ~]# timedatectl Local time: Tue 2019-12-24 16:37:04 CST Universal time: Tue 2019-12-24 08:37:04 UTC RTC time: Tue 2019-12-24 16:37:04 Time zone: Asia/Shanghai (CST, +0800) NTP enabled: yes NTP synchronized: yes RTC in local TZ: yes DST active: n/a
-
查看下面三个是否都是yes,如果缺了就使用下面的命令:
NTP enabled: yes
timedatectl set-ntp on
NTP synchronized: yes
将当前时间和日期写入BIOS,避免重启后失效
hwclock -w
timedatectl set-local-rtc 1
- Logstash收集不到日志数据
-
原因1: 新建容器,进入容器后忘了删除ssl的三行配置
解决:删除ssl的三行配置(上文有步骤)
-
原因2: 日志文件没有更新,日志读取的偏移量没有改变,所以认为没有新的日志,就不进行新的收集
解决:可以在logstash.conf中新增两行代码
input { file { path => ["/logs/access.log"] start_position => "beginning" # 从头读文件 sincedb_path => "/dev/null" # 偏移量放入Linux黑洞中,所以# 永远从头开始读文件 } }