• filebeat收集kubernets日志到ES集群


    Kubernetes中部署ELK Stack日志收集平台

    1 、ELK概念

    ELK是Elasticsearch、Logstash、Kibana三大开源框架首字母大写简称。市面上也被成为Elastic Stack。其中:

    Elasticsearch是一个基于Lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。像类似百度、谷歌这种大数据全文搜索引擎的场景都可以使用Elasticsearch作为底层支持框架,可见Elasticsearch提供的搜索能力确实强大,市面上很多时候我们简称Elasticsearch为es。官方网站:https://www.elastic.co/cn/products/  ;

    Logstash是ELK的中央数据流引擎,用于从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过过滤后支持输出到不同目的地(文件/MQ/redis/elasticsearch/kafka等);

    Kibana可以将elasticsearch的数据通过友好的页面展示出来,提供实时分析的功能。 通过上面对ELK简单的介绍,我们知道了ELK字面意义包含的每个开源框架的功能。市面上很多开发只要提到ELK能够一致说出它是一个日志分析架构技术栈总称,但实际上ELK不仅仅适用于日志分析,它还可以支持其它任何数据分析和收集的场景,日志分析和收集只是更具有代表性。并非唯一性。我们本教程主要也是围绕通过ELK如何搭建一个生产级的日志分析平台来讲解ELK的使用;

    2、收集日志的对象

    (1)、k8s系统组件日志

    (2)、k8s部署应用中的日志

    3、日志采集方案

    采集流程:

    使用ELK+Filebeat架构,还需要明确Filebeat采集K8S集群日志的方式。

    方案一:Node上部署一个日志收集程序

    使用DaemonSet的方式去给每一个node上部署日志收集程序logging-agent 然后使用这个agent对本node节点上的/var/log和/var/lib/docker/containers/两个目录下的日志进行采集 或者把Pod中容器日志目录挂载到宿主机统一目录上,这样进行收集

    Docker默认的日志驱动(LogDriver)是json-driver,其会将日志以JSON文件的方式存储。所有容器输出到控制台的日志,都会以*-json.log的命名方式保存在/var/lib/docker/containers/目录下。

    方案二:Pod中附加专用日志收集的容器

     

    每个运行应用程序的Pod中增加一个日志收集容器,使用emtyDir共享日志目录让日志收集程序读取到。

    方案三:应用程序直接推送日志

     

    这个方案需要开发在代码中修改直接把应用程序直接推送到远程的存储上,不再输入出控制台或者本地文件了,使用不太多

    4、方案对比:

    方式

    优势

    缺点

    方案一:Node上部署一个日志收集程序

    每个Node仅需部署一个日志收集程序,资源消耗少,对应用无侵入

    应用程序日志需要写到标准输出和标准错误输出,不支持多行日志

    方案二:Pod中附加专用日志收集的容器

    低耦合,扩展性强,方便和升级

    每个Pod启动一个日志收集代理,增加资源消耗,并增加运维维护成本

    方案三:应用程序直接推送日志

    无需额外组件

    侵入应用,增加应用复杂度

    相对来说,方式1在业界使用更为广泛,并且官方也更为推荐。因此,最终我们采用ELK+Filebeat架构,并基于方式1,如下:

     

     (我这里直接把日志导入到ES集群,没有用到kafka和logstash)

    5、 K8S中日志采集应该注意的问题

    问题1: 一个K8S集群我们需要收集哪些日志?

    这里只是以主要收集日志为例:

    • K8S系统的组件日志
    • K8S Cluster里面部署的应用程序日志

      -标准输出   -日志文件

    问题2: 我们需要收集的日志在哪里,如何去收集当下比较常用的runtime?

    docker和containerd的容器日志及相关参数

    对比项

    Docker

    Containerd

    存储路径

    docker作为k8s容器运行时的情况下,容器日志的落盘由docker来完成, 默认保存在/var/lib/docker/containers/$CONTAINERID目录下。kubelet会在/var/log/pods和/var/log/containers下面建立软链接,指向/var/lib/docker/containers/$CONTAINERID目录下的容器日志文件

    containerd作为k8s容器运行时的情况下, 容器日志的落盘由kubelet来完成,保存到/var/log/pods/$CONTAINER_NAME目录下,同时在/var/log/containers目录下创建软链接,指向日志文件

    配置参数

    在docker配置文件中指定: "log-driver": "json-file", "log-opts": {"max-size": "100m","max-file": "5"}

    方法一:在kubelet参数中指定:   --container-log-max-files=5 --container-log-max-size="100Mi"

    方法二:在KubeletConfiguration中指定:     "containerLogMaxSize": "100Mi",     "containerLogMaxFiles": 5

    把容器日志保存到数据盘

    把数据盘挂载到"data-root"(缺省是/data/var/lib/docker)即可

    创建一个软链接/var/log/pods指向数据盘挂载点下的某个目录(ln -s /data/var/log/pods /var/log/)


    无论k8s使用哪种容器运行时,最终的日志都是读取的xxx-json.log,是由容器以json格式stdout输出的,了解这些后我们得到了统一的日志收集规则:

    统一目录 :/var/log/containers

    统一的输出方式:stdout

    统一的日志格式:json 

    6、部署

    (1)环境

    kubernets平台使用kubeadm创建

    ES集群是独立三台服务器创建的ES集群(参见:https://www.cnblogs.com/xiaoyou2018/p/13754943.html)

    192.168.1.194

    192.168.1.195

    192.168.1.198

    (2)部署filebeat收集kubernets的test-meeu空间的日志

    filebeat.yml  (注意yml格式,前后都不要有多的tab和空格)

    获取kubernets的test-xx这个空间的日志

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: filebeat-config
      namespace: kube-system
      labels:
        k8s-app: filebeat
    data:
      filebeat.yml: |-
        filebeat.inputs:
        - type: container
            multiline.type: pattern
            multiline.pattern: '^\d{4}-\d{2}-\d{2}' #把不以时间开头的日志,归结为一行;示例“2021-12-21”
            multiline.negate: true
            multiline.match: after
          enabled: true
          paths:
          - /var/log/containers/*_test-xx_*log #需要采集的日志的目录
          fields:
            namespace: test-xx #采集的K8S空间名称
            env: dev
            k8s: cluster-dev
          processors: #test-meeu的“收集者”的属性设置
            - add_kubernetes_metadata: # 增加kubernetes的属性
                host: ${NODE_NAME}
                matchers:
                - logs_path:
                    logs_path: "/var/log/containers/"
        processors: #全局“收集者”的属性设置
          - add_cloud_metadata: # 增加cloud属性
          - add_host_metadata: # 增加k8s node节点属性
          - dissect: #从某个字段里(默认message)取值,按照tokenizer定义的格式 拆分(切割)数据,并输出到target_prefix 字段里,默认是dissect
              when: 
                or:
                  - contains:
                      message: "  INFO"
                  - contains:
                      message: "  WARN"
              tokenizer: "%{} %{}  %{loglevel} %{}"
              field: "message"
              target_prefix: ""
              trim_values: "all"
          - dissect: #参考https://www.elastic.co/guide/en/beats/filebeat/current/dissect.html
              when: 
                or:
                  - contains:
                      message: " ERROR"
                  - contains:
                      message: " DEBUG"
              tokenizer: "%{} %{} %{loglevel} %{}"
              field: "message"
              target_prefix: ""
              trim_values: "all"
          - drop_fields: #去除掉某些字段
              fields: ["host.os.family","_id","_index","_score","_type","agent.ephemeral_id","agent.hostname","agent.id","agent.name","agent.type","agent.version","ecs.version","host.architecture","host.containerized","host.hostname","host.id","host.ip","host.mac","host.name","host.os.codename","host.os.kernel","host.os.name","host.os.platform","host.os.type","host.os.version","input.type","kubernetes.labels.app","kubernetes.namespace_labels.name","kubernetes.node.labels.beta_kubernetes_io/arch","kubernetes.node.labels.beta_kubernetes_io/os","kubernetes.node.labels.kubernetes_io/arch","kubernetes.node.labels.kubernetes_io/hostname","kubernetes.node.labels.kubernetes_io/os","kubernetes.node.uid","log.offset","fields.env","fields.k8s","fields.namespace","log.file.path","kubernetes.namespace_uid","container.id","container.image.name","container.runtime","kubernetes.labels.pod-template-hash","kubernetes.labels.timestamp","kubernetes.node.hostname","kubernetes.replicaset.name","kubernetes.node.labels.scene"]      
        cloud.id: ${ELASTIC_CLOUD_ID}
        cloud.auth: ${ELASTIC_CLOUD_AUTH}
        setup.template.settings: #设置索引3主分片和0副本(索引自动生成,格式是 "filebeat-%{[beat.version]}-%{+yyyy.MM.dd}"(例如 "filebeat-7.15.2-2021.12.17"))
          index.number_of_shards: 3
          index.number_of_replicas: 0
        setup.template.name: "filebeat"
        setup.template.pattern: "filebeat*"
        setup.ilm.enabled: false
        output.elasticsearch: #输出到ES集群
           hosts: ["192.168.1.194:9200","192.168.1.195:9200","192.168.1.198:9200"]
           username: "elastic"
           password: "5yKsAQ4hgbBo0jxxxx"
        setup.kibana:
          host: '192.168.1.194:5601'
        setup.dashboards.enabled: true
        setup.template.enabled: true
    ---
    # Source: filebeat/templates/filebeat-service-account.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: filebeat
      namespace: kube-system
      labels:
        k8s-app: filebeat
    
    ---
    # Source: filebeat/templates/filebeat-role.yaml(RBAC 权限)
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRole
    metadata:
      name: filebeat
      labels:
        k8s-app: filebeat
    rules:
    - apiGroups: [""] # "" indicates the core API group
      resources:
      - namespaces
      - pods
      - nodes
      verbs:
      - get
      - watch
      - list
    
    ---
    # Source: filebeat/templates/filebeat-role-binding.yaml(RBAC 权限)
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: filebeat
    subjects:
    - kind: ServiceAccount
      name: filebeat
      namespace: kube-system
    roleRef:
      kind: ClusterRole
      name: filebeat
      apiGroup: rbac.authorization.k8s.io
    ---
    # Source: filebeat/templates/filebeat-daemonset.yaml
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: filebeat
      namespace: kube-system
      labels:
        k8s-app: filebeat
    spec:
      selector:
        matchLabels:
          k8s-app: filebeat
      template:
        metadata:
          labels:
            k8s-app: filebeat
        spec:
          serviceAccountName: filebeat
          terminationGracePeriodSeconds: 30
          hostNetwork: true
          dnsPolicy: ClusterFirstWithHostNet
          containers:
          - name: filebeat
            image: docker.elastic.co/beats/filebeat:7.15.2
            args: [
              "-c", "/etc/filebeat.yml",
              "-e",
            ]
            env:
            - name: ELASTICSEARCH_HOST
              value: "192.168.1.194" # 指定其中一个ES的地址
            - name: ELASTICSEARCH_PORT
              value: "9200"
            - name: ELASTICSEARCH_USERNAME
              value: elastic
            - name: ELASTICSEARCH_PASSWORD
              value: 5yKsAQ4hgbBo0juxxxx
            - 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:
                memory: 200Mi
              requests:
                cpu: 100m
                memory: 100Mi
            volumeMounts:
            - name: config #挂载的是filebeat的配置文件
              mountPath: /etc/filebeat.yml
              readOnly: true
              subPath: filebeat.yml
            - name: data ##持久化filebeat数据到宿主机上
              mountPath: /usr/share/filebeat/data
            - name: varlibdockercontainers #这里主要是把宿主机上的源日志目录挂载到filebeat容器中
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: varlog #这里主要是把宿主机上/var/log/pods和/var/log/containers的软链接挂载到filebeat容器中
              mountPath: /var/log
              readOnly: true
            - name: timezone
              mountPath: /etc/localtime
          volumes:
          - name: config
            configMap:
              defaultMode: 0600
              name: filebeat-config
          - name: varlibdockercontainers
            hostPath:
              path: /var/lib/docker/containers
          - name: varlog
            hostPath:
              path: /var/log
          # data folder stores a registry of read status for all files, so we don't send everything again on a Filebeat pod restart
          - name: data
            hostPath:
              path: /data/filebeat-data
              type: DirectoryOrCreate
          - name: timezone
            hostPath:
              path: /etc/localtime
          tolerations: #加入容忍能够调度到每一个节点
          - effect: NoSchedule
            operator: Exists

    (3)设置索引的生命周期

    设置日志保留30天

     

    展示

     日志格式

     

     参考:

    https://blog.csdn.net/qq_27818541/article/details/108229185

    https://www.elastic.co/guide/en/beats/filebeat/current/decode-json-fields.html

    https://www.elastic.co/guide/en/beats/filebeat/current/defining-processors.html

    https://www.coder.work/article/7399194

  • 相关阅读:
    Spring messageSource
    Spring MVC集成Tiles使用方法
    Jquery发送ajax请求以及datatype参数为text/JSON方式
    怎样使用jsp实现header和footer与网页内容的分离
    jsp:include怎么设置才能正确显示包含的页面呢
    JSP中两种include的区别
    让html文件也具体include包含的功能
    DWZ中uploadify多文件上传
    DWZ+Uploadify +JSON 多文件上传
    dwz+jquery+fileupload+springmvc实现文件上传 及图片预览
  • 原文地址:https://www.cnblogs.com/xiaoyou2018/p/15702614.html
Copyright © 2020-2023  润新知