本文简单整理 Kubernetes 里关于容器应用日志的四种收集方式。
文章目录
首先解释下容器日志原则:
- 日志收集方案一般需要想办法把日志数据转发到后端(Loging Backend)里存储然后处理。
- 因为Kubernetes 里面对容器日志的处理过程应该与容器、Pod 以及 Node 的生命周期都是完全无关的。这种设计是为了保证,无论是容器挂了、Pod 被删除,甚至节点宕机的时候,应用的日志依然可以被正常获取到。
下面整理几种日志收集方案:
一、直接指定方案
(app容器 - 后端)
最直接的方式,在编写应用的时候,就直接指定好日志的存储后端,如下所示:
在这种方案下,Kubernetes 就完全不必操心容器日志的收集了。但这仅适用于本身已经有完善的日志处理系统的公司。
二、NodeAgent 方案
(app容器 - [stdout/stderr] - NodeAgent - 后端)
这个方案,在社区里是最常用的一种。
在 Node 上部署 logging agent(一般都会以 DaemonSet 的方式运行),将日志文件转发到后端存储里保存起来。
过程解释:
- 应用 Pod 里的容器 app-container 产生日志输出到 stdout 和 stderr
- 对于一个容器来说,当应用把日志输出到 stdout 和 stderr 之后,容器项目在默认情况下就会把这些日志输出到宿主机上的一个 JSON 文件里。(这样通过 kubectl logs 命令就可以看到这些容器的日志了)
- logging agent 将日志文件转发到后端存储里
另外, logrotate,在日志文件超过 10MB 的时候会自动对日志文件进行 rotate 操作
优点与不足:
最大的优点在于一个节点只需要部署一个 agent,并且不会对应用和 Pod 有任何侵入性。
不足之处就在于,它要求应用输出的日志,都必须是直接输出到容器的 stdout 和 stderr 里。因为 stdout 的数据会默认输出到容器之外的宿主机,但如果日志直接输出到了容器内的某个文件里,或者输出到了远程存储里,就不适用了。
三、Sidecar + NodeAgent 方案
(app容器 - Sidecar - [stdout/stderr] - NodeAgent - 后端)
这种方案针对容器应用产生的日志不输出到 stdout/stderr 上的特殊情况。但实际上存在两份相同的日志文件,浪费磁盘空间。
通过一个 sidecar 容器把日志文件重新输出到 sidecar 的 stdout 和 stderr 上,然后再利用 logging agent 将日志文件转发到后端。
过程解释:
- 应用 Pod 里的容器 app-container 产生日志输出到容器内的某个文件,因为在容器内,外面是获取不到的。
- 为 Pod 添加一个 sidecar 容器,因为 sidecar 跟主容器之间是共享 Volume 的,所以可以将容器内日志文件内容重新以 stdout 和 stderr 的方式输出出来。
- 对于输出到 stdout 和 stderr 的内容,容器项目会默认地把这些日志输出到宿主机上的一个 JSON 文件里。
- logging agent 将日志文件转发到后端存储里
分析:
此方案的额外性能损耗虽然并不高,也就是 sidecar 多占用一点 CPU 和内存罢了。但需要注意的是,这时候宿主机上实际上会存在两份相同的日志文件:一份是应用自己写入的;另一份则是 sidecar 的 stdout 和 stderr 对应的 JSON 文件。这对磁盘是很大的浪费。
所以,除非万不得已或者应用容器完全不可能被修改,其他不推荐使用此方案
四、SidecarAgent 方案
(app容器 - SidecarAgent - 后端)
通过一个 sidecar 容器,直接把应用的日志文件发送到后端远程存储里面去。
这种方案也可以处理容器应用产生的日志不输出到 stdout/stderr 上的特殊情况,但这个 sidecar 容器会消耗较多的资源,甚至拖垮应用容器。
总结
综合对比以上几种方案,建议将应用日志输出到 stdout 和 stderr,然后通过在宿主机上部署 logging-agent 的方式来集中处理日志。这种方案不仅管理简单,kubectl logs 也可以用,而且可靠性高,并且宿主机本身,很可能就自带了 rsyslogd 等非常成熟的日志收集组件来供你使用。
图片均来自于张磊老师极客时间课程《深入剖析 Kubernetes》,也是本文的主要参考资料