我们使用的基础镜像是openjdk:8-jdk-alpine。容器启动时第一个进程就是java:
PID USER TIME COMMAND 1 root 0:50 java -Xms256m -Xmx512m ...... 94 root 0:00 sh 99 root 0:00 ps
使用alpine镜像会有个问题,如果java进程的pid=1,那么无法执行jdk的各种连接java进程的命令,会报如下错误:
Unable to get pid of LinuxThreads manager thread
我们的docker文件如下:
FROM openjdk:8-jdk-alpine MAINTAINER david "[email protected]" # copy arthas COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas ENV TZ=PRC RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ADD rpt-answerall-1.0-SNAPSHOT.jar answerall.jar ADD /script /script EXPOSE 9089 ENTRYPOINT ["java","-Xms750m","-Xmx900m","-server","-jar","/hello.jar"]
其他os镜像未验证,相关issue:https://github.com/docker-library/openjdk/issues/76
解决的方法是:启动一个init进程(pid=1)来接收docker stop and docker kill的信号,它会转发信号给其他进程,负责关闭僵尸进程。java进程由init进程启动。
具体有以下两种做法。
方法一:docker run –init
在docker 1.13 之后的版本,可以在docker run时加上 –init 参数来实现。
docker run -i --restart=always -v /etc/localtime:/etc/localtime --name hello-m 1024m -p 7005:7005 --net=host --log-opt max-size=500m --log-opt max-file=3 --init hello
方法二:krallin/tini
安装Tini,使用tini作为入口进程,配置启动java进程。
RUN apk add --no-cache tini # Tini is now available at /sbin/tini ENTRYPOINT ["/sbin/tini", "--", "java", "-Xms256m", "-Xmx512m", ......]
实际上,docker的–init参数也是通过集成Tini实现的。
参考链接:openjdk-alpine容器中的jvm如何dump