关于使用Fluentd收集K8s集群容器日志
1. K8S日志
Kubernetes整个框架产生的日志主要划分为以下四种:
- Cluster(集群)级别的日志
- Node(节点)级别的日志
- Pod(共同构成一个应用的容器集合)级别的日志
- Docker(容器)级别的日志
通过应用和系统日志可以了解Kubernetes集群内所发生的事情,对于调试问题和监视集群活动来说日志非常有用。对于大部分的应用来说,都会具有某种日志机制。因此,大多数容器引擎同样被设计成支持某种日志机制。对于容器化应用程序来说,最简单和最易接受的日志记录方法是将日志内容写入到标准输出和标准错误流。
但是,容器引擎或运行时提供的本地功能通常不足以支撑完整的日志记录解决方案。例如,如果一个容器崩溃、一个Pod被驱逐、或者一个Node死亡,应用相关者可能仍然需要访问应用程序的日志。
因此,日志应该具有独立于Node、Pod或者容器的单独存储和生命周期,这个概念被称为群集级日志记录。群集级日志记录需要一个独立的后端来存储、分析和查询日志。Kubernetes本身并没有为日志数据提供原生的存储解决方案,但可以将许多现有的日志记录解决方案集成到Kubernetes集群中。
1.1 容器日志
kubernetes基础日志即将日志数据输出到标准输出流,使用kubectl logs 加容器名和命名空间来获取容器日志信息。
kubectl logs user-7d4d7c9675-rrs5m --namespace=sock-shop
1.2节点日志
容器化应用写入到stdout和stderr的所有内容都是由容器引擎处理和重定向的。例如,docker容器引擎会将这两个流重定向到日志记录驱动,在Kubernetes中该日志驱动被配置为以json格式写入文件。docker json日志记录驱动将每一行视为单独的消息。当使用docker日志记录驱动时,并不支持多行消息,因此需要在日志代理级别或更高级别上处理多行消息。
默认情况下,如果容器重新启动,kubectl将会保留一个已终止的容器及其日志。如果从Node中驱逐Pod,那么Pod中所有相应的容器也会连同它们的日志一起被驱逐。Node级别的日志中的一个重要考虑是实现日志旋转,这样日志不会消耗Node上的所有可用存储。Kubernetes目前不负责旋转日志,部署工具应该建立一个解决方案来解决这个问题。
在Kubernetes中有两种类型的系统组件:运行在容器中的组件和不在容器中运行的组件。例如:
- Kubernetes调度器和kube-proxy在容器中运行。
- kubelet和容器运行时,例如docker,不在容器中运行。
在带有systemd的机器上,kubelet和容器运行时写入journald。如果systemd不存在,它们会在/var/log目录中写入.log文件。在容器中的系统组件总是绕过默认的日志记录机制,写入到/var/log目录,它们使用golg日志库。可以找到日志记录中开发文档中那些组件记录严重性的约定。
类似于容器日志,在/var/log目录中的系统组件日志应该被旋转。这些日志被配置为每天由logrotate进行旋转,或者当大小超过100mb时进行旋转。
1.3 集群日志
Kubernetes本身没有为群集级别日志记录提供原生解决方案,但有几种常见的方法可以采用:
- 使用运行在每个Node上的Node级别的日志记录代理
- 在应用Pod中包含一个用于日志记录的sidecar
- 将日志直接从应用内推到后端
2.方案选定
因为日志记录必须在每个Node上运行,所以通常将它作为DaemonSet副本、或一个清单Pod或Node上的专用本机进程。然而,后两种方法后续将会被放弃。使用Node级别日志记录代理是Kubernetes集群最常见和最受欢迎的方法,因为它只为每个节点创建一个代理,并且不需要对节点上运行的应用程序进行任何更改。但是,Node级别日志记录仅适用于应用程序的标准输出和标准错误。
Kubernetes本身并没有指定日志记录代理,但是有两个可选的日志记录代理与Kubernetes版本打包发布:和谷歌云平台一起使用的Stackdriver和Elasticsearch,两者都使用自定义配置的fluentd作为Node上的代理。在本文的方案中,Logging-agent 采用Fluentd,而 Logging Backend 采用Elasticsearch,前端展示采用Kibana。即通过Fluentd作为Logging-agent收集日志,并推送给后端的Elasticsearch;前端展示采用Kibana从Elasticsearch中获取日志,并进行统一的展示。