4

一份接地气的Kubernetes日志方案

 11 months ago
source link: https://www.51cto.com/article/768495.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一份接地气的Kubernetes日志方案

作者:不焦躁的程序员 2023-09-29 22:41:26

本文主要聊聊Kubernetes场景下收集微服务应用日志方案,相对来说更接地气,非常好落地。

微服务应用的日志链路一般比较长,包含以下环节:日志收集 → 日志缓冲 → 日志过滤清洗 → 日志存储 → 日志展示。每个环节都有多种对应的组件去解决,这样的结果就是业内组合出了多种整体解决方案。

以前我的微服务部署在IDC机房虚拟机时,采用的是ELK(Elasticsearch、Logstash、Kibana)方案,这也是通用的微服务应用的日志解决方案。几年前我们的应用部署整体切到Kubernetes后,我依旧采用了这套方案。

下面介绍Kubernetes场景下基于ELK的日志解决方案。整体思路:Filebeat -> Kafka -> Logstash -> Elasticsearch -> Kibana。

1、日志数据流转

日志数据流转见下图:

d3c72d903fca00f86bc942a73036954704e079.png

2、日志采集

2.1、容器日志在哪儿

首先得有个概念:容器只是K8S集群Node上的一个进程。要在K8S集群机器上找到此Docker进程,然后进入到对应的文件夹里查看日志文件。

一般情况下,容器的日志存放在宿主机上的这个目录下/var/lib/docker/containers/:

# 日志在宿主机的这个文件夹下
cd /var/lib/docker/containers
# 用这个命令可以查找对应的日志文件
find /var/lib/docker/containers -name "*-json.log"

进入到/var/lib/docker/containers/下,看到的是一堆毫无规律的文件夹。

151b5a448de6837a00273780ab6d9ebfbfd12f.png

看到这些毫无规律的文件夹名称,会一下子有点懵,但是仔细看看,其实这些码是对应的Docker容器的id。继续通过名称查看容器id。

# docker命令查看容器
docker ps -a
5793a25376e431e6fcc7120dcdd44077bbd063.png

找到了容器id之后,可以看到用容器id的前几位,可以完全匹配到,日志文件夹名称的前几位。docker ps 显示的容器id只是显示了整个id的前几位。

a1b29fd71f19f4309681468166ce77d06c6e5f.png

a1e9eba08a03c8f84fd0833098636c22e7f723.png

进入到日志文件夹后,就可以看到具体的json日志文件了。

997b8a59536490d15ea2907a085cf8cea7ccd7.png

至此已经知道日志文件存放的位置了。当然啦,要控制好日志级别,还要做好日志清理任务,否则大量的日志会导致磁盘空间不够。Pod销毁之后,日志文件也会被销毁的。

文件找到了接下来,就看怎么采集日志了。

2.2、日志采集工具

日志采集工具有多种,本文采用Filebeat作为日志采集工具。

Filebeat是用于转发和汇总日志与文件的轻量级传送程序。作为服务器上的代理安装,Filebeat会监视你指定的日志文件或位置。然后收集日志事件,并将它们转发到Elasticsearch或Logstash或Kafka。官方文档显示的工作流程如下:

f48c14790834a61849f726bf58953581d581a6.png

Filebeat的主要优势有:

  • 轻量级并且易使用
  • 资源使用率低
  • 良好的性能

2.3、日志如何采集

日志采集工具选型确定之后,接下来就是如何采集了。

K8S部署的场景下,想要收集每台Node下的容器日志,需要采用Deamonset控制器自动部署,这样每次新增节点时,会自动部署Filebeat的Pod。每台Node自动安装好Filebeat后,每台Node上的日志会被自动采集,然后输出到Kafka。

Filebeat大致的编排yaml如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: ops-monit
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    filebeat.inputs:
    - type: container #因为是采集的容器日志,所以这里要用container 不能用 log,否则拿不到容器日志
      enable: true
      stream: stdout #只取stdout日志
      paths:
        - /var/log/containers/*demo*.log #采集了demo环境的所有日志
      processors:
        - add_kubernetes_metadata: # 增加kubernetes的属性
            in_cluster: true
            host: ${NODE_NAME}
            matchers:
            - logs_path:
                logs_path: "/var/log/containers/"
        - drop_event:
            when:
              contains:
                message: "INFO"
        - drop_event:
            when:
              contains:
                message: "DEBUG"
      # 配置多行显示
      multiline.type: pattern
      multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
      multiline.negate: true
      multiline.match: after
      fields:
        logtype: applog
    output.kafka:
      hosts: ['172.10.10.10:9092','172.10.10.11:9092','172.10.10.12:9092']
      topic: 'topic-bizlog'
      partition.round_robin:
        reachable_only: false
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
  namespace: ops-monit
  labels:
    k8s-app: filebeat
spec:
  selector:
    matchLabels:
      k8s-app: filebeat
  template:
    metadata:
      labels:
        k8s-app: filebeat
    spec:
      serviceAccountName: filebeat
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirstWithHostNet
      containers:
        - name: filebeat
          image: elastic/filebeat:7.12.1
          args: [
              "-c", "/etc/filebeat.yml",
              "-e",
          ]
          env:
            - name: ELASTICSEARCH_HOST
              value: "172.10.20.10"
            - name: ELASTICSEARCH_PORT
              value: "9200"
            - name: ELASTICSEARCH_USERNAME
              value:
            - name: ELASTICSEARCH_PASSWORD
              value:
            - name: ELASTIC_CLOUD_ID
              value:
            - name: ELASTIC_CLOUD_AUTH
              value:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
            # If using Red Hat OpenShift uncomment this:
            # privileged: true
          resources:
            limits:
              cpu: 3000m
              memory: 2000Mi
            requests:
              cpu: 500m
              memory: 100Mi
          volumeMounts:
            - name: timezone
              mountPath: /etc/localtime
            - name: config
              mountPath: /etc/filebeat.yml
              readOnly: true
              subPath: filebeat.yml
            - name: data
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog
              mountPath: /var/log
      volumes:
        - name: timezone
          hostPath:
            path: /usr/share/zoneinfo/Asia/Shanghai
        - name: config
          configMap:
            defaultMode: 0640
            name: filebeat-config
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
        - name: varlog
          hostPath:
            path: /var/log
        - name: data
          hostPath:
            path: /var/lib/filebeat-data
            type: DirectoryOrCreate
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: filebeat
  namespace: ops-monit
subjects:
  - kind: ServiceAccount
    name: filebeat
    namespace: ops-monit
roleRef:
  kind: ClusterRole
  name: filebeat
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: filebeat
  namespace: ops-monit
  labels:
    k8s-app: filebeat
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources:
      - namespaces
      - pods
      - nodes
    verbs:
      - get
      - watch
      - list
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: filebeat
  namespace: ops-monit
  labels:
    k8s-app: filebeat
---

3、日志缓冲、过滤清洗、存储、展示

3.1、缓冲

Kafka是一个消息处理引擎,这里采用Kafka作为日志数据的缓冲工具。采用Kafka有2个用途:

  • 作为缓冲,防止日志量太大导致下游来不及消费,所以要加入消息缓冲这一层。这一层必不可少。
  • Kafka消息可以被别的应用监听消费,过滤输出到一些告警信息到企微、钉钉、邮件等。

3.2、过滤清洗和转发

Logstash 是一个日志收集和处理引擎,它带有各种各样的插件,能够从各种来源摄取数据。并且可以对数据进行转换,然后转发到目的地。我这里采用Logstash作为日志摄取、过滤、清洗、转发的工具。

这是一个大概的Logstash Conf文件,文件的内容分3块:input 、filter 、output。

input {
    kafka {
        bootstrap_servers=>"172.10.7.79:9092"
        topics=>["topic-bizlogs"]
        codec => "json"
    }
}

filter{
    mutate{
        split => ["message", "|"]
        add_field => { "log_time" => "%{[message][0]}"}
        add_field => { "level" => "%{[message][1]}"}
        add_field => { "class" => "%{[message][2]}"}
        add_field => { "line" => "%{[message][3]}"}
        add_field => { "thread" => "%{[message][4]}"}
        add_field => { "log_message" => "%{[message][5]}"}

        add_field => { "env" => "%{[kubernetes][namespace]}"}
        add_field => { "podName" => "%{[kubernetes][pod][name]}"}
        add_field => { "podId" => "%{[kubernetes][pod][uid]}"}
        add_field => { "image" => "%{[container][image][name]}"}
        add_field => { "imageId" => "%{[container][id]}"}
        add_field => { "nodeId" => "%{[kubernetes][node][uid]}"}
        add_field => { "nodeName" => "%{[kubernetes][node][name]}"}
        add_field => { "nodeHostName" => "%{[kubernetes][node][hostname]}"}
        add_field => { "logPath" => "%{[log][file][path]}"}
        add_field => { "appName" => "%{[kubernetes][labels][app]}"}

        remove_field => ["agent","fields","input","ecs","host","@version","kubernetes","stream","log","container"]
    }
}

output{
        elasticsearch{
                hosts=>["172.11.4.82:9200"]
                index => "%{appName}‐%{+YYYY.MM.dd}"

        }
}

3.3、存储和搜索

Elasticsearch是一个可扩展的搜索引擎,这里采用Elasticsearch作为日志存储搜索工具。

3.4、展示

采用Kibana为日志构建可视化的UI。

本文主要介绍Kubernetes场景下比较接地气好落地的,基于ELK的日志解决方案。整体思路:Filebeat -> Kafka -> Logstash -> Elasticsearch -> Kibana。

本文没有介绍Kafka、Logstash、Elasticsearch、Kibana的安装,只提及了一些配置文件,安装过程读者自行查阅资料搭建。

责任编辑:华轩 来源: 不焦躁的程序员

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK