木讷大叔爱运维

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

Image

点击上方蓝色字体,关注我们

预计阅读时间5分钟Image

Image

需求

在传统的使用虚拟机/云主机/物理机的时代,业务进程部署在固定的节点上,业务日志直接输出到宿主机上,运维只需要手动或者使用自动化工具把日志采集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-<pod-id> -- curl localhost/hello/ilogtail
# 3.查看测试日志
# 注意:需要查看和nginx 在同一个node节点上的ilogtail-ds
kubectl logs ilogtail-ds-<pod-id> -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动态迁移下日志收集

Image

添加好友,邀你入群,运维人的圈子,每日精彩分享,更有大咖解惑!

对的那条路,往往不是最好走的!

精彩文章合集

文章推荐

☞【合集】运维思索系列
☞【合集】运维管理系列
☞【合集】运维监控之路
☞【合集】基础设施自动化之路
☞【合集】CI/CD之路
☞【合集】Ansible之路
☞【合集】K8S之路
☞【合集】数据库系列

札记:“头等舱可以优先登机;银行vip可以不用排队;演唱会最贵的票位置也是最好的,这个世界从来就不公平。所以,你有多努力,你就有多特殊”。

喜欢这篇文章,记得点赞+在看哦~