日志采集/分析

· 浏览次数 : 0

小编点评

本文介绍了如何部署一个基于Elasticsearch、Logstash、Kafka和Kibana的可观测性体系。该体系可以帮助用户收集、分析和可视化日志数据,从而更好地监控基础设施和应用。 1. **日志系统**:本文首先介绍了ELK Stack(Elasticsearch、Logstash、Kibana)的基本概念和作用,以及它们在可观测性体系中的重要性。 2. **部署Elasticsearch**:接着,文章详细描述了如何在Kubernetes上部署Elasticsearch,并创建了一个无状态服务。 3. **部署Kibana**:文章展示了如何将Kibana部署到Kubernetes集群中,并配置了相关的环境变量和端口。 4. **部署ilogtail(docker-compose)**:为了简化日志采集过程,文章介绍了如何使用Docker Compose部署ilogtail,并配置了日志采集规则。 5. **查看容器采集的日志**:文章说明了如何查看由ilogtail采集的容器日志,并提供了查看标准输出日志的选项。 6. **部署kafka**:文章介绍了Kafka作为消息队列的重要性,并在Kubernetes上部署了Kafka,包括其配置和网络设置。 7. **部署kafdrop**:为了方便用户查看Kafka中的日志数据,文章部署了Kafdrop,这是一个Kafka的Web界面工具。 8. **ilogtail将日志写入到kafka**:文章最后介绍了如何配置ilogtail将日志写入到Kafka,并通过Kibana查看索引情况。 总的来说,本文提供了一个完整的日志收集和可视化方案,帮助用户更好地理解和监控他们的基础设施和应用。

正文

EFK

这是一个日志收集系统,日志收集属于可观测性体系

可观测性体系

  • 监控

    • 基础设施的维度
      • USE方法
        • CPU:
          • 利用率
          • 负载
        • 内存:
          • 利用率
          • 饱和度
          • 错误率
        • 网卡:
          • 利用率
          • 饱和度
          • 错误率
    • 应用程序的维度
      • RED方法
  • 日志

    • 操作系统维度
    • 应用维度
      • 通过日志的错误进一步完善监控
      • 通过日志排查问题
      • 行为分析
  • 链路追踪

1. 日志系统

  1. ELK
    • ElasticSearch :日志存储系统
    • LogStash:日志采集器
    • Kibana:日志查询分析系统

ELK现在用的少,原因是

  1. jruby(java+ruby)
  2. 语法复杂:重量级日志采集
  3. 性能差
  1. EFK

    • ElasticSearch
    • Fluneted:日志采集器
    • Kibana
  2. PLG

    • Promtail :日志采集器
    • Loki:日志存储系统
    • Grafana:日志查询分析系统

我们这里部署的架构是

ilogtail ---> kafka ---> logstash ---> elasticsearch ---> kibana

使用ilogtail采集日志写入到kafka消息队列里,再由logstash从消息队列里读取日志写入到 es,最后再由kibana做展示

至于第三个环节为什么是logstash而不是ilogtail是因为,ilogtail要往es里面写日志会需要配置es的认证密码,但我们是没有给es配置用户名和密码的,所以采用logstash

2. 部署ElasticSearch

2.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.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

应用yaml文件

[root@master EFK]# kubectl create ns logging
[root@master EFK]# kubectl apply -f .
service/elasticsearch create
statefulset.apps/es create
[root@master EFK]# kubectl get pods -n logging 
NAME   READY   STATUS    RESTARTS   AGE
es-0   1/1     Running   0          46s

pod显示running就是部署好了

3. 部署kibana

我直接将所有需要的资源放在一个yaml文件里面

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@master EFK]# kubectl get svc
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
elasticsearch   ClusterIP   None            <none>        9200/TCP,9300/TCP   17m
kibana          NodePort    10.104.94.122   <none>        5601:30980/TCP      4m30s

kibana的nodeport端口是30980,我们来访问

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

4. 部署ilogtail(docker-compose)

因为Fluentd配置复杂,所以我这里采用ilogtail来采集日志

  • ilogtail配置简单
  • 阿里开源,界面中文

我们先使用docker-compose的方式部署,最后整个平台搭建起来之后我们再将ilogtail部署到k8s集群里

4.1 编写docker-compose

[root@master ilogtail]# vim docker-compose.yaml
version: "3"
services:
  ilogtail:
    container_name: ilogtail
    image: sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:2.0.4
    network_mode: host
    volumes:
      - /:/logtail_host:ro
      - /var/run:/var/run
      - ./checkpoing:/usr/local/ilogtail/checkpoint
      - ./config:/usr/local/ilogtail/config/local
  • /:我们将宿主机的整个 / ,目录挂载到容器里面,方便容器读取日志
  • checkpoint:这个相当于一个指针,指向当前读取到哪一行日志了,如果ilogtail被重启了它可以根据这个checkpoint来回到上一次读取的地方
  • config:这个就是放采集的配置文件的

启动容器

[root@master ilogtail]# docker-compose up -d
[root@master ilogtail]# docker ps |grep ilogtail
eac545d4da87        sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:2.0.4   "/usr/local/ilogtail…"   10 seconds ago      Up 9 seconds                            ilogtail

这样容器就启动了

4.2 配置ilogtail采集

[root@master ilogtail]# cd config/
[root@master config]# vim sample-stdout.yaml
enable: true
inputs:
  - Type: input_file          # 文件输入类型
    FilePaths: 
      - /logtail_host/var/log/messages
flushers:
  - Type: flusher_stdout    # 标准输出流输出类型
    OnlyStdout: true
[root@master config]# docker restart ilogtail
  • /logtail_host/var/log/messages:这里是这个地址的原因是我们将宿主机的/,挂载到了容器内的logtail_host,所以我们宿主机产生的日志会在容器的/logtail_host/var/log/messages这个目录下

  • 配置文件写好之后我们还需要重启容器让他读取配置,所以有一个restart

4.3 查看容器采集的日志

[root@master config]# docker logs ilogtail

2024-06-30 11:16:25 {"content":"Jun 30 19:16:22 master dockerd[1467]: time=\"2024-06-30T19:16:22.251108165+08:00\" level=info msg=\"handled exit event processID=9a8df40981b3609897794e50aeb2bde805eab8a75334266d7b5c2899f61d486e containerID=61770e8f88e3c6a63e88f2a09d2683c6ccce1e13f6d4a5b6f79cc4d49094bab4 pid=125402\" module=libcontainerd namespace=moby","__time__":"1719746182"}
2024-06-30 11:16:25 {"content":"Jun 30 19:16:23 master kubelet[1468]: E0630 19:16:23.594557    1468 kubelet_volumes.go:245] \"There were many similar errors. Turn up verbosity to see them.\" err=\"orphaned pod \\\"9d5ae64f-1341-4c15-b70f-1c8f71efc20e\\\" found, but error not a directory occurred when trying to remove the volumes dir\" numErrs=2","__time__":"1719746184"}

可以看到,宿主机的日志已经被成功采集了,宿主机的日志会被封装到content里,如果没有看到输出的日志的话,需要进入到容器内部查看一个叫做ilogtail.LOG的文件,而不能使用docker logs ilogtail

4.4 采集容器标准输出日志(可选)

[root@master config]# cp sample-stdout.yaml docker-stdout.yaml
# 为了避免同时输出到标准输出而导致的日志杂乱,我们临时将sample-stdout关掉
[root@master config]# cat sample-stdout.yaml 
enable: false                 # 将这里改为false
inputs:
  - Type: input_file          # 文件输入类型
    FilePaths: 
      - /logtail_host/var/log/messages
flushers:
  - Type: flusher_stdout    # 标准输出流输出类型
    OnlyStdout: true
[root@master config]# cat docker-stdout.yaml 
enable: true
inputs:
  - Type: service_docker_stdout        
    Stdout: true                 # 采集标准输出
    Stderr: false                # 不采集错误输出
flushers:
  - Type: flusher_stdout    
    OnlyStdout: true
[root@master config]# docker restart ilogtail 
ilogtail

4.5 查看采集的容器日志

2024-06-30 11:24:13 {"content":"2024-06-30 11:24:10 {\"content\":\"2024-06-30 11:24:07 {\\\"content\\\":\\\"2024-06-30 11:24:04.965 [INFO][66] felix/summary.go 100: Summarising 12 dataplane reconciliation loops over 1m3.4s: avg=3ms longest=12ms ()\\\",\\\"_time_\\\":\\\"2024-06-30T11:24:04.965893702Z\\\",\\\"_source_\\\":\\\"stdout\\\",\\\"_container_ip_\\\":\\\"192.168.200.200\\\",\\\"_image_name_\\\":\\\"calico/node:v3.23.5\\\",\\\"_container_name_\\\":\\\"calico-node\\\",\\\"_pod_name_\\\":\\\"calico-node-hgqzr\\\",\\\"_namespace_\\\":\\\"kube-system\\\",\\\"_pod_uid_\\\":\\\"4d0d950c-346a-4f81-817c-c19526700542\\\",\\\"__time__\\\":\\\"1719746645\\\"}\",\"_time_\":\"2024-06-30T11:24:07.968118197Z\",\"_source_\":\"stdout\",\"_container_ip_\":\"192.168.200.200\",\"_image_name_\":\"sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:2.0.4\",\"_container_name_\":\"ilogtail\",\"__time__\":\"1719746647\"}","_time_":"2024-06-30T11:24:10.971474647Z","_source_":"stdout","_container_ip_":"192.168.200.200","_image_name_":"sls-opensource-registry.cn-shanghai.cr.aliyuncs.com/ilogtail-community-edition/ilogtail:2.0.4","_container_name_":"ilogtail","__time__":"1719746650"}

能够正常看见日志就说明日志采集没有问题,接下来我们部署kafka,用来接收ilogtail的日志,注意将日志采集关掉,不然你的虚拟机磁盘很快就会满

5. 部署kafka

kafka作为消息队列,会有消费者和生产者,生产者在这里就是ilogtail,也就是将日志写入到kafka,消费者就是logstash,从kafka里面读取日志写入到es

5.1 kafka介绍

Apache kafka是分布式的,基于发布/订阅的容错消息系统,主要特性如下

  • 高吞吐,低延迟:可以做到每秒百万级的吞吐量,并且延迟低(其他的消息队列基本也都可以)

  • 持久性,可靠性:消息会被持久化到本地磁盘,支持数据备份防止数据丢失,并且可以配置消息有效期,以便消费者可以多次消费

  • kafka官方不支持docker部署,我们可以使用第三方的镜像

5.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.200.200"
      KAFKA_ZOOKEEPER_CONNECT: "192.168.200.200:2181"
      KAFKA_LOG_DIRS: "/kafka/logs"
    volumes:
      - kafka_vol:/kafka
    depends_on:
      - zookeeper
volumes:
  zookeeper_vol: {}
  kafka_vol: {}
  • KAFKA_LOG_DIRS: "/kafka/logs":这个地方需要注意,在kafka的名词里面,他把数据叫做日志,这个地方看似是定义的日志目录,其实是kafka的数据目录

5.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

5.4 ilogtail将日志写入到kafka

[root@master config]# cd /root/ilogtail/config
[root@master config]# cp sample-stdout.yaml kafka.yaml
[root@master config]# vim kafka.yaml
enable: true
inputs:
  - Type: input_file         
    FilePaths:
      - /logtail_host/var/log/messages
flushers:
  - Type: flusher_kafka_v2  
    Brokers:
      - 192.168.200.200:9092
    Topic: KafkaTopic
[root@master config]# docker restart ilogtail
ilogtail

这个时候我们再回到web界面就会出现一个topic

点进去可以查看有哪些日志被写入进去了

能看见日志就没问题了,接下来部署logstash

6. 部署logstash

logstash会从kafka读取消息然后写入到es里面去

6.1 部署logstash(docker-compose)

[root@master ~]# mkdir logstash
[root@master ~]# cd logstash
[root@master logstash]# vim docker-compose.yaml
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@master logstash]# mkdir /apps/logstash/{config,pipeline}
[root@master logstash]# cd /apps/logstash/config/
[root@master config]# vim logstash.yml 
pipeline.workers: 2
pipeline.batch.size: 10
pipeline.batch.delay: 5
config.reload.automatic: true
config.reload.interval: 60s

写好这个文件之后我们启动这个logstash容器

[root@master logstash]# /root/logstash
[root@master logstash]# docker-compose up -d
[root@master logstash]# docker ps |grep logstash
60dfde4df40d        quay.io/3330878296/logstash:8.10.1                                                              "/usr/local/bin/dock…"   2 minutes ago       Up 2 minutes                                 logstash

启动之后就没问题了

6.2 输出日志到es

Logstash官方文档地址

我们要使用logstash输出日志到es的话就需要到pipeline里面去写一些规则

[root@master EFK]# cd /apps/logstash/pipeline/
[root@master pipeline]# vim logstash.conf
input {
  kafka {
    # 指定kafka地址
    bootstrap_servers => "192.168.200.200: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.200.200:9200"]
    index => "kubernetes-logs-%{+YYYY.mm}"
  }
}
  • ​ hosts => ["http://192.168.200.200:9200"]:这个地方的9200,因为我们的logstash是用docker部署的,但是es是部署在k8s集群内部的,所以这个地方9200端口是通不了的,所以我们需要给k8s的es创建一个nodeport类型的svc,来让docker可以访问到
[root@master EFK]# kubectl expose pod es-0 --type NodePort --port 9200 --target-port 9200
service/es-0 exposed
[root@master EFK]# kubectl get svc
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
elasticsearch   ClusterIP   None            <none>        9200/TCP,9300/TCP   3h38m
es-0            NodePort    10.97.238.173   <none>        9200:32615/TCP      2s
kibana          NodePort    10.106.1.52     <none>        5601:30396/TCP      3h38m

这里他将9200映射到了本地的32615端口,所以我们将logstash的地址改到32615

output {
  elasticsearch {
    hosts => ["http://192.168.200.200:32615"]
    index => "kubernetes-logs-%{+YYYY.mm}"
  }
}

然后重启logstash

[root@master pipeline]# docker restart logstash 

6.3 到kibana查看

6.3.1 查看索引

  1. 点击stack management

  2. 点击索引管理,会看到有索引存在就是正常

  3. 点击索引模式,创建索引

  1. 进入discover

与日志采集/分析相似的内容:

日志采集/分析

目录EFK1. 日志系统2. 部署ElasticSearch2.1 创建handless服务2.2 创建sts3. 部署kibana4. 部署ilogtail(docker-compose)4.1 编写docker-compose4.2 配置ilogtail采集4.3 查看容器采集的日志4.4 采集

安卓开发日志采集和分析面面谈

明确系统提供了哪些日志,cpu、meminfo、app、log等,我们怎么看日志,看日志的三步骤,怎么用工具提高分析日志的效率,bugreport和chkbugreport。

大数据 - DWD&DIM 行为数据

我们前面采集的日志数据已经保存到 Kafka 中,作为日志数据的 ODS 层,从 Kafka 的ODS 层读取的日志数据分为 3 类, 页面日志、启动日志和曝光日志。这三类数据虽然都是用户行为数据,但是有着完全不一样的数据结构,所以要拆分处理。将拆分后的不同的日志写回 Kafka 不同主题中,作为日

【pandas小技巧】--读取多个文件

日常分析数据时,只有单一数据文件的情况其实很少见,更多的情况是,我们从同一个数据来源定期或不定期的采集了很多数据文件;或者从不同的数据源采集多种不同格式的数据文件。 在这样的情况下,分析数据之前,需要将不同的数据集合并起来。合并数据一般有两个维度,一是同构的数据集合并后行数增加;一是异构的数据集合并

[转帖]LSM-Tree:从入门到放弃——入门:基本概念、操作和Trade-Off分析

https://zhuanlan.zhihu.com/p/428267241 LSM-Tree,全程为日志结构合并树,有趣的是,这个数据结构实际上重点在于日志结构合并,和 tree 本身的关系并不是特别大(除了各种可能的天外飞仙式的工程优化,一般来说只有 level0 采用了平衡树的结构) LSM-

Mybatis-SQL分析组件

大促备战,最大的隐患项之一就是慢sql,带来的破坏性最大,也是日常工作中经常带来整个应用抖动的最大隐患,而且对sql好坏的评估有一定的技术要求,有一些缺乏经验或者因为不够仔细造成一个坏的sql成功走到了线上,等发现的时候要么是造成了线上影响、报警、或者后置的慢sql采集发现,这时候一般无法快速止损,需要修改代码上线、或者调整数据库索引。

实战分享 | 金融数据采集报送平台实践

本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 大数据时代,数据在企业的日常经营中无处不在,各类数据的汇总、整合、分析、研究对企业的决策和发展有着至关重要的作用。企业要进行数字化转型,本质是强化对数据的使用,包含数据

[转帖]夜莺 监控项目

项目介绍 夜莺监控是一款开源云原生观测分析工具,采用 All-in-One 的设计理念,集数据采集、可视化、监控告警、数据分析于一体,与云原生生态紧密集成,提供开箱即用的企业级监控分析和告警能力。夜莺于 2020 年 3 月 20 日,在 github 上发布 v1 版本,已累计迭代 100 多个版

[转帖]TiDB损坏多副本之有损恢复处理方法

https://tidb.net/blog/b1ae4ee7 TiDB分布式数据库采用多副本机制,数据副本通过 Multi-Raft 协议同步事务日志,确保数据强一致性且少数副本发生故障时不影响数据的可用性。在三副本情况下,单副本损坏可以说对集群没什么影响,但当遇到多副本损坏的损坏丢失的时候,如何快

每天5分钟复习OpenStack(十三)存储缓存技术Bcache

Ceph作为一个分布式存储,在项目中常见的形态有两者,一种是采用 SSD 或NVME 磁盘做Ceph的日志盘,使用SATA磁盘来做数据盘。这样的好处是比较经济实惠。另一种则是全部采用 SSD 或NVME磁盘,其性能更好,但是其价格比较昂贵。在第一种形态中,我们能像中间件那样加上一层缓存层,从而实现给