iLogtail和Loggie:K8S环境下日志收集利器


预计阅读时间5分钟

需求

在传统的使用虚拟机/云主机/物理机的时代,业务进程部署在固定的节点上,业务日志直接输出到宿主机上,运维只需要手动或者使用自动化工具把日志采集Agent部署在节点上,加一下Agent的配置,就可以开始采集日志了。而在Kubernetes环境中,情况就没这么简单了:

  • 「动态迁移」:在Kubernetes集群中经常存在Pod主动或者被动的迁移,频繁的销毁、创建,我们无法和传统的方式一样人为的给每个服务下发日志采集配置。
  • 「日志存储方式多样性」:容器的日志存储方式有很多不同的类型,例如stdout、hostPath、emptyDir、pv等。
  • 「Kubernetes元信息」:由于日志数据采集后会被集中存储,所以查询日志时,需要根据namespace、pod、container、node,甚至包括容器的环境变量、label等维度来检索、过滤,此时要求Agent感知并默认在日志里注入这些元信息。

以上都是有别于传统日志采集配置方式的需求和痛点,究其原因,还是因为传统的方式脱离了Kubernetes,无法感知Kubernetes,无法和Kubernetes集成。

解决方案

针对以上痛点,我们特对Kubernetes环境下的日志收集方式进行整理总结。

1.iLogtail

iLogtail 为可观测场景而生,拥有的轻量级、高性能、自动化配置等诸多生产级别特性,在阿里巴巴以及外部数万家阿里云客户内部广泛应用。你可以将它部署于物理机,虚拟机,Kubernetes等多种环境中来采集遥测数据,例如logs、traces和metrics。https://ilogtail.gitbook.io/ilogtail-docs/about/readme

ilogtail的核心优势:

  • 支持多种Logs、Traces、Metrics数据采集,尤其对容器、Kubernetes环境支持非常友好
  • 数据采集资源消耗极低,相比同类遥测数据采集的Agent性能好5-20倍
  • 高稳定性,在阿里巴巴以及数万阿里云客户生产中使用验证,部署量近千万,每天采集数十PB可观测数据
  • 支持插件化扩展,可任意扩充数据采集、处理、聚合、发送模块
  • 支持配置远程管理,支持以图形化、SDK、K8s Operator等方式进行配置管理,可轻松管理百万台机器的数据采集
  • 支持自监控、流量控制、资源控制、主动告警、采集统计等多种高级特性

2.Loggie

Loggie是一个基于Golang的轻量级、高性能、云原生日志采集Agent和中转处理Aggregator,支持多Pipeline和组件热插拔。https://loggie-io.github.io/docs/

Loggie的优势与特性:

  • 可扩展、热插拔:配置不同的Source/Interceptor/Sink,获得中转、过滤、解析、切分等能力,可快速自研插件
  • 强隔离:多Pipeline设计,减少互相干扰,支持同时发送多个不同数据源
  • 轻量级、高性能:基于Golang,极少的资源占用,强大的吞吐性能,满足各类场景需求
  • 可靠性保障:完善的日志可观测性,原生Prometheus metrics支持,还有限流、背压等Interceptor
  • 云原生:配置中心集成Kubernetes,创建CRD实例即可采集容器或节点日志
  • 不仅仅是日志:数据流基于Source/Interceptor/Sink模型,可采集各种可观测性事件,扩展更多的可能性

应用

本次应用以iLogtail为主,以收集nginx和java日志为示例。

1.快速部署

# 1.创建命名空间
wget https://raw.githubusercontent.com/alibaba/ilogtail/main/example_config/start_with_k8s/ilogtail-ns.yaml
kubectl apply -f ilogtail-ns.yaml

# 2.configmap 定义配置文件
wget https://raw.githubusercontent.com/alibaba/ilogtail/main/example_config/start_with_k8s/ilogtail-user-configmap.yaml
kubectl apply -f ilogtail-user-configmap.yaml

# 3.DaemonsSet 部署应用
wget https://raw.githubusercontent.com/alibaba/ilogtail/main/example_config/start_with_k8s/ilogtail-daemonset.yaml
kubectl apply -f ilogtail-daemonset.yaml

2.收集Nginx日志

# 1.Deployment部署Nginx
wget https://raw.githubusercontent.com/alibaba/ilogtail/main/example_config/start_with_k8s/nginx-deployment.yaml
kubectl apply -f nginx-deployment.yaml
# 2.访问日志
kubectl exec nginx- -- curl localhost/hello/ilogtail
# 3.查看测试日志
# 注意:需要查看和nginx 在同一个node节点上的ilogtail-ds
kubectl logs ilogtail-ds- -n ilogtail
# json格式化后,日志查看
{
 "_time_": "2022-07-15T00:36:48.489153485+08:00",
 "_source_": "stdout",
 "_image_name_": "docker.io/library/nginx:latest",
 "_container_name_": "nginx",
 "_pod_name_": "nginx-76d49876c7-r892w",
 "_namespace_": "default",
 "_pod_uid_": "07f75a79-da69-40ac-ae2b-77a632929cc6",
 "_container_ip_": "10.223.0.154",
 "remote_addr": "::1",
 "remote_user": "-",
 "time_local": "14/Jul/2022:16:36:48",
 "method": "GET",
 "url": "/hello/ilogtail",
 "protocol": "HTTP/1.1",
 "status": "404",
 "body_bytes_sent": "153",
 "http_referer": "-",
 "http_user_agent": "curl/7.74.0",
 "http_x_forwarded_for": "-",
 "__time__": "1657816609"
}

从JSON日志中我们可以看出,除了Nginx日志常规的字段,ilogtail还增加了namespace、pod、container、node等各维度的容器信息。

「iLogtail 配置文件解析」

# ilogtail-user-configmap.yaml 配置文件
nginx_stdout.yaml: |
   enable: true
   inputs:
     - Type: service_docker_stdout
       Stderr: false
       Stdout: true                # only collect stdout
       IncludeK8sLabel:
         app: nginx                # choose containers with this label
   processors:
     - Type: processor_regex       # structure log
       SourceKey: content
       Regex: '([\d\.:]+) - (\S+) \[(\S+) \S+\] \"(\S+) (\S+) ([^\\"]+)\" (\d+) (\d+) \"([^\\"]*)\" \"([^\\"]*)\" \"([^\\"]*)\"'
       Keys:
         - remote_addr
         - remote_user
         - time_local
         - method
         - url
         - protocol
         - status
         - body_bytes_sent
         - http_referer
         - http_user_agent
         - http_x_forwarded_for
   flushers:
     - Type: flusher_stdout
       OnlyStdout: true

ilogtail-user-configmap.yaml 配置文件中关于nginx日志收集配置,位于nginx_stdout.yaml处:

  1. 输入inputs
  • Type,容器标准输出插件即service_docker_stdout
  • Stdout、Stderr,是否采集标准输出错信息
  • IncludeK8sLabel,通过Kubernetes Label(定义在template.metadata中)白名单指定待采集的容器
  1. 处理processors
  • Type,processor_regex插件可以通过正则匹配的模式实现文本日志的字段提取
  • SourceKey,原始字段名
  • Regex,正则表达式,使用()标注待提取的字段
  • Keys,提取的字段名,例如["ip", "time", "method"]
  1. 输出flushers
  • Type,flusher_stdout插件可以实现将采集到的数据,经过处理后,打印到标准输出或者自定义文件
  • OnlyStdout,是否打印打印到标准输出,true表示标准输出;false表示文件;

3.收集Java日志

通过以上Nginx日志的收集,我们已经对ilogtail有了大致的了解,因此我们进一步探索Java日志的收集,先来分析下Java日志收集的需求:

  • Java日志打印在文件,而非容器标准输出
  • Java日志一般为多行日志,因此我们需要对日志按日期分行
  • Java日志是否有规范,例如按日期、应用名、子线程、父线程等字段进行定义,以便后续排查问题

以上都是在真正进行Java日志收集前需要了解的。下面我们再来确定下ilogtail 对Java多行日志文件的收集配置:

log_file.yaml: |
enable: true
inputs:
 - Type: file_log
   LogPath: /data/logs/
   FilePattern: java.log
processors:
 - Type: processor_split_log_regex
   SplitRegex: \d+-\d+-\d+\s\d+:\d+:\d+\s\[.*
   SplitKey: content
   PreserveOthers: true
flushers:
 - Type: flusher_stdout
   OnlyStdout: true

通过实际运行,ilogtail对Java多行日志文件的收集并没有像期望的那样收集成功。经仔细阅读官方文档,并对配置文件进行了如下修改才成功收集,我们来具体分析下:

log_file.yaml: |
enable: true
inputs:
 - Type: file_log
   LogPath: /data/logs/
   FilePattern: "*.log"
   MaxDepth: 5
   ContainerFile: true
   ContainerInfo:
     IncludeK8sLable:
       log: java
processors:
 - Type: processor_split_log_regex
   SplitRegex: \d+-\d+-\d+\s\d+:\d+:\d+\s\[.*
   SplitKey: content
   PreserveOthers: true
flushers:
 - Type: flusher_stdout
   OnlyStdout: true

Java日志按规范要求:

  • 日志目录为/data/logs;
  • 日志名以 *.log 结尾;
  • 日志目录深度不固定,但5层深度肯定是够的;
  • 日志字段格式,以通用为主,可按需定义;

最终的具体定义如下:

  1. 输入inputs
  • Type,file_log插件可以实现从文本文件中采集日志。采集的日志内容将会保存在content字段中,后续对该字段进行处理,以实现日志格式的解析。此外,通过__tag__:__path__字段也可以查看日志的采集路径。
  • LogPath,采集文本日志所在的目录,支持完整目录和通配符两种模式。
  • FilePattern,采集文本日志的文件名,支持完整文件名和通配符两种模式。
  • MaxDepth,日志目录被监控的最大深度,范围:0~1000。如果未添加该参数,则默认使用0,代表只监控本层目录。
  • ContainerFile,iLogtail与待采集日志是否处于不同环境中。「若待采集的日志和iLogtail在不同的容器中,请将参数值置为true,其余情况请置为false。」

注意:正是由于ilogtail和采集的日志处于不同的命名空间和容器,导致日志收集不成功。

  • ContainerInfo,容器相关参数,仅当ContainerFile参数为true时有效。
  • IncludeK8sLable,对于部署于K8s环境的容器,指定待采集容器所在Pod的标签条件,多个条件之间为“或”的关系,即Pod标签满足任一条件即可匹配并被采集。
  • log: java,通过标签采集特定Key:Value的pod。
  1. 处理processors
  • Type,processor_split_log_regex processor插件实现多行日志(例如Java程序日志)的采集。备注:该插件必须设置为processor的第一个插件。
  • SplitKey,切分依据的字段
  • SplitRegex,行首正则,只有匹配上的才认为是多行日志块的行首。默认为.*,表示每行都进行切分。
  • PreserveOthers,是否保留其他非SplitKey字段。
  1. 输出flushers
  • Type,flusher_stdout插件可以实现将采集到的数据,经过处理后,打印到标准输出或者自定义文件
  • OnlyStdout,是否打印打印到标准输出,true表示标准输出;false表示文件

总结

至此我们只是带大家对Kubernete容器环境下的日志收集进行了初步的介绍,但是在实际使用过程中,我们还需要多关注下以下几个方面:

  • stdout、hostPath、emptyDir、pv 日志存储方式
  • DaemonSet / Sidecar 哪一种方式更适合来部署ilogtail及loggie
  • Pod动态迁移下日志收集



请使用浏览器的分享功能分享到微信等