背景介绍

  目前公司的微服务是跑在IDC自建的K8S中,各个微服务的日志与前期开发沟通,约定日志输出规范,INFO和ERROR级别日志分开(当然每个公司的需求都不一样),但跑在K8S集群中的日志,如何收集及展示呢?提高研发效能,基于此,进行了K8S应用日志调研及部署。


K8S的日志收集难点

  k8s的日志相比于传统的基于物理机/虚拟机部署的场景有哪些不同点呢?

  1. 日志形式变得更加复杂:不仅有物理机/虚拟机上的系统日志,还有容器的标准输出日志,容器内的应用日志、容器事件日志、k8s事件等等日志都需要采集。

  2. 环境的动态变化:在k8s中,机器的宕机、上下线,Pod销毁/重建、扩缩容等等都是常态,这种情况的日志时瞬时的(例如Pod生命周期结束后,该Pod中的日志就没有了),这就要求日志采集能够使用这种环境动态的变化,也即是:日志需要实时采集到。

  3. 业务架构变化:现在也有好多公司在k8s中进行了落地架构,在微服务体系架构中,服务的开发变得更复杂,服务之间的依赖关系及服务底层之间的调用关系更加复杂,若出现异常情况,对于排障情况,更加复杂。

  4. 日志种类变化多样:当k8s真正落地到生产环境,且中大规模使用时,里面的日志种类是非常多的;就譬如一个用户从app发起一个请求,大致需要经过CDN、Ingress、Mesh、Pod、调用链日志(traceId)、App访问日志、App错误日志、中间件日志、审计日志、网络日志、系统组件日志、内核日志等。

  5. 日志规模:若业务量不是很大,业界都是都是自建开源的日志系统(我们也是自建的),这种方式没有打到一定的日志规模,都不会出现什么问题。若打到一定规模,自建的开源日志系统就出出现各种问题;例如 ES整个集群Hang、查询延迟、日志系统可用性等。当然了,公司有钱,直接上阿里云日志服务,省心省力、有时有问题,还有阿里云背锅(哈哈)或者基于开源的日志进行自研。不排查问题时,系统系统地位体现不到,尤其是出现关键问题,就知道日志系统的重要性;


基于以上几点,那日志系统需要哪些功能呢

  1. 全方位的日志采集;支持web、移动端、IoT、物理机、虚拟机各种数据源采集

  2. 日志实时

  3. 数据清洗

  4. 日志展现和搜索

  5. 实时分析:可以快速分析问题的根因;离线分析:通过连线分析提供一定是数据价值给运营或安全部门。

  6. 机器学习,通过对大量的历史日志数据进行离线训练,并将训练后的结果加载到线上实时的方法库中。就好比是历史技术文档,出现类似问题,就能找到处理方法


K8S的日志采集方案

 官方给出了3种方案

  1. Using a node logging agent

    image.png

  2. Using a sidecar container with the logging agent 

    image.png

    此方案,官方给出的是使用Fluentd插件,我们是使用Filebeat插件,原因如下:

    Kubernetes官方提供了EFK的日志收集解决方案,但是这种方案并不适合所有的业务场景,它本身就有一些局限性,例如:

      a. 所有日志都必须是out前台输出,真实业务场景中无法保证所有日志都在前台输出

      b. 只能有一个日志输出文件,而真实业务场景中往往有多个日志输出文件

      c. Fluentd并不是常用的日志收集工具,我们更习惯用logstash,现使用filebeat替代

         因Logstash是基于JDK的,在没有产生日志的情况单纯启动Logstash就大概要消耗500M内存,在每个Pod中都启动一个日志收集组件的情况下,使用logstash有点浪费系统资源;单独启动Filebeat容器大约会消耗12M内存,比起logstash相当轻量级

  3. Exposing logs directly from the applicatio

image.png

 可以参见kubernetes.io的官方介绍:https://kubernetes.io/docs/concepts/cluster-administration/logging/


以上各采集方式对比:

image.png

这里我们是使用方案二:Sidecar方式

整体情况介绍:

  1. 确保k8s集群能正常运行

  2. 确保es和kibana能正常运行且可访问,这里安装略,可参见官网

  3. 我这里使用filebeat版本为:7.8.1,将其镜像下载好后,然后推入到自己的私仓中,不然出现下载很慢很慢

  4. 确保有一个能跑通的jar应用,我这里集成了Jenkins 的CI/CD,通过触发job,自动将jar包生成镜像,并上传到我们的私仓中,然后进行deployment、创建Service、进行NodePort映射,通过nginx绑定nodeport(因我们应用不多,没有使用Ingress),结合内网DNS访问。关于Jenkins 与K8S集成CI/CD这里不做过介绍,因为每个公司的CI/CD都是不一样的。

cat deploy.yaml

---

apiVersion: v1

kind: ConfigMap

metadata:

  name: filebeat-config

  namespace: dev

  labels:

    k8s-app: filebeat

data:

  filebeat.yml: |-

    filebeat.inputs:

    - type: log

      enabled: true

      paths:

        - /logs/*

      multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'

      multiline.negate: true

      multiline.match: after

      multiline.timeout: 10s

    # To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:

    #filebeat.autodiscover:

    #  providers:

    #    - type: kubernetes

    #      node: ${NODE_NAME}

    #      hints.enabled: true

    #      hints.default_config:

    #        type: container

    #        paths:

    #          - /var/log/containers/*${data.kubernetes.container.id}.log


    processors:

      #- add_cloud_metadata:

      - add_host_metadata:


    cloud.id: ${ELASTIC_CLOUD_ID}

    cloud.auth: ${ELASTIC_CLOUD_AUTH}

    

    output.elasticsearch:

      hosts: ['192.168.1.101:9200']

      #username: ${ELASTICSEARCH_USERNAME}

      #password: ${ELASTICSEARCH_PASSWORD}

      index: "k8s-dev-%{+YYYY}"

    setup.template.name: "k8s-dev"

    setup.template.pattern: "k8s-dev-*"  

    setup.ilm.enabled: false

   

---

apiVersion: apps/v1

kind: Deployment

metadata:

  name: cd-web

  namespace: dev 

spec:

  selector:

    matchLabels:

      app: cd-web

  replicas: 2

  template:

    metadata:

      labels:

        app: cd-web

    spec:

      imagePullSecrets:

      - name: cd-registry

      containers:

      - image: harbor.ttsingops.com/beats/filebeat:7.8.1

        name: cd-web-filebeat

        args: [

          "-c", "/etc/filebeat.yml",

          "-e",

        ]

        env:

        - name: ELASTICSEARCH_HOST

          value: "192.168.1.101"

        - 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

        volumeMounts:

        - name: filebeat-config

          readOnly: true

          subPath: filebeat.yml

          mountPath: /etc/filebeat.yml

        - name: applogs

          mountPath: /logs


      - image: harbor.ttsingops.com/cd-web/cd-web:297

        name : cd-web-container

        imagePullPolicy: Always

        ports:

        - containerPort: 9090

        volumeMounts:

        - name: applogs

          mountPath: /data/logs/cd-web/

      volumes:

      - name: applogs

        emptyDir: {}

      - name: filebeat-config

        configMap:

          defaultMode: 0600

          name: filebeat-config

---

#Service

apiVersion: v1

kind: Service

metadata:

  name: cd-web

  namespace: dev

spec:

  type: NodePort

  ports:

  - port: 9090

    protocol: TCP

    targetPort: 9090

    nodePort: 39090

  selector:

    app: cd-web

image.png


查看Dashboard的filebeat容器的日志信息:

说明配置已采集到定义的日志文件了

image.png


最后通过Kibana来查询日志信息

image.png


最后访问api的Rest接口:

image.png


至此,k8s的应用日志收集完成,并成功的通过Kibana来展示,同时api接口也访问正常。