
需求
在传统的使用虚拟机/云主机/物理机的时代,业务进程部署在固定的节点上,业务日志直接输出到宿主机上,运维只需要手动或者使用自动化工具把日志采集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处:
输入inputs
Type,容器标准输出插件即service_docker_stdout Stdout、Stderr,是否采集标准输出错信息 IncludeK8sLabel,通过Kubernetes Label(定义在template.metadata中)白名单指定待采集的容器
处理processors
Type,processor_regex插件可以通过正则匹配的模式实现文本日志的字段提取 SourceKey,原始字段名 Regex,正则表达式,使用()标注待提取的字段 Keys,提取的字段名,例如["ip", "time", "method"]
输出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层深度肯定是够的; 日志字段格式,以通用为主,可按需定义;
最终的具体定义如下:
输入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。
处理processors
Type,processor_split_log_regex processor插件实现多行日志(例如Java程序日志)的采集。备注:该插件必须设置为processor的第一个插件。 SplitKey,切分依据的字段 SplitRegex,行首正则,只有匹配上的才认为是多行日志块的行首。默认为.*,表示每行都进行切分。 PreserveOthers,是否保留其他非SplitKey字段。
输出flushers
Type,flusher_stdout插件可以实现将采集到的数据,经过处理后,打印到标准输出或者自定义文件 OnlyStdout,是否打印打印到标准输出,true表示标准输出;false表示文件
总结
至此我们只是带大家对Kubernete容器环境下的日志收集进行了初步的介绍,但是在实际使用过程中,我们还需要多关注下以下几个方面:
stdout、hostPath、emptyDir、pv 日志存储方式 DaemonSet / Sidecar 哪一种方式更适合来部署ilogtail及loggie Pod动态迁移下日志收集