• Kubernetes 集群中日志采集的几种玩法¶


    简介

    对于企业的应用系统来说,日志的地位非常重要,特别是在 Kubernetes 环境,日志采集就更复杂,因此 DataKit 对日志采集提供了非常强劲的支持,支持多种环境、多种技术栈。接下来就对 DataKit 日志采集的使用方式做详细说明。

    前置条件

    登录 观测云,【集成】->【Datakit】-> 【Kubernetes】,请按照指引在 Kubernetes 集群中安装 DataKit ,其中部署使用的 datakit.yaml 文件,在接下来的操作中会使用到。

    DataKit 高级配置

    1 设置日志级别

    DataKit 默认日志级别是 Info,如果需要把日志级别调整为 Debug,请在 datakit.yaml 中增加环境变量。

    1. - name: ENV_LOG_LEVEL
    2. value: debug

    2 设置日志输出方式

    DataKit 默认会把日志输出到 /var/log/datakit/gin.log 和 /var/log/datakit/log,如果不想在容器中生成日志文件,请在 datakit.yaml 中增加环境变量。

    1. - name: ENV_LOG
    2. value: stdout
    3. - name: ENV_GIN_LOG
    4. value: stdout

    DataKit 产生的日志可以通过 kubectl 命令加 POD 名称查看日志。

    kubectl logs datakit-2fnrz -n datakit # 
    

    注意』:ENV_LOG_LEVEL 设置成 debug 后,会产生大量日志,此时不建议再把 ENV_LOG 设置成 stdout。

    日志采集

    1 stdout 采集

    1.1 stdout 日志全采集

    DataKit 可以采集输出到 stdout 的容器日志,使用 datakit.yaml 部署 DataKit 后默认已经开启了 container 采集器。

    1. - name: ENV_DEFAULT_ENABLED_INPUTS
    2. value: cpu,disk,diskio,mem,swap,system,hostobject,net,host_processes,container

    此时会在 DataKit 容器中生成 /usr/local/datakit/conf.d/container/container.conf 配置文件,默认配置是采集除了 pubrepo.jiagouyun.com/datakit/logfwd 开头的镜像外的所有 stdout 日志。

    1. container_include_log = [] # 相当于image:*
    2. container_exclude_log = ["image:pubrepo.jiagouyun.com/datakit/logfwd*"]

    1.2 自定义 stdout 日志采集

    为了更好的区分日志来源,增加 tag及 指定日志切割 pipeline 文件,这是就需要使用自定义方式了。即在部署的 yaml 文件中增加 annotations。

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. name: log-demo-service
    5. labels:
    6. app: log-demo-service
    7. spec:
    8. replicas: 1
    9. selector:
    10. matchLabels:
    11. app: log-demo-service
    12. template:
    13. metadata:
    14. labels:
    15. app: log-demo-service
    16. annotations:
    17. # 增加如下部分
    18. datakit/logs: |
    19. [
    20. {
    21. "source": "pod-logging-testing-demo",
    22. "service": "pod-logging-testing-demo",
    23. "pipeline": "pod-logging-demo.p",
    24. "multiline_match": "^\\d{4}-\\d{2}-\\d{2}"
    25. }
    26. ]

    Annotations 参数说明

    • source: 数据来源
    • service: tag标记
    • pipeline: pipeline 脚本名
    • ignore_status:
    • multiline_match: 正则表达式匹配一行日志,如示例中以日期(比如2021-11-26)开始的为一行日志,下行中如果不是此日期开始则认为此行日志是上条日志一部分
    • remove_ansi_escape_codes: 是否删除 ANSI 转义码,例如标准输出的文本颜色等

    1.3 不采集容器的 stdout 日志

    开启了容器采集器,会自动采集容器输出到 stdout 的日志,对于不想采集的日志,有以下几种方式。

    1.3.1 关闭 POD 的 STDOUT 日志采集

    在部署应用的 yaml 文件中增加 annotations,把 disable 设置成 true。

    1. apiVersion: apps/v1
    2. kind: Deployment
    3. metadata:
    4. ...
    5. spec:
    6. ...
    7. template:
    8. metadata:
    9. annotations:
    10. ## 增加下面内容
    11. datakit/logs: |
    12. [
    13. {
    14. "disable": true
    15. }
    16. ]

    1.3.2 标准输出重定向

    如果开启了 stdout 日志收集,容器的日志也输出到 stdout,两者都不想做修改的情况下,可以修改启动命令,让标准输出重定向。

    java ${JAVA_OPTS}   -jar ${jar} ${PARAMS}  2>&1 > /dev/null
    

    1.3.3 CONTAINER 采集器的过滤功能

    如果想更方便的控制 stdout 日志的采集,建议重写 container.conf 文件,即使用 ConfigMap 定义 container.conf,修改 container_include_log 和 container_exclude_log 的值,再挂载到 datakit 中。在 datakit.yaml修改如下:

    1. ---
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: datakit-conf
    6. namespace: datakit
    7. data:
    8. #### container
    9. container.conf: |-
    10. [inputs.container]
    11. docker_endpoint = "unix:///var/run/docker.sock"
    12. containerd_address = "/var/run/containerd/containerd.sock"
    13. enable_container_metric = true
    14. enable_k8s_metric = true
    15. enable_pod_metric = true
    16. ## Containers logs to include and exclude, default collect all containers. Globs accepted.
    17. container_include_log = []
    18. container_exclude_log = ["image:pubrepo.jiagouyun.com/datakit/logfwd*", "image:pubrepo.jiagouyun.com/datakit/datakit*"]
    19. exclude_pause_container = true
    20. ## Removes ANSI escape codes from text strings
    21. logging_remove_ansi_escape_codes = false
    22. kubernetes_url = "https://kubernetes.default:443"
    23. ## Authorization level:
    24. ## bearer_token -> bearer_token_string -> TLS
    25. ## Use bearer token for authorization. ('bearer_token' takes priority)
    26. ## linux at: /run/secrets/kubernetes.io/serviceaccount/token
    27. ## windows at: C:\var\run\secrets\kubernetes.io\serviceaccount\token
    28. bearer_token = "/run/secrets/kubernetes.io/serviceaccount/token"
    29. # bearer_token_string = ""
    30. [inputs.container.tags]
    31. # some_tag = "some_value"
    32. # more_tag = "some_other_value"
    1. volumeMounts:
    2. - mountPath: /usr/local/datakit/conf.d/container/container.conf
    3. name: datakit-conf
    4. subPath: container.conf
    • container_include 和 container_exclude 必须以 image 开头,格式为 "image:",表示 glob 规则是针对容器 image 生效
    • Glob 规则是一种轻量级的正则表达式,支持 * ? 等基本匹配单元

    比如只想采集镜像名包含 log-order,且镜像名不包含 log-pay,可以做如下配置。

    1. container_include_log = ["image:*log-order*"]
    2. container_exclude_log = ["image:*log-pay*"]

    注意』:如果某一 POD 开启了采集 stdout 日志,请不要在使用 logfwd 或者 socket 日志采集,否则日志会被重复收集。

    2 logfwd 采集

    这是一种使用 Sidecar 模式的日志采集方式, 即利用同一个 POD 内的容器共享存储,让 logfwd 以 Sidecar 的模式读取业务容器的日志文件,然后发送给 DataKit。具体使用,请参考 Pod 日志采集最佳实践 方案二。

    3 socket 采集

    DataKit 开通 Socket 端口比如 9542,日志会被推送到这个端口,Java 的 log4j、logback 支持日志推送。下面以 SpringBoot 集成 Logback 为例来实现 socket 日志采集。

    3.1 添加 Appender

    在 logback-spring.xml 文件中增加 socket Appender。

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <configuration scan="true" scanPeriod="60 seconds" debug="false">
    3. <springProperty scope="context" name="dkSocketHost" source="datakit.socket.host" />
    4. <springProperty scope="context" name="dkSocketPort" source="datakit.socket.port" />
    5. <contextName>logback</contextName>
    6. <!-- 日志根目录 -->
    7. <property name="log.path" value="./logs"/>
    8. <!-- 日志输出格式 -->
    9. <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - - %msg%n" />
    10. <!-- 打印日志到控制台 -->
    11. <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
    12. <encoder>
    13. <pattern>${log.pattern}</pattern>
    14. </encoder>
    15. </appender>
    16. ...
    17. <!--下面是增加的 Socket appender-->
    18. <appender name="socket" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    19. <!-- datakit host: logsocket_port -->
    20. <destination>${dkSocketHost}:${dkSocketPort}</destination>
    21. <!-- 日志输出编码 -->
    22. <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
    23. <providers>
    24. <timestamp>
    25. <timeZone>UTC+8</timeZone>
    26. </timestamp>
    27. <pattern>
    28. <pattern>
    29. {
    30. "severity": "%level",
    31. "appName": "${logName:-}",
    32. "trace": "%X{dd.trace_id:-}",
    33. "span": "%X{dd.span_id:-}",
    34. "pid": "${PID:-}",
    35. "thread": "%thread",
    36. "class": "%logger{40}",
    37. "msg": "%message\n%exception"
    38. }
    39. </pattern>
    40. </pattern>
    41. </providers>
    42. </encoder>
    43. </appender>
    44. <root level="INFO">
    45. <appender-ref ref="Console"/>
    46. <appender-ref ref="file_info"/>
    47. <appender-ref ref="socket" />
    48. </root>
    49. </configuration>

    3.2 增加配置

    在 SpringBoot 项目的 application.yml 文件中增加配置。

    1. datakit:
    2. socket:
    3. host: 120.26.218.200 #
    4. port: 9542

    3.3 添加依赖

    在 SpringBoot 项目的 pom.xml 中添加依赖。

    1. <dependency>
    2. <groupId>net.logstash.logback</groupId>
    3. <artifactId>logstash-logback-encoder</artifactId>
    4. <version>4.9</version>
    5. </dependency>

    3.4 DataKit 增加 logging-socket.conf 文件

    在 DataKit 的 datakit.yaml 文件中

    1. volumeMounts: # 此位置增加下面三行
    2. - mountPath: /usr/local/datakit/conf.d/log/logging-socket.conf
    3. name: datakit-conf
    4. subPath: logging-socket.conf
    5. ---
    6. apiVersion: v1
    7. kind: ConfigMap
    8. metadata:
    9. name: datakit-conf
    10. namespace: datakit
    11. data:
    12. logging-socket.conf: |-
    13. [[inputs.logging]]
    14. # only two protocols are supported:TCP and UDP
    15. sockets = [
    16. "tcp://0.0.0.0:9542",
    17. #"udp://0.0.0.0:9531",
    18. ]
    19. ignore = [""]
    20. source = "demo-socket-service"
    21. service = ""
    22. pipeline = ""
    23. ignore_status = []
    24. character_encoding = ""
    25. # multiline_match = '''^\S'''
    26. remove_ansi_escape_codes = false
    27. [inputs.logging.tags]
    28. # some_tag = "some_value"
    29. # more_tag = "some_other_value"

    关于 Socket 日志采集的更多内容,请参考 logback socket 日志采集最佳实践

    4 日志文件采集

    Linux 主机安装的 DataKit 采集该主机上的日志的方式是复制 logging.conf 文件,然后再修改 logging.conf 文件中的 logfiles 的值为日志的绝对路径。

    1. cd /usr/local/datakit/conf.d/log
    2. cp logging.conf.sample logging.conf

    在 Kubernetes 环境下,需要先把的 Pod 生成的日志目录 /data/app/logs/demo-system 挂载到宿主机上 /var/log/k8s/demo-system,再使用 Daemonset 部署DataKit ,挂载 /var/log/k8s/demo-system 目录,这样datakit 就能采集到宿主机上的 /rootfs/var/log/k8s/demo-system/info.log 日志文件。

    1. volumeMounts:
    2. - name: app-log
    3. mountPath: /data/app/logs/demo-system
    4. ...
    5. volumes:
    6. - name: app-log
    7. hostPath:
    8. path: /var/log/k8s/demo-system

    1. volumeMounts: # 此位置增加下面三行
    2. - mountPath: /usr/local/datakit/conf.d/log/logging.conf
    3. name: datakit-conf
    4. subPath: logging.conf
    5. ---
    6. apiVersion: v1
    7. kind: ConfigMap
    8. metadata:
    9. name: datakit-conf
    10. namespace: datakit
    11. data:
    12. #### logging
    13. logging.conf: |-
    14. [[inputs.logging]]
    15. ## required
    16. logfiles = [
    17. "/rootfs/var/log/k8s/demo-system/info.log",
    18. ]
    19. ## glob filteer
    20. ignore = [""]
    21. ## your logging source, if it's empty, use 'default'
    22. source = "k8s-demo-system-log"
    23. ## add service tag, if it's empty, use $source.
    24. #service = "k8s-demo-system-log"
    25. ## grok pipeline script path
    26. pipeline = ""
    27. ## optional status:
    28. ## "emerg","alert","critical","error","warning","info","debug","OK"
    29. ignore_status = []
    30. ## optional encodings:
    31. ## "utf-8", "utf-16le", "utf-16le", "gbk", "gb18030" or ""
    32. character_encoding = ""
    33. ## The pattern should be a regexp. Note the use of '''this regexp'''
    34. ## regexp link: https://golang.org/pkg/regexp/syntax/#hdr-Syntax
    35. multiline_match = '''^\d{4}-\d{2}-\d{2}'''
    36. [inputs.logging.tags]
    37. # some_tag = "some_value"
    38. # more_tag = "some_other_value"

    注意』:既然使用观测云收集日志,日志已经被持久化了,没必要再把日志落盘到宿主机,所以 Kubernetes 环境下不建议使用这种采集方式。

    Pipeline

    Pipeline 主要用于切割非结构化的文本数据,或者用于从结构化的文本中(如 JSON)提取部分信息。对日志来说主要是提取日志产生时间、日志级别等信息。这里特别说明 Socket 采集到的日志是 JSON 格式,需要切割后才能在搜索框按关键字搜索。Pipeline 使用详情,请参阅下面的文章。

    异常检测

    当日志出现异常,对应用影响很大的时候,使用观测云的日志异常检测功能,并配置告警,能及时把异常通知到观测对象,观测云的告警支持邮箱、钉钉、短信、企业微信、飞书等通知方式。下面以邮箱为例介绍一下告警。

    1 创建通知对象

    登录 观测云,【管理】->【通知对象管理】-> 【新建通知对象】,选择邮件组,输入名称和邮件地址。

    2 新建监控器

    点击【监控】->【新建监控器】-> 【日志监测】。

    输入规则名称,检测指标 log_fwd_demo 是采集日志时候配置的 source,后面的 error 是日志包含的内容,host_ip 是日志的标签,在事件内容可以使用 {{host_ip}} 把具体标签的值输出。触发条件填 1,标题和内容会以邮件的方式发送。填完后点击【保存】。

    3 配置告警

    在【监控器】界面,点击刚才创建的监控器,点击【告警配置】。

    告警通知对象选择第一步中创建的邮件组,选择告警沉默时间,点击【确定】。

    4 触发告警

    应用触发 error 日志,这时会收到通知邮件。

  • 相关阅读:
    apache-atlas-hive-hook-源码分析
    王老吉药业“关爱烈日下最可爱的人”公益活动在杭启动
    【老生谈算法】matlab实现Retinex理论的图像去雾算法源码——图像去雾算法
    PostgreSQL 与 Oracle 访问分区表执行计划差异
    微信小程序 24 播放音乐页的完善①
    grid布局之容器属性grid-auto-columns&grid-auto-rows
    verilog语言中条件编译ifdef的使用和例子
    ruoyi-nbcio增加websocket与测试页面
    QT C++ AES字符串加密实现
    算数练习——模拟
  • 原文地址:https://blog.csdn.net/DataFlux/article/details/126856649