日志分析
日志采集/分析
EFK
日志收集系统,后面需要部署的
可观测体系
-
通过数据看懂系统内部发生了什么
-
依赖下面三类数据
-
系统出现了问题时,能快速定位原因,而不只是看到挂了
监控
-
看系统现在好不好,稳不稳
-
cpu,内存,延迟,错误率,磁盘io
-
prometheus,grafana,zabbix
日志
链路追踪
这三个都是非常的重要
混沌工程,故障演练
怎么提问题
你的环境是什么样的,操作的命令是什么呢,报的的错误是什么呢,查看的日志是什么呢?
用户在斗鱼直播间看的直播类型,停留了多长的时间,都会记录在日志里面
然后大数据根据这个来实现用户的画像
日志系统
- ELK
-
ElasticSearch 日志存储系统
-
LogStash 日志采集器,也可以解析,分析
-
Kibana 日志分析查询系统
ELK现在用的少,原因是
1.jruby java+ruby
2.语法复杂,重量级日志采集
3.性能差
- EFK
-
ElasticSearch 日志存储系统
-
Fluneted:日志采集器,也可以解析,分析
-
Kibana 日志分析查询系统
- PLG(轻量级)
-
Promtail :日志采集器
-
Loki:日志存储系统
-
Grafana:日志查询分析系统
流程;
- 轻量级别采集器(logtail/filebeat/fluent-bit)
-
装在业务服务器上
-
只干一件事,对日志文件--> 发到kafka
-
不做任何复杂解析,不占业务资源
- kafka
-
接收采集器发来的原始,未加工日志
-
作用就是缓冲,削峰,防止后面处理不过来把采集端压崩
- fluentd/logstash
-
不是前端采集,而是后端处理
-
从kafka把原始日志拉下来
-
过滤无用日志
-
解析格式(json,nginx,java栈等)
-
结构化,字段拆分
-
最后输出到es(日志存储),数据库,存储等
- kibana
- 日志查询
方案的优点和缺点,深度,广度,长期的积淀
轻量采集器 只负责采集,发送,不解析
kafka 存原始日志,做缓冲,解耦,消息队列
fluentd/logstash 从kafka消费日志,专门做解析,清洗,结构化
2、部署ES(ElasticSearch)
日志存储
1、部署handless服务
[root@master EFK]# vim es-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: elasticsearch
namespace: logging
labels:
app: elasticsearch
spec:
selector:
app: elasticsearch
clusterIP: None
ports:
- port: 9200 # 监听的第一个端口
name: rest
- port: 9300 # 监听的第二个端口
name: inter-node
2、创建sts
[root@master EFK]# vim es-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: es
namespace: logging
spec:
serviceName: elasticsearch
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
initContainers:
- name: initc1
image: busybox
command: ["sysctl","-w","vm.max_map_count=262144"]
securityContext:
privileged: true
- name: initc2
image: busybox
command: ["sh","-c","ulimit -n 65536"]
securityContext:
privileged: true
- name: initc3
image: busybox
command: ["sh","-c","chmod 777 /data"]
volumeMounts:
- name: data
mountPath: /data
containers:
- name: elasticsearch
image: swr.cn-east-3.myhuaweicloud.com/hcie_openeuler/elasticsearch:7.17.1
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
ports:
- containerPort: 9200
name: rest
protocol: TCP
- containerPort: 9300
name: inter-node
protocol: TCP
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
env:
- name: cluster.name
value: k8s-logs
- name: node.name
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: cluster.initial_master_nodes
value: "es-0"
- name: discovery.zen.minimum_master_nodes
value: "2"
- name: discovery.seed_hosts
value: "elasticsearch"
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
- name: network.host
value: "0.0.0.0"
volumeClaimTemplates:
- metadata:
name: data
labels:
app: elasticsearch
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
volumeClaimTemplates字段
-
为每一个pod自动的创建独立的持久的存储,pvc,pv
-
数据必须放在持久化硬盘上,不能丢
-
pod删除了,重建了,还是能读到原来的数据
-
不写storage class自动的去找默认storage class
3、部署kibana
直接将所有需要的资源放在一个yml文件里面
apiVersion: v1
kind: ConfigMap
metadata:
namespace: logging
name: kibana-config
labels:
app: kibana
data:
kibana.yml: |
server.name: kibana
server.host: "0.0.0.0"
i18n.locale: zh-CN
elasticsearch:
hosts: ${ELASTICSEARCH_HOSTS}
---
apiVersion: v1
kind: Service
metadata:
name: kibana
namespace: logging
labels:
app: kibana
spec:
ports:
- port: 5601
type: NodePort
selector:
app: kibana
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
namespace: logging
labels:
app: kibana
spec:
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: swr.cn-east-3.myhuaweicloud.com/hcie_openeuler/kibana:7.17.1
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1
requests:
cpu: 1
env:
- name: ELASTICSEARCH_URL
value: http://elasticsearch:9200 # 写handless的名字
- name: ELASTICSEARCH_HOSTS
value: http://elasticsearch:9200 # 写handless的名字
ports:
- containerPort: 5601
volumeMounts:
- name: config
mountPath: /usr/share/kibana/config/kibana.yml
readOnly: true
subPath: kibana.yml
volumes:
- name: config
configMap:
name: kibana-config
[root@master01 efk]# kubectl get svc -n logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 35m
kibana NodePort 10.105.137.181 <none> 5601:30044/TCP 35s
kibana的端口为30044,访问即可

这样就算部署好了,接下来部署日志采集工具
4、部署ilogtail(docker-compose)
因为Fluentd配置复杂,所以我这里采用ilogtail来采集日志
-
ilogtail配置简单
-
阿里开源,界面中文
我们先使用docker-compose的方式部署,最后整个平台搭建起来之后我们再将ilogtail部署到k8s集群里
5、部署kafaka
kafka作为消息队列,会有消费者和生产者,生产者就是ilogtail(采集信息),也就是将日志写入到kafka,消费者就是logstash,从kafak里面读取日志写入到es
1、kafka介绍
Apache kafka是分布式的,基于发布/订阅的容错消息系统,主要特性如下
高吞吐,低延迟:可以做到每秒百万级的吞吐量,并且延迟低(其他的消息队列基本也都可以)
持久性,可靠性:消息会被持久化到本地磁盘,支持数据备份防止数据丢失,并且可以配置消息有效期,以便消费者可以多次消费
kafka官方不支持docker部署,我们可以使用第三方的镜像
2、部署kafka(docker-compose)
version: '3'
services:
zookeeper:
image: quay.io/3330878296/zookeeper:3.8
network_mode: host
container_name: zookeeper-test
volumes:
- zookeeper_vol:/data
- zookeeper_vol:/datalog
- zookeeper_vol:/logs
kafka:
image: quay.io/3330878296/kafka:2.13-2.8.1
network_mode: host
container_name: kafka
environment:
KAFKA_ADVERTISED_HOST_NAME: "192.168.50.20"
KAFKA_ZOOKEEPER_CONNECT: "192.168.50.20:2181"
KAFKA_LOG_DIRS: "/kafka/logs"
volumes:
- kafka_vol:/kafka
depends_on:
- zookeeper
volumes:
zookeeper_vol: {}
kafka_vol: {}
# 启动
[root@master01 kafka]# docker-compose up -d
KAFKA_LOG_DIRS: "/kafka/logs":这个地方需要注意,在kafka的名词里面,他把数据叫做日志,这个地方看似是定义的日志目录,其实是kafka的数据目录
3、部署kafdrop(kafka的web界面)
[root@master kafka]# docker run -d --rm -p 9000:9000 \
-e KAFKA_BROKERCONNECT=192.168.200.200:9092 \
-e SERVER_SERVLET_CONTEXTPATH="/" \
quay.io/3330878296/kafdrop
部署好之后就可以使用web界面查看了,部署web界面的原因是我们将日志写入到kafka之后可以直接使用web界面查看也没有写入进去,比kafka命令行更加的直观
在浏览器中输入ip:9000

6、部署logstash
logstash会从kafka读取消息然后写入到es里面
1、部署logstash(docker-compose)
version: '3'
services:
logstash:
image: quay.io/3330878296/logstash:8.10.1
container_name: logstash
network_mode: host
environment:
LS_JAVA_OPTS: "-Xmx1g -Xms1g"
volumes:
- /etc/localtime:/etc/localtime:ro
- /apps/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
- /apps/logstash/pipeline:/usr/share/logstash/pipeline
- /var/log:/var/log
-
config里面放的是logstash本身的配置文件
-
pipeline里面放的是采集/输出日志的规则
docker-compose写好之后先不要着急启动,因为我们给他挂载的配置文件还没有启动
现在编写配置文件
[root@node1 logstash]# mkdir /apps/logstash/{config,pipeline} -p
[root@node1 config]# cat logstash.yml
pipeline.workers: 2
pipeline.batch.size: 10
pipeline.batch.delay: 5
config.reload.automatic: true
config.reload.interval: 60s
写好这个文件,启动logstash容器
2、输出日志到es
logsstash官方文档地址
https://www.elastic.co/guide/en/logstash/current/index.html
我们要使用logstash输出日志到es的话就需要到pipeline里面去写一些规则
tob 就是部署到客户端的吗
现在的话,就是云端访问,作为企业的员工,用的考勤,报销,根本不知道服务器在哪里,打开网页或者app就能访问,数据都在厂商,云端部署
[root@node1 pipeline]# cat logstash.conf
input {
kafka {
# 指定kafka地址
bootstrap_servers => "192.168.50.20:9092"
# 从哪些topic获取数据,要写已经存在topic
topics => ["KafkaTopic"]
# 从哪个地方开始读取,earliest是从头开始读取
auto_offset_reset => "earliest"
codec => "json"
# 当一个logstash中有多个input插件时,建议每个插件定义一个id
# id => "kubernetes"
# group_id => "kubernetes"
}
}
filter {
json {
source => "event.original"
}
mutate {
remove_field => ["event.original","event"]
}
}
output {
elasticsearch {
hosts => ["http://192.168.50.20:9200"]
index => "kubernetes-logs-%{+YYYY.MM.dd}"
}
}
- hosts => ["http://192.168.50.20:9200"]:这个地方的9200,因为我们的logstash是用docker部署的,但是es是部署在k8s集群内部的,所以这个地方9200端口是通不了的,所以我们需要给k8s的es创建一个nodeport类型的svc,来让docker可以访问到
[root@master01 kafka]# kubectl expose pod es-0 --type NodePort --port 9200 --target-port 9200 -n logging
service/es-0 exposed
[root@master01 kafka]# kubectl get svc -n logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 99m
es-0 NodePort 10.105.44.93 <none> 9200:32229/TCP 3s
kibana NodePort 10.105.137.181 <none> 5601:30044/TCP 64m
将9200映射到32229,所以我们将logstash的地址改到32229
output {
elasticsearch {
hosts => ["http://192.168.50.20:32229"]
index => "kubernetes-logs-%{+YYYY.MM.dd}"
}
}
重启logstash
[root@node1 pipeline]# docker restart logstash
logstash
3、到kibana查看
1、查看索引
7、将ilogtail部署到k8s
我们刚刚是将ilogtail使用的单机docker部署,无法采集到其他节点上的容器,主机日志,所以我们可以将ilogtail采用DaemonSet的方式部署到k8s集群内的每个节点上,这样每个节点的日志都可以被采集到
如果已经使用docker部署,就先将docker部署的ilogtail停掉
1、下载配置实例
1、创建命名空间
[root@master01 nodes]# kubectl create ns ilogtail
namespace/ilogtail created
2、创建configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: ilogtail-user-cm
namespace: ilogtail
data:
nginx_stdout.yaml: |
enable: true
inputs:
- Type: service_docker_stdout
Stderr: false
Stdout: true # only collect stdout
IncludeK8sLabel:
app: nginx # choose containers with this label
#processors:
# - Type: processor_regex # structure log
# SourceKey: content
# Regex: '([\d\.:]+) - (\S+) \[(\S+) \S+\] \"(\S+) (\S+) ([^\\"]+)\" (\d+) (\d+) \"([^\\"]*)\" \"([^\\"]*)\" \"([^\\"]*)\"'
# Keys:
# - remote_addr
# - remote_user
# - time_local
# - method
# - url
# - protocol
# - status
# - body_bytes_sent
# - http_referer
# - http_user_agent
# - http_x_forwarded_for
flushers:
- Type: flusher_kafka_v2
Brokers:
- 192.168.50.20:9092
Topic: nginx
OnlyStdout: true
3、创建ds
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ilogtail-ds
namespace: ilogtail
labels:
k8s-app: logtail-ds
spec:
selector:
matchLabels:
k8s-app: logtail-ds
template:
metadata:
labels:
k8s-app: logtail-ds
spec:
tolerations:
- operator: Exists
containers:
- name: logtail
env:
- name: ALIYUN_LOG_ENV_TAGS
value: _node_name_|_node_ip_
- name: _node_name_
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: _node_ip_
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: cpu_usage_limit
value: "1"
- name: mem_usage_limit
value: "512"
- name: default_access_key_id
valueFrom:
secretKeyRef:
name: ilogtail-secret
key: access_key_id
optional: true
- name: default_access_key
valueFrom:
secretKeyRef:
name: ilogtail-secret
key: access_key
optional: true
image: sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:2.0.4
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 400m
memory: 384Mi
volumeMounts:
- mountPath: /var/run
name: run
- mountPath: /logtail_host
mountPropagation: HostToContainer
name: root
readOnly: true
- mountPath: /usr/local/ilogtail/checkpoint
name: checkpoint
- mountPath: /usr/local/ilogtail/config/local
name: user-config
readOnly: true
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
volumes:
- hostPath:
path: /var/run
type: Directory
name: run
- hostPath:
path: /
type: Directory
name: root
- hostPath:
path: /etc/ilogtail-ilogtail-ds/checkpoint
type: DirectoryOrCreate
name: checkpoint
- configMap:
defaultMode: 420
name: ilogtail-user-cm
name: user-config
2、采集数据
在configmap里面我们定义的是采集带有app: nginx这个标签的pod,所以我们现在来创建这个一个nginx的pod
[root@master01 ilogtail]# cat nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
namespace: logging
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: quay.io/3330878296/nginx
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
status: {}
访问nginx的ip
[root@master01 ilogtail]# curl 10.245.149.55
3、回到kafdrop查看topic
我们访问nginx之后按照正常情况下来说的话,ilogtail会采集日志写入到kafka并创建一个nginx的topic,我们现在来看看也没有

有这个nginx就没有问题了,说明日志可以被正常采集到并写入,要将nginx写入到es的话可以在/apps/logstash/pipeline/这个目录下面写一个新的配置文件
[root@node1 pipeline]# cat nginx.conf
input {
kafka {
# 指定kafka地址
bootstrap_servers => "192.168.50.20:9092"
# 从哪些topic获取数据,要写已经存在topic
topics => ["nginx"]
# 从哪个地方开始读取,earliest是从头开始读取
auto_offset_reset => "earliest"
codec => "json"
# 当一个logstash中有多个input插件时,建议每个插件定义一个id
# id => "kubernetes"
# group_id => "kubernetes"
}
}
filter {
json {
source => "event.original"
}
mutate {
remove_field => ["event.original","event"]
}
}
output {
elasticsearch {
hosts => ["http://192.168.50.20:32229"]
index => "kubernetes-nginx-logs-%{+YYYY.MM.dd}"
}
}
es上面就有这个索引了


浙公网安备 33010602011771号