当 K8s healthcheck 重启 pod 时创建 JVM heapdump - 没有 OOM 发生

Create JVM heapdump when K8s healthcheck restarts the pod - no OOM occur

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

关于如何导致堆转储发生,我唯一的想法是使用 preStop 挂钩。 问题是,是否在健康检查失败重启pod时触发了preStop hook?

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

The question is, whether the preStop hook is fired when the pod is restarted because of health check failure?

是的。根据 definitionperStop 钩子 运行,在容器因 API 请求或管理事件(例如活性探测失败、抢占、资源争用和其他


Should I use preStop hook to capture Java Heap Dump before pod termination?

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


Any more elegant solution to this?

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

Why the above solution will work?

当 kubernetes 杀死你的容器因为它没有响应健康检查时,kubernetes 只会重启容器,但它不会重新安排 pod,所以它不会将它移动到另一个节点。因此,在将 pod 移动到另一个节点之前,不会删除空目录卷。因此,当容器重新启动时,新容器将挂载相同的空目录,其中将包含来自先前 运行 的堆转储。因此,您可以在活动结束后随时 kubectl cp 这些文件。复制堆转储文件可能还有其他挑战,但它们是可以解决的。查看 this 了解更多信息。