【问题标题】:jvmkill is unable to kill the JVM in an image created by Paketo Java Buildpackjvmkill 无法杀死由 Paketo Java Buildpack 创建的映像中的 JVM
【发布时间】:2021-06-02 20:24:31
【问题描述】:

我在使用官方 spring boot gradle 插件创建的容器中有一个 spring boot 应用程序 v2.4.3,该插件使用 buildpakcs 来执行此操作。

其中一层是jvmkill:

[creator]     Adding layer 'paketo-buildpacks/bellsoft-liberica:jvmkill'

这很好,它正在为 jvmkill 正确添加 jvm arg

Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx387804K -XX:MaxMetaspaceSize=148771K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 1G, Thread Count: 250, Loaded Class Count: 23852, Headroom: 0%)                                                                                                                                           
Adding 129 container CA certificates to JVM truststore                                                                                                                               
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=2 -XX:MaxDirectMemorySize=10M -Xmx387804K -XX:MaxMetaspaceSize=148771K -XX:ReservedCodeCacheSize=240M -Xss1M                                                                                                                         
   .   ____          _            __ _ _                                                                                                                                              
  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \                                                                                                                                             
 ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \                                                                                                                                            
  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )                                                                                                                                           
   '  |____| .__|_| |_|_| |_\__, | / / / /                                                                                                                                            
  =========|_|==============|___/=/_/_/_/                                                                                                                                             
  :: Spring Boot ::                (v2.4.3)

应用程序在 Kubernetes (AWS EKS) 中运行,但是当我遇到 OOM 时

java.lang.OutOfMemoryError: Java heap space

jvmkill 启动,打印堆转储并发送终止信号

Heap                                                                                                                                                                                 
  def new generation   total 116736K, used 90606K [0x00000000e8400000, 0x00000000f02a0000, 0x00000000f02a0000)                                                                        
   eden space 103808K,  87% used [0x00000000e8400000, 0x00000000edc7bae0, 0x00000000ee960000)                                                                                         
   from space 12928K,   0% used [0x00000000ef600000, 0x00000000ef600000, 0x00000000f02a0000)                                                                                          
   to   space 12928K,   0% used [0x00000000ee960000, 0x00000000ee960000, 0x00000000ef600000)                                                                                          
  tenured generation   total 259456K, used 249951K [0x00000000f02a0000, 0x0000000100000000, 0x0000000100000000)                                                                       
    the space 259456K,  96% used [0x00000000f02a0000, 0x00000000ff6b7f18, 0x00000000ff6b8000, 0x0000000100000000)                                                                     
  Metaspace       used 74292K, capacity 76000K, committed 76824K, reserved 208160K                                                                                                    
   class space    used 8689K, capacity 9350K, committed 9600K, reserved 140576K                                                                                                       
 jvmkill killing current process                          ```

但 jvm 永远不会被杀死。 检查容器时,我注意到应用程序以 PID 1 运行,无法从容器内部终止(或发出信号)。

cnb@myhost-6968d47f4b-2cnlj:/$ ps -fea
UID        PID  PPID  C STIME TTY          TIME CMD
cnb          1     0  6 19:49 ?        00:00:54 java org.springframework.boot.loader.JarLauncher
cnb        121     0  0 20:02 pts/0    00:00:00 bash
cnb        131   121  0 20:02 pts/0    00:00:00 ps -fea

由于所有这些都是由 java buildpack 本身构建的,我希望它知道 PID 1 不能被杀死并以不同的方式启动应用程序以正常工作。

我是否缺少或需要配置 buildpack jvmkill 以使其开箱即用?

解决方法:

  1. 如果我直接使用 docker 运行映像,我可以使用 docker run --init 来向 jvm 进程发出信号(我的应用程序使用 PID 7 运行)。不适用于 Kubernetes。
cnb          1  4.0  0.0   1120     4 ?        Ss   20:10   0:00 /sbin/docker-init -- java etc...
cnb          7  4.0  0.0  18372  1580 ?        S    20:10   0:00 java etc...
  1. 我可以在我的 k8s 规范中 shareProcessNamespace: true 让它在 PID 不是 1 的情况下运行,但由于安全合规性要求,这很难证明是合理的。

  2. 我可以只添加 jvm 标志 -XX:+ExitOnOutOfMemoryError,但没有 jvmkill 显示的良好堆转储以及 jvmkill 线程创建失败覆盖率。

【问题讨论】:

    标签: kubernetes buildpack paketo


    【解决方案1】:

    鉴于https://github.com/airlift/jvmkill#using-inside-docker-containers 中提到的解决方法,您需要其他的 pid 1。Kubernetes 没有 --init 的等效项,但如果您在映像中包含 tini,您可以通过容器手动使用它命令。您也可以类似地使用sh

    还请记住,这只会保护您免于达到 Java 级别的堆大小限制。如果您达到了实际的容器内存限制,那么您的进程将立即终止,没有机会捕获它并执行任何操作。

    【讨论】:

    • 您可以使用github.com/paketo-buildpacks/tinitini 包含在生成的图像中。您也可以使用此处的说明:buildpacks.io/docs/app-developer-guide/run-an-app/…。只需复制并粘贴由 builpacks 生成的启动命令(您可以使用 pack inspect <image> 查看它)并使用该命令。通过使用我链接到的说明,应该在 shell 中启动你的进程,这将使它不是 PID1。您也可以使用这些说明与tini 一起运行。
    猜你喜欢
    • 1970-01-01
    • 2010-12-10
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    • 2022-12-05
    • 2021-10-19
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多