joeの小窝

Loading...

日志分析

日志采集/分析

EFK

日志收集系统,后面需要部署的

可观测体系

  • 通过数据看懂系统内部发生了什么

  • 依赖下面三类数据

  • 系统出现了问题时,能快速定位原因,而不只是看到挂了

监控

  • 看系统现在好不好,稳不稳

  • cpu,内存,延迟,错误率,磁盘io

  • prometheus,grafana,zabbix

日志

链路追踪

这三个都是非常的重要

混沌工程,故障演练

怎么提问题

你的环境是什么样的,操作的命令是什么呢,报的的错误是什么呢,查看的日志是什么呢?

用户在斗鱼直播间看的直播类型,停留了多长的时间,都会记录在日志里面

然后大数据根据这个来实现用户的画像

日志系统

  1. ELK
  • ElasticSearch 日志存储系统

  • LogStash 日志采集器,也可以解析,分析

  • Kibana 日志分析查询系统

ELK现在用的少,原因是
1.jruby java+ruby
2.语法复杂,重量级日志采集
3.性能差

  1. EFK
  • ElasticSearch 日志存储系统

  • Fluneted:日志采集器,也可以解析,分析

  • Kibana 日志分析查询系统

  1. PLG(轻量级)
  • Promtail :日志采集器

  • Loki:日志存储系统

  • Grafana:日志查询分析系统

流程;

  1. 轻量级别采集器(logtail/filebeat/fluent-bit)
  • 装在业务服务器上

  • 只干一件事,对日志文件--> 发到kafka

  • 不做任何复杂解析,不占业务资源

  1. kafka
  • 接收采集器发来的原始,未加工日志

  • 作用就是缓冲,削峰,防止后面处理不过来把采集端压崩

  1. fluentd/logstash
  • 不是前端采集,而是后端处理

  • 从kafka把原始日志拉下来

  • 过滤无用日志

  • 解析格式(json,nginx,java栈等)

  • 结构化,字段拆分

  • 最后输出到es(日志存储),数据库,存储等

  1. 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,访问即可

img

这样就算部署好了,接下来部署日志采集工具

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

img

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,我们现在来看看也没有

img

有这个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上面就有这个索引了

img

posted @ 2026-04-18 17:14  乔的港口  阅读(18)  评论(0)    收藏  举报