[toc]php
早期咱们一般会使用goaccess或awstat来对nginx等访问日志进行分析和统计,但随着统计分析的多样性以及后续访问日志的实时监控等定制化的需求愈来愈强烈,goaccess或awstat愈来愈不能知足咱们的需求.因此咱们急迫须要更加灵活的日志统计分析工具,能辅助咱们对访问日志进行统计、分析和监控.这时候,随着elk/efk的普遍应用,nginx等访问日志也将归入到elk体系当中,同时elk也能知足咱们对日志的统计与分析、监控的多样化需求.
先上图
nginx
如图,如下是1个很简单的架构,也没有作缓冲和聚合,若是对日志的要求比较高,能够在中间加入redis或Kafka 等.redis
为何ingress或者nginx的日志要转换成json格式呢?
我这边简单的解释一下:,主要是2个缘由:
1:便于结合elasticseach作实时监控和报警.
好比直接监控status字段,若是1分钟连续出现20次4XX报错就直接报警,若是不转换的化,你还须要进一步解析access日志,这样带来了不少的不便.
2:便于结合elk作可视化分析.
能够组合不一样的字段,对不一样的需求定制不一样的可视化报表.json
ingress部署参考: https://www.pvcreate.com/index.php/archives/205/ vim
kubectl apply -f ingress-nfs.yaml
segmentfault
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ingress-nfs spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: nfs-client-local
kubectl edit deployments.apps ingress-nginx-controller
后端
...... volumeMounts: - mountPath: /data/log/ingress/ name: ingress-nfs ...... volumes: - name: ingress-nfs persistentVolumeClaim: claimName: ingress-nfs
kubectl edit configmaps ingress-nginx-controller
api
access-log-path: /data/log/ingress/access_$hostname.log error-log-path: /data/log/ingress/error.log log-format-upstream: '{"@timestamp": "$time_iso8601","remote_addr": "$remote_addr","x-forward-for": "$proxy_add_x_forwarded_for","request_id": "$req_id","remote_user": "$remote_user","bytes_sent": $bytes_sent,"request_time": $request_time,"status": $status,"vhost": "$host","request_proto": "$server_protocol","path": "$uri","request_query": "$args","request_length": $request_length,"duration": $request_time,"method": "$request_method","http_referrer": "$http_referer","http_user_agent": "$http_user_agent","upstream-sever":"$proxy_upstream_name","proxy_alternative_upstream_name":"$proxy_alternative_upstream_name","upstream_addr":"$upstream_addr","upstream_response_length":$upstream_response_length,"upstream_response_time":$upstream_response_time,"upstream_status":$upstream_status}'
因为阿里云kubernetes上的ingress默认已经部署,同时官方也是建议使用AliyunLogConfig自动接入日志服务和可视化.咱们考虑到自定义以及其余缘由,采用了自定义接入ingress日志存储,也就是说将ingress存储到nas中,同时发送到elasticsearch中.架构
kubectl edit deployments.apps -n kube-system nginx-ingress-controller
并发
... volumeMounts: - mountPath: /data name: nfs-oss ... volumes: - name: nfs-oss persistentVolumeClaim: claimName: ingress-log
kubectl edit configmaps ingress-nginx-controller
修改内容和上面自建kubernetes的ingress一致,须要注意的是若是ingress的日志路径定义为/data/log/ingress/access.log
,必定要注意挂载的目录要存在,也就是说你在修改configmaps以前要确保/data/log/ingress
提早建立,能够进入pod中建立,也能够在外部建立好.
除了ingress之外,若是你的nginx也须要同步推送到elasticsearch中的话,也须要修改nginx的日志格式为json,值得注意的是有部分参数ingress和nginx是不一致的,好比ingress中支持req_id而nginx中没有该参数.同时如下参数是添加到nginx.conf的http全局参数当中,添加在server段中无效的. vim nginx.conf
log_format json '{"@timestamp": "$time_iso8601","remote_addr": "$remote_addr","x-forward-for":"$proxy_add_x_forwarded_for","remote_user": "$remote_user","bytes_sent":$bytes_sent,"request_time": $request_time,"status": $status,"vhost": "$host","request_proto":"$server_protocol","path": "$uri","request_query": "$args","request_length": $request_length,"duration":$request_time,"method": "$request_method","http_referrer": "$http_referer","http_user_agent":"$http_user_agent","upstream_addr":"$upstream_addr","upstream_response_length":$upstream_response_length,"upstream_response_time":$upstream_response_time,"upstream_status":"$upstream_status"}'; access_log /data/log/nginx/access.log json;
filebeat的安装很简单,这边就不作赘述,我这边主要贴下filebeat的配置文件. filebeat.yml
setup.template.name: "local-app" setup.template.pattern: "local-app-*" setup.template.enabled: true setup.ilm.enabled: false filebeat.config: inputs: path: /data/www/apps/filebeat/inputs.d/*.yml reload.enabled: true reload.period: 10s modules: path: /data/www/apps/filebeat/modules.d/*.yml reload.enabled: false output.elasticsearch: protocol: "https" ssl.verification_mode: none hosts: ['192.168.1.100:9200'] username: "elastic" password: "123456" index: "local-app-%{[fields.appName]}-%{+yyyy.MM.dd}"
nginx_ingress.yml
- type: log enable: true tail_files: true # 若是设置为true,Filebeat从文件尾开始监控文件新增内容,把新增的每一行文件做为一个事件依次发送, # 而不是从文件开始处从新发送全部内容 paths: - /data/log/nginx/access*.log tags: [app, nginx-local] fields: appName: nginx-local json.keys_under_root: true #keys_under_root可让字段位于根节点,默认为false json.overwrite_keys: true #对于同名的key,覆盖原有key值 json.message_key: message #message_key是用来合并多行json日志使用的,若是配置该项还须要配置multiline的设置,后面会讲 json.add_error_key: true #将解析错误的消息记录储存在error.message字段中 json.ignore_decoding_error: true #用于指定是否JSON解码错误应该被记录到日志中。若是设为true,错误将被记录
要注意的是,若是配置了multiline,会开启合并多条json日志的功能,若是不须要该功能请务必注释掉该yml中关于multiline的配置
。(因为我在nginx/ingress中的access的json日志都是一行,因此在nginx日志当中不须要配置multiline配置)
multiline配置:
#将'['做为新的一行的标识,若是message中不碰到'[',则合并为一条日志 multiline.pattern: ^\[ multiline.negate: true multiline.match: after
同时配置:
processors: - decode_json_fields: fields: ['message'] target: json
kibana的安装配置此处再也不说明.
添加索引按照界面一步步操做便可.
几个典型图形配置示例
(1)PV
(2)UV
(3)Top10(接口访问量)
(4)Top10(客户端IP访问占比)
(5)Top10(最慢接口)
(6)后端upstream占比
(7)实时流量
(8)客户端访问占比
(9)平均并发数
(10)异常状态码统计
(11)总流量
(12)接口异常响应码
(13)接口访问耗时占比
(14)每10秒接口访问平均耗时
(15)每10秒接口访问最大耗时
(16)状态码统计
(17)访问量趋势图
(18)超过30秒以上的接口
(19)超过30秒以上的接口出现次数
以Top10(最慢接口)举例,获取Top10耗时最慢的url组成1个表格,可是我在Metrics怎么都找不到duration字段或者request_time字段,经过排查得知,Metrics字段通常是数值型字段,对数值型字段求和、求最大值、求平均值等.可是我在ingress定义的字段都是字符串,因此同步到elasticsearch中也是字符串,因此在kibana的Metrics中也没法找到duration字段.既然找到问题症结了,咱们就开始修正.从新修改ingress的confimap配置,从新在kibana添加索引.固然添加索引以前,我先删除了原来的索引从新添加.固然这个方法比较粗暴!!还有其余方法能够解决.
(1)若是是logstash可使用mutate对字段进行转换
mutate { convert => ["name-of-field", "integer"] }
(2)官方没有提供字符串转数值,但咱们能够建立1个新的索引,同时把原来的elasticsearch格式化数值后导入便可.
#建立新索引并格式化duration字段 curl -H 'Content-Type: application/json' -XPUT "http://localhost:9200/ingress_new" curl -H 'Content-Type: application/json' -XPOST "http://localhost:9200/ingress_new/ingress_old/_mapping?pretty" -d ' { "ingress_old": { "properties": { "duration": { "type": "double", "store": "true", "ignore_malformed": "true" } } } } #从旧索引中导入数据 curl -X POST "localhost:9200/_reindex" -H 'Content-Type: application/json' -d' { "source": { "index": "ingress_old" "size": 5000 }, "dest": { "index": "ingress_new" "routing": "=cat" } }'