Kubernetes日志传输过程中面临的4个挑战

在过去的三个月里,我一直在研究PKS的可观察特性。最后,我把关注点放在了Kubernetes的日志系统上面。

收集日志,并将其发送到日志服务器。这看起来是简单而普通的工作,不是吗?或许有时候是这样的吧。但是,与虚拟机或裸机环境相比,我注意到了使用容器时在日志记录方面的一些新的挑战。

以下是摘要。了解一下!看看您的Kubernetes项目上是否也有同样的问题。

这篇文章的动机更多的是想要阐释问题和技术难点。而不是关于如何解决它们。如果这里面的内容有什么不合适的地方,我会根据需要做出一些改变。

通常,日志的传输工作流有主动和被动之分。

主动方式:进程主动将日志消息发送到远程的syslog服务器上。通常,数据编码的格式是会是rfc5424

Kubernetes日志传输过程中面临的4个挑战

被动方式:对于每个进程,指定其默认的日志路径或文件模式。日志代理系统将会定期扫描它们,并将捕获的日志消息发送到日志服务器上面。

Kubernetes日志传输过程中面临的4个挑战

你可能认为问题已经解决了!还没有,我的朋友们。

在容器中运行服务与在虚拟机或裸机中有所不同。因为我们将要面临的新趋势是:

  1. 这个过程将更加短暂。
  2. 流程部署将更加分散。

而这对容器的日志记录意味着什么?

挑战I:无法收集所有的关键日志

当出现问题时,Pod(容器的集合)可能会被删除或快速被重新创建。因此,与Pod/容器相关联的日志文件将被快速删除或重建。

然而,像Fluentdlog stash这样的日志代理通常是通过定期扫描文件夹或日志模式来检测新的日志文件的。默认的扫描间隔可能是60秒(见下图)。很可能会因为扫描间隔太长而无法捕获短寿命的容器日志。那我们把时间间隔设置得更短,比如1秒,这样又如何呢?显然这会带来更高的性能开销。

Kubernetes日志传输过程中面临的4个挑战

这在以前的虚拟机世界中不会是个问题。当进程以某种方式重新启动时,日志文件可能会被轮换,而不是删除。此时,用户接收日志的速度可能只是会变慢。但不会缺少问题流程的关键日志。

我们如何解决这个问题呢?目前还没有所谓的最佳实践,我们也在探索。也许我们可以启动一个订阅pod事件的Kubernetes控制器。每当触发pod创建事件时,立即通知日志代理。 honeycomb-kubernetes-agent就是一个有趣的实现了这个想法的GitHub项目。如果您有更好的解决方案,请留下评论。

然而,并不是所有日志都会被重定向到stdout/stderr之中。如果pod内的进程将日志写入本地文件,而不是stdout/stderr当中,那么日志代理系统无法获取这些日志。

为什么? 日志代理系统只会监视与pod相关的日志文件,如下所示。该日志文件将只捕获容器的stdout/stderr。

# ls -1  /var/lib/docker/containers/*/*-json.log 


ls -1  /var/lib/docker/containers/*/*-json.log 


/var/lib/docker/containers/0470.../0470...-json.log 


/var/lib/docker/containers/0645.../0645...-json.log 


/var/lib/docker/containers/12d2.../12d2...-json.log 


... 


... 

是的,这种日志记录行为的确是Kubernetes世界的一种反模式。然而,云原生运动的发展仍然需要时间,不是每个人都能够紧跟潮流。对于数据库服务来说尤其如此。

与虚拟机世界相比,Pod可能会经常在不同的工作节点中移动。您肯定不希望每当K8s集群有一个pod更改时,就需要重新加载或重新启动日志代理。这是新的挑战,对吧?

挑战II:日志命名空间下的多租户

Kubernetes的工作负载通常会在共享工作虚拟机中运行。来自不同项目的工作负载会以不同命名空间来进行划分。

不同的项目可能对日志记录有不同的偏好。日志转到哪里,由什么工具管理,等等,都需要提供一种简单的配置方式,并且没有额外的安全隐患。

事实证明,在这方面,Kubernetes CRD (CustomResourceDefinition)是一个非常好的工具。

  1. 您需要学习的只是标准的kubectl命令。(参见kubectl备忘录)。
  2. RBAC可以在这里用于资源的自定义。安全性也可以得到保证。

在PKS中,我们将这个特性称为资源的sink。注意:这个想法已经提交给了Kubernetes社区。希望它能很快并入Kubernetes上游。

Kubernetes日志传输过程中面临的4个挑战

挑战III:支持为不同命名空间使用不同的日志SLA

为了方便,人们通常只需要部署一个日志代理来作为Kubernetes daemonset。这意味着每个Kubernetes工作节点只有一个pod。如果因为某种原因需要重新加载或重新安排此pod,它将影响在此工作节点中的所有Pod。

从K8s v1.12开始,你可以在每个节点上运行100个pod。相应的,你需要确保你的日志代理足够快,以便从所有pod中收集日志。

像任何共享的环境一样,您可能会遇到一个嘈杂的邻居问题。一个Pod的不当行为可能会损害同一工作节点中的所有其他pod。想要禁用一个有问题的命名空间的日志记录?虽然你可以很容易的将整个日志系统关闭,却无法继续收集需要收集的日志了。

另外,慢速的磁盘可能会给日志传输带来显著的延迟。如果无法及时处理日志的背压问题可能会导致日志代理的DDoS。

Kubernetes日志传输过程中面临的4个挑战

挑战四:处理来自不同层级的日志记录

如下图所示,我们有pod日志、K8s日志和平台日志。即使是对于“pod日志”,我们也有来自标准工作负载或K8s加载项的日志。

正如你可能猜测的,不同类型的日志具有不同的特性,以及不同的优先级。不仅是层与层之间,有时同一层的内部也有不同的SLA。

为了提供K8s解决方案,我们可以如何解决这个问题呢?你需要在协助项目经理和开发人员迅速找出问题根源的同时,尽量减少安全隐患。

相关推荐