16 - Logs - 挖掘系统内部发生的状况 (4/4) - 透过 Filebeat 收集 Infrastructure 中各种服务的细节资讯

Logs - 挖掘系统内部发生的状况 系列文章


本篇学习重点

  • 使用 Filebeat 收集使用主机 (Host) 所布署的 Infrastructure 当中 Logs 的方式
  • 使用 Filebeat 收集使用容器 (Container) 布署的 Infrastructure 当中 Logs 的建议做法

使用 Filebeat 收集使用主机 (Host) 所布署的 Infrastructure 当中的 Logs

当我们使用非容器化的布署方式,也就是直接在各主机上安装服务或应用程序时,我们要收集这些机器上的 Logs 时,可能会有二种方式:

直接在服务的机器上安装 Filebeat

例如我们在一个单纯的三层式服务架构之中,有以下三种服务的主机:

  • Apache Web Server
  • Java Backend Service
  • MySQL Database

而我们要收集这几台机器上的 Logs 时,我们会建议直接在每台主机上安装 Filebeat,并且在不同的机器上配置不同的 Inputs 与 Modules 设定值,来收取我们希望取得的 Logs,例如:

主机所安装的服务 希望收集的资讯 Inputs Modules 说明
Apache Web Server Apache access & error logs Apache 透过 Apache module 指定 accesserror Logs 的档案路径。
Java Backend Service Application logs Logfilestream 由於 Logs 的格式是自订义的,直接使用 filestream 来指定要 Logs 的档案来源路径,甚至要特别处理的 processors
MySQL Database MySQL logs MySQL 透过 MySQL module 指定 errorslowlog Logs 的档案路径。
主机本身 主机本身的系统日志,或是 auth logs System 透过 System module 指定 syslogauth Logs 的档案路径。

使用 Shared Drive 的方式收集 Logs

如果有使用 Shared drive 的方式,来简化『集中化收集日志』这件事的话,基本上就是在专门运行 Filebeat 的机器上,透过 NFS 之类的 Shared drives 取得各服务的日志。

使用这种方式,在 Filebeat 的 InputsModules 的配置上,没有特别的差异,只是会一口气将这些配置设定在同一个 Filebeat 身上,不过有个地方要特别注意,Filebeat 的 Logfilestream input,在使用网路共享或是云端应商的储存空间时,因为会使用磁碟机的 inode 资讯与 device id 当作档案的唯一识别,有时 shared drive 的这个值会改变,导致於已经处理过的档案,又重新被判断成是新的档案,造成重覆的传送,这部份会要透过自行产生唯一的识别 ID,并且指定 inode_maker 来避免这件事发生,细节请参考 官方文件 - Filebeat Input - Logs

使用 Filebeat 收集使用容器 (Container) 布署的 Infrastructure 当中的 Logs

Docker 环境的 Log 产生方式

当我们使用 Docker 来布署服务时,一般的做法都是在 Container 之中直接把 log 输出到 stdout 或是 stderr,并透过 Docker logging driver 去进行处理,而实际的档案预设会写在 Docker host 身上,例如在 linux 环境中,会写到 /var/lib/docker/containers/ 的路径底下。

注意:因为容器的生命周期可能随时会中断,一个有良好 scalability 的容器化架构的设计,会是 stateless 的,也就是当容器被关闭时,存在里面的 logs 就消失了,所以一般绝对不建议把 logs 直接写在 container 之中,至少也要使用 volume 的方式将 logs 写到会持久保存的另外的储存空间里。

收集所有 Docker Conainer 产生的 Logs

因此我们要使用 Filebeat 来收集所有 Docker Container 产生的 logs 时,我们其实就是针对 Docker host 的这个路径里的 logs 下手,这也是 Filebeat Container Inputs 所使用的方法。

注意:Docker Input 已经在 7.2 版时弃用 (deprecated) 了,之後请直接使用 Container Input。

而 Container Input 的设定方式如下:

filebeat.inputs:
- type: container
  paths: 
    - '/var/lib/docker/containers/*/*.log'

里面也可以在 stream 属性去设定只要针对 stdout 或是 stderr 的内容进行收集,细节可以参考 官方文件 - Filebeat Input - Container

注意:在这种使用一口气收集所有 Containers 产生的 logs 时,应该要搭配一些内建的 Processors,例如 add_docker_metadataadd_kubernetes_metadataadd_cloud_metadata,将产生 logs 的 container 或是 pod 的资讯增加在 logs 之中,以便於後续使用时能进行分辨。

使用 Kubernetes DaemonSet 收集 K8S Nodes 身上各 Pods 的 Logs

如同我们前面 11 - Metrics - 观察系统的健康指标 (5/6) - 使用 Metricbeat 掌握 Infrastructure 的健康状态 Kubernetes 篇 在介绍 Metricbea 时,提到在 Kubernetes 使用 DaemonSet 的方式同样的考量,可以确保每个 Node 身上有一个独立的 Filebeat pod 来进行收集整个 Nodes 上所有 Pods 里的 logs,并且传送到 Elasticsearch。

而在 Kubernetes 里,也如同前面『 Docker 环境的 Log 产生方式』运作的方式一样,因为 Pods 会是 stateless,因此一般我们也都会直接将 logs 透过 stdout 或是 stderr 送出,并且由运行这些 Pods 所在的 Node,写在实体的 disk 路径 /var/log/containers/*.log 之中,因此我们也就可以使用 DaemonSet 的方式来布署 Filebeat,并且将主机的 /var/log mount 到 Filebeat 身上,让他可以直接使用 Container Inputs 的方式,取的这个所有 Pods 产生的 logs。

例如以官方的 filebeat-kubernetes.yaml 为例 (以下仅截取 ConfigMap 与 DaemonSet 的主要配置,完整版请参考原始档案):

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: filebeat-config
  namespace: kube-system
  labels:
    k8s-app: filebeat
data:
  filebeat.yml: |-
    filebeat.inputs:
    - type: container
      paths:
        - /var/log/containers/*.log
      processors:
        - add_kubernetes_metadata:
            host: ${NODE_NAME}
            matchers:
            - logs_path:
                logs_path: "/var/log/containers/"

    # 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: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
      username: ${ELASTICSEARCH_USERNAME}
      password: ${ELASTICSEARCH_PASSWORD}
---
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:8.0.0
        args: [
          "-c", "/etc/filebeat.yml",
          "-e",
        ]
        env:
        - name: ELASTICSEARCH_HOST
          value: elasticsearch
        - name: ELASTICSEARCH_PORT
          value: "9200"
        - name: ELASTICSEARCH_USERNAME
          value: elastic
        - name: ELASTICSEARCH_PASSWORD
          value: changeme
        - 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
          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
          readOnly: true
      volumes:
      - name: config
        configMap:
          defaultMode: 0640
          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:
          # When filebeat runs as non-root user, this directory needs to be writable by group (g+w).
          path: /var/lib/filebeat-data
          type: DirectoryOrCreate
---
  • DaemonSet 有宣告 mount /var/lib/docker/container 以及 /var/log,让 Filebeat 可以取得 container 的 logs。

  • DaemonSet 有另外宣告 /var/lib/filebeat-data 当作 data 的 volumeMounts 来挂载到 container 内的 /var/share/filebeat/data 路径,让这个 DaemonSet 的 Filebeat 运作时的档案,是写到实体主机的 disk 之中,不会因为重启而造成资料的遗失。

  • 另外有特别使用 add_kubernetes_metadataprocessor,让这些一口气收集进来的各种 Pod 产生的 logs,加上 Pod NamePod UIDNamespaceLabels 的资讯,让我们在後续分析处理时,能分辨得出来是哪边产生的 log。

  • 有一段是注解掉的 autodiscovery 的配置,若是使用 Docker、Kubernetes、或是使用 Nomad 时,可以考虑使用 autodiscovery 的机制,让 container 或是 pod 动态增加时,也能够由 DaemonSet 自动开始收集新增加容器产生的 logs。

使用 Kubernetes SideCar 的方式收集 K8S Pod 里服务产生的实体 Logs

如果 Service container 写的是实体的 Logs 档案,另一种方式是我们可以使用 SideCar 的方法将 Logs 转成 stdoutstderr 的方式往外传送,以使用我们先前建议的容器化收集 logs 的方法。

首先将 Pod 中的 Service container 与 Sidecar container 使用 Shared Volume,让 Sidecar container 能够直接取得 Service container 产生 的 logs,并且 SideCar container 再负责将这个 logs tail 出来,输出到 stdoutstderr,这样後续就能同样的使用 DaemonSet 或是专门收集 log 的 pod 的机制,进行後续的处理。

参考资料

  1. 官方文件 - Filebeat Input - Logs
  2. 官方文件 - Filebeat Input - Container

查看最新 Elasticsearch 或是 Elastic Stack 教育训练资讯: https://training.onedoggo.com
欢迎追踪我的 FB 粉丝页: 乔叔 - Elastic Stack 技术交流
不论是技术分享的文章、公开线上分享、或是实体课程资讯,都会在粉丝页通知大家哦!


<<:  Chapter4 附录 贝兹曲线

>>:  [day19] 优惠券检查

DAY 12 SASS 间的相似之处

介绍完了前几天的 sass 各种用法,大家有没有觉得有些方法好像很类似? 像是 mixin 跟 ex...

AWS Academy LMS 申请开课 - 教师

AWS 所提供的 AWS Academy 教材可以透过 AWS Academy Learning M...

7. STM32-结合中断来做个红绿灯吧!

既然前几篇介绍了外部中断、Timer中断与USART,那接下来就结合这三种中断来模拟红绿灯出来吧。 ...

Day24 用python写UI-聊聊Text(一)

今天放假好开心,睡超饱的ヾ(^▽^))), 但是还是要起床发文啦~ Text顾名思义就是可以输入文字...

Thunkable学习笔记 2 - 加入Firebase登入功能(使用EMail)

Firebase提供现成的email/password验证功能供我们使用, thunkable提供s...