康维克实验室:使用BPF调查Kubernetes性能问题

2020-05-02 18:01:51

我们Kinvk实验室团队的工作之一是为遇到Kubernetes或Linux环境问题的客户提供专家技术咨询-从安全审计到网络故障再到令人费解的性能问题的故障排除。

几周前,视频广告技术公司SmartClip联系了我们,要求我们调查他们的Kubernetes部署的性能问题。在这篇博文中,我将向您介绍我们的流程,并解释如何使用BCC项目中的BPF工具快速识别和解决问题。最后,我将解释Inspektor Gadget如何使您能够轻松访问这些相同的BPF工具,用于您自己的Kubernetes安装。

Kubernetes集群运行nginx(其中包括fluentd和ApacheFlume)来处理日志。在部署了新版本的Kubernetes之后,devopteam注意到了fluentd中的一个性能回归问题:它无法足够快地处理日志,并且一直在缓冲日志,直到达到极限。

不幸的是,回归问题只有在生产几天后才能显现出来,尽管团队试图在开发环境中创建一个复制场景,但在生产之外的测试中无法复制。而且更有可能发生在晚上,因为有更多的流量要处理。

这次升级意味着几个变化:Linux内核的新版本、Kubernetes的新版本、不同的Docker版本等等。为了找出是哪个变化导致了问题,SmartClip团队逐一隔离了不同的变化,直到他们找到了导致回归问题的一个变化:从Kubernetes v1.14.4更新到v1.16.4。

起初令人惊讶的是:我看不出任何原因为什么会有任何KubernetesComponent(Kube-apiserver、控制器管理器、kubelet等)。应该会导致应用程序(Fluentd和Apache Flume)速度变慢。

我被授予ssh访问一个好节点(运行Kubernetesv1.14.4)和一个坏节点(运行v1.16.4)的权限,因此我可以找出它们之间的区别。我最初的想法是比较两个节点之间的以下内容:

但是,我看不出好节点和坏节点之间有什么区别。

BPF编译器集合(BCC)项目包含用于性能分析的工具。其中之一是CPUprofiler:它的工作方式是每隔一定的时间间隔采集内核或用户空间堆栈跟踪的样本,并计算每个跟踪可见的次数。

性能问题只在生产中出现,不建议在没有测试的情况下在生产节点上安装新工具。幸运的是,bcc及其CPU分析器可以作为容器执行,而无需在节点上安装。

Docker运行--rm-ti--特权\--net=host--pid=host\-v/usr/src:/usr/src\-v/lib/module:/lib/module\docker.io/kunk/bcc\/usr/share/bcc/tools/profile-d-f-K-p$FLUENTD_PID 10。

您可以在kventk的公共容器存储库中找到容器镜像,地址是docker.io/kinvk/bcc。如果出于某种原因您需要构建您自己的映像,您可以使用我们一个月前提供的GitHub操作中的新部分。

此命令按频率从最低频率到最频繁打印内核堆栈跟踪。这允许用户查看输出的最后一行,以获得最重要的行。输出的最后一行是这个内核堆栈:

这个带有函数ebt_ip_mt()的堆栈仅在坏节点上列出。我们发现好节点和坏节点之间有不同的行为。这是值得探讨的。

查看内核源代码,ebt_ip_mt()是Netfilter的一部分,负责在数据链路层过滤数据包。很多人都熟悉iptables命令来检查网络层和传输层的防火墙规则,但是Netfilter也有用于数据链路层防火墙规则的ebtables命令。

这给出了使用ebtables-L检查桥接防火墙规则的想法。在坏节点上,我注意到以下内容:

桥链:Kube-DEDUP,条目:4268,策略:接受-p ipv4-s e2:3f:9b:74:a8:7a-o veth+--ip-src 10.2.207.0/24-j drop-p ipv4-s e2:3f:9b:74:a8:7a-o veth+--ip-src 10.2.207.0/24-j drop-p ipv4-s e2:3f:9b:74:a8:7A-o veth+--ip-src。9b:74:a8:7a-o veth+--ip-src 10.2.207.0/24-j drop-p ipv4-s e2:3f:9b:74:a8:7a-o veth+--ip-src 10.2.207.0/24-j drop-p ipv4-s e2:3f:9b:74:a8:7a-o veth+--ip-src 10.2.207.0/24-j drop-p IPv4-s。

相同的规则在Kube-DEDUP链中重复数千次。这意味着将根据该规则对每个网络数据包进行数千次评估。链名称Kube-DEDUP表明它不是由Kubernetes手动添加的规则,而是由Kubernetes以编程方式添加的。这看起来像是窃听器。

在Kubernetes源代码中搜索,我发现Kubernetes集群中使用的kubenet网络插件确实添加了这样的规则,但是有一个特定的函数