当 K8s healthcheck 重新启动 pod 时创建 JVM heapdump - 不会发生 OOM

Kik*_*sha 6 java jvm heap-dump kubernetes kubernetes-health-check

我遇到过这样一种情况,突然发生很长的 GC 暂停,我需要找出突然内存分配的根源是什么。长时间的 GC 暂停(大约 30 秒)会导致 pod 连续多次 K8s 健康检查失败,并且 pod 会重新启动,而实际上并没有发生 OOM。我想在 K8s 实际重新启动 pod 之前创建堆转储。我意识到应该对某些外部持久安装进行转储。

我对如何导致堆转储发生的唯一想法是使用 preStop 挂钩。问题是,pod因健康检查失败而重启时,preStop钩子是否会被触发?

也许有一个更优雅的解决方案?

mch*_*wre 5

问题是,pod因健康检查失败而重启时,preStop钩子是否会被触发?

是的。根据定义PreStop钩子会在容器由于 API 请求或管理事件(例如活动探测失败、抢占、资源争用等)而终止之前立即运行。


我应该在 pod 终止之前使用 preStop 钩子捕获 Java 堆转储吗?

是的。但您需要小心,如果容器已处于终止或完成状态,则对 preStop 挂钩的调用将失败。当Pod 终止时,它会在发送 KILL 信号之前等待默认的 30 秒宽限期(如果 PerStop 挂钩未完成,则额外等待 2 秒)。如果 preStop 挂钩需要比默认宽限期允许的时间更长的时间才能完成,则必须进行修改terminationGracePeriodSeconds以适应这一点。


有更优雅的解决方案吗?

据我所知,没有。我想通过向 pod 添加一个空的目录卷,并配置 JVM 以将堆转储到该目录command: ["java", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/dumps/oom.bin", "-jar", "yourapp.jar"]应该可以工作。

为什么上述解决方案会起作用?

当 kubernetes 由于没有响应健康检查而杀死您的容器时,kubernetes 只会重新启动容器,但不会重新调度 pod,因此不会将其移动到另一个节点。因此,在 pod 移动到另一个节点之前,空的 dir 卷不会被删除。因此,当容器重新启动时,新容器将安装相同的空目录,其中将包含上次运行的堆转储。因此您可以kubectl cp在活动结束后随时查看这些文件。复制堆转储文件可能还存在其他挑战,但它们是可以解决的。检查以获取更多信息。