Kubernetes环境下的日志处理和传统虚拟机时代完全是两回事。应用日志写在容器内部,Pod一重建就没了;节点挂了,上面的日志更是无从找起。靠kubectl logs临时排查还行,可一旦要追溯三天前的错误、做日志检索或者接告警,就必须有一套完整的日志收集体系。市面上的方案看着五花八门,其实底层架构就那么几种,理解了采集原理,选型就不再是难事。

一、Kubernetes里日志到底存在哪里
先把日志的来源搞清楚,才能明白为什么采集这么麻烦。Kubernetes中的日志大致分三类。第一类是标准输出和标准错误,kubelet会把容器写到stdout、stderr的内容重定向到节点上的日志文件,路径通常是/var/log/pods/和/var/log/containers/下面的文件,后一个目录里放的是软链接。这类日志是最好采集的,因为格式统一、位置固定,Docker和containerd运行时都遵循这套约定。
第二类是容器内部文件日志。不少Java应用用log4j或者logback把日志写到容器里的/app/logs/目录,这类日志不会出现在标准输出里,kubelet不会帮你管理,容器一销毁文件就跟着没了。第三类是系统组件日志,比如kubelet自身、kube-proxy的日志,一般在节点的/var/log/目录下,或者需要通过journald来获取。
这三类日志的采集难度依次递增。标准输出日志挂载节点目录就能采到;容器内文件日志要么挂载emptyDir共享目录,要么用Sidecar把文件重新打到stdout;系统组件日志则要额外处理journald或者固定文件路径。选方案之前,先盘点自己集群里这三类日志各占多少,能少走很多弯路。
二、三种主流采集架构的原理与取舍
第一种是节点级DaemonSet部署,也是最普遍的做法。在Kubernetes里跑一个DaemonSet,采集器以Pod形式落到每个节点上,挂载/var/log/pods/和/var/log/containers/目录,直接读取节点上的日志文件。这个模式的好处是不侵入应用,应用Pod完全无感知,资源开销可控,一个节点一份采集器。缺点是只能读到节点文件系统里的日志,容器内部文件日志采不到,除非把目录挂出来。
第二种是Sidecar模式,在每个业务Pod里再塞一个采集容器,和主容器共享日志卷。下面是一个典型写法:
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: log-volume
mountPath: /app/logs
- name: log-agent
image: fluent-bit:latest
volumeMounts:
- name: log-volume
mountPath: /app/logs
volumes:
- name: log-volume
emptyDir: {}
Sidecar能解决容器内文件日志的采集问题,还能针对单个应用做定制化的解析规则。但代价也很明显:每个Pod多一个容器,资源消耗随Pod数量线性增长,采集器镜像要让所有业务团队接受,升级维护都要走一遍业务发布流程。一般来说,只有应用写文件日志且改造成本高时才考虑Sidecar,新应用更应该直接输出到stdout,把问题在源头解决。
第三种是节点Agent直接对接容器运行时接口,比如通过CRI接口按容器ID拉取日志,甚至有方案直接hook应用进程。这种模式最灵活,但对运行时版本有依赖,Kubernetes切换容器运行时(比如从Docker换到containerd)时容易踩坑,通用性不如读文件的方式,生产环境用得相对少。
三、EFK、Loki、Vector三大组合怎么选
架构定了,还要选具体的工具组合。EFK(Elasticsearch、Fluent Bit、Kibana)是最经典的一套:Fluent Bit做采集,Elasticsearch做存储和索引,Kibana做查询可视化。它的强项是全文检索,任意关键字秒级出结果,适合排查问题场景多的团队。短板是Elasticsearch资源吃得很凶,日志量大时存储成本和内存占用都不低,还得操心索引生命周期管理。
Loki是Grafana推出的轻量级方案,只索引标签不索引全文,日志按时间顺序压缩存储,查询靠标签过滤加顺序扫描。资源消耗能比Elasticsearch低一个数量级,配合Grafana界面也很顺手。代价是没有全文检索,如果你记得日志里某个报错关键字但不记得是哪个Pod打的,Loki就无能为力了。它适合标签体系清晰、主要按服务查日志的微服务场景。
Vector作为采集器是近年起来的新选择,用Rust写的,性能比Fluent Bit在高吞吐场景下更稳,配置用TOML或YAML,转换能力很强,还支持VRL自定义处理语言。Vector本身不管存储,后端可以接Elasticsearch、Loki、Kafka等,灵活性最好。如果日志量在每天TB级别,值得认真评估Vector加Kafka做缓冲的链路。
选型时可以这么判断:中小规模、检索需求强,选EFK最省心;标签化查询为主、成本敏感,Loki很合适;日志量巨大、需要复杂加工和多个下游,用Vector做采集层。另外无论选哪套,采集器和存储之间加一层Kafka做缓冲都值得考虑,能扛住下游故障时的日志堆积,避免日志丢失。
四、落地时的几个实践细节
第一,务必给日志采集打上Kubernetes元数据标签。采集器解析/var/log/pods/路径时能提取出namespace、Pod名、容器名,把这些作为标签带上,后面按服务、按命名空间过滤才有意义。Fluent Bit的kubernetes过滤插件、Vector的kubernetes_metadata转换都能做这件事。
第二,控制日志体量和成本。开发者随手打印的调试日志、健康检查接口的访问日志,往往占了存储的大头。在采集层配置日志级别过滤、字段裁剪和采样,比事后扩容Elasticsearch划算得多。同时配好存储的保留策略,比如业务日志保留七天、审计日志保留九十天,用索引生命周期管理或者Loki的compactor实现。
第三,注意多行日志的处理。Java的异常堆栈是一大坨多行文本,如果采集器没配多行合并,每一行都会变成独立日志,检索时惨不忍睹。Fluent Bit用multiline.parser,Vector用multiline转换,都要针对常见堆栈格式提前配好规则。
最后提醒一点,采集器本身也是DaemonSet,它的资源请求要合理设置,别为了省资源限得太死导致OOM重启,日志断流比日志系统本身故障还难排查。建议给采集链路加上简单的监控,关注采集延迟和丢弃计数,这套日志体系才算真正稳定可用。
Kubernetes日志收集EFK日志方案选型修改时间:2026-09-05 10:08:42