博客/工程

[KubeCon重述]如何在Kubernetes中调试实时应用程序

2019年11月26日8分钟

Grafana Labs的后端工程师Joe Elliott在圣地亚哥的bob电竞频道KubeCon + CloudNativeCon会场前展示了他在Kubernetes现场调试应用程序时使用的一些技巧。

乔·埃利奥特在KubeCon的演讲
乔·埃利奥特在KubeCon的演讲

目标是增加您在生产环境中应用程序的知识。Elliott的技术与框架无关,并且是特定于linux的,在您有已知类型的问题和应用程序的情况下最有用。它们的影响也非常小,可以在负载下大规模运行。首先,他通过Kubernetes API以Kubernetes原生方式完成所有事情。

Linux调试系统可能令人困惑,所以他推荐博客文章和一个是有用的概述。

构建工具集

最初Elliott使用了一种简单的方法来调试应用程序。他会通过SSH进入,执行任务,并使用一些工具。这很有帮助,但也产生了一个问题:当他完成时,会安装很多工具,或者安装了不同包的节点,或者留下很少的笔记或文件。

他意识到一辆挎斗是完美的解决方案,而且它有几个好处。

1.简单的清理。你把所有的工具放在一个容器里,当你删除pod时,它们就都消失了。因此,也不会有影响节点或节点上其他进程的风险。

2.它不需要主机访问。这种技术使开发人员有机会更好地查看他们的应用程序,而不必向他们提供对节点的SSH访问。

3.这是“简单”。好了,不容易,这很简单,但是构建一个包含调试工具的工具集容器并不难,因为它遵循许多与应用程序容器相同的规则。“你可以对它进行迭代,所以你可以构建一个只具有性能和只执行一些CPU分析的容器,”Elliott说。“有了这个功能,就有了一种新的方式来查看你的应用程序。此外,您可以动态地编写脚本,随着时间的推移,继续构建这个工具集容器,并将其部署到任何地方。”

4.它是不可变的。他说:“它可以放在开发部门,可以放在QA部门,可以放在产品部,也可以放在我们的桌面,而且它具有可移植性。”

5.它支持发展多样性。使用不同技术的团队可以构建自己的容器来调试自己的应用程序。

的挑战

Elliott说他在安装应用程序时遇到了最大的困难,比如perf,这些应用程序需要为特定的内核安装。

“如果你现在就apt-get perf,它将是一个为你正在运行的内核构建的perf版本,”他说。“当您试图将其部署到生产集群中具有不同版本的节点时,可能会出现问题。”

其他问题:Sidecar图像可能非常大,而且它们也不能动态编辑。

修复

1.加入所有的工具。如果你的所有节点都将是完全相同的内核版本,你就可以这样做,他说:“让它完全符合你正在运行的内核的需要。”

2.从主机挂载。这是一个轻微的欺骗。通过从主机挂载资源,模糊了使用或不使用主机访问之间的界限。

3.使用工具部署。内核版本现在已经知道了。“这种方法主要是我使用。net Core容器的方式,”他说。这使他能够部署到许多环境中,例如AWS KOPS和DBN上的KOPS集群,以及GK Ubuntu。(他补充说,很难保持这种效果,所以烘烤仍然是更好的选择。)

从sidecar现场调试应用程序需要以下pod规范的元素:

  • shareProcessNamespace

  • 共享挂载的卷

  • 挂载主机路径

  • securityContext.privileged

在上面列出的四个中,shareProcessNamespace是最重要的。“如果您将此设置为true,”Elliott说,“那么所有进程和所有容器都可以看到彼此。”当您的调试工具要开始查看实际应用程序时,这是一个要求。

演示

Elliott介绍了三种不同的Linux本机调试工具和技术:用于CPU分析的perf;LTTng用于用户空间静态跟踪点;和BCC用于uprobes/动态跟踪。

CPU性能分析

这是一种抽样方法。它可以帮助您了解应用程序花费时间在哪些函数上,还可以帮助您了解应用程序行为异常的原因。“Perf每秒将对我们的其他进程的堆栈进行1000次采样,它只是要写出发生了什么,”Elliott说。

它使用一种叫做火焰图的工具来记录这些数据,它创建了下面的图像。

CPU分析的火焰图
CPU分析的火焰图

下面是这项技术的详细介绍:

CPU性能分析
CPU性能分析

Elliott解释说,因为他必须传递一个PID,所以他运行了ps x。“如果你没有设置shareProcessNamespace: true,然后运行这个ps x命令,你将无法看到你的主进程,”他警告说,“你将无法执行这些技术。”

他说,他在这个例子中安装了temp,“因为perf想要在temp中看到一个perf映射”,它将重新符号化堆栈,这使它更容易理解正在发生什么。

静态Tracepoints

“静态跟踪点是专为非常非常大的容量设计的框架——您可以在关键路径中写入这些内容,并且可以记录这些信息,并且对应用程序的影响很小,甚至没有影响,”Elliott解释道。

这需要预检测,并且需要内置于应用程序中。他主要使用LTTng(用于收集跟踪点的框架)和Babeltrace.应用程序和用户空间创建事件并将其传递给LTTng守护进程和用户空间。

静态跟踪点(LTTng)
静态跟踪点(LTTng)

这种技术不需要内核访问,也不需要securityContext。特权被设置为true,因为它只是在用户空间中与主进程通信。与跟踪指南针,您可以调出所有这些事件,并在桌面上查看它们。

我们挂载var/run/lttng的原因是因为lttng希望通过Unix套接字进行通信,默认情况下它会将其放在var/run/lttng中。艾略特说。“所以要让这一切正常工作,两个应用程序本质上需要访问同一个文件夹。”他指出,他使用。net Core是因为它有一个针对LTTng的预检测。

通过这种技术,可以分析垃圾收集、线程创建和死锁等事件。Babeltrace支持Python扩展,因此可以编写Python脚本,也可以使用Trace Compass实用程序来查看直方图。

动态跟踪

这是Elliott展示的最新技术。它不需要仪器,但它是最难完成的。

他说:“动态跟踪是一个非常酷的技巧,它可以让内核回调你,并在某个函数被应用程序调用时随时告诉你。”

动态跟踪
动态跟踪

在这里,他运行了一个名为run-native的脚本,“然后我将共享所有这些东西,这些都与Uprobes的特定需求有关,这是BCC正在使用的,”他说。(为了确保它能正常工作,您需要一个磁盘上的机器代码二进制。)他还运行了一个脚本来进行字节码编译,将其转换为机器代码,并将其放在磁盘上。“只有这种特殊的技巧才能让我们对这个应用程序进行密件抄送,”他补充说。

作为欺骗,他挂载了usersource和lib/modules,这是为了获得Linux头文件。他说:“在Kubernetes上运行的容器中,很难将编译内核的Linux头文件精确地拉到容器中。”他还从主机挂载了/sys,因为它使用Ftrace,而Ftrace需要/sys。

在该技术的一次演示中,Elliott转储了字符串参数值,他说这展示了BPF的强大功能:“BPF是一种编写C的子集的技术,该子集被编译为在内核中运行的字节代码。所以这使得它非常快速和高效。”他将它附加到一个Uprobe,获取。net Core内部字符串表示,然后提取该字符串并在控制台上显示它。

“Perf也支持动态跟踪,”他补充说,“但它只支持以空结尾的字符串,所以实际上用Perf无法做到这一点。”

他说,使用自己编写的小程序,就可以做一些事情,比如计算直方图,或者获取一些数据,并以一种在应用程序之外更有意义的方式重新表示它。

最终的想法

他说,可以将这些工具注入到已经运行的pod中,但你必须作弊,从节点上的Docker进行操作:“除此之外,Kubernetes pod是不可变的。”

目前是这样。预计处于alpha测试阶段的Kubernetes 1.16将运行临时容器。

“如果你设置了功能门标志,那么你就可以访问它,”他说,“然后当它升级到测试版时,它就会是通用的。”