java容器无法使用jmap命令

jmap是java一个常用的辅助工具,它可以输出所有内存中对象,来检查内存泄漏等问题,然而在容器里使用jmap命令时,会遇到以下错误:

/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      1h30 java -jar /app-salary.jar --sahara.config.file=/sahara.yml
   67 root      0:00 sh
   84 root      0:00 ps -ef
/ # jmap -dump:format=b,file=heap.bin 1
1: Unable to get pid of LinuxThreads manager thread

查看当前使用的Dockerfile,可以看到使用的镜像是openjdk:8-jdk-alpine,信息如下:

FROM openjdk:8-jdk-alpine
LABEL maintainer="Qiu Shuhui"

RUN set -xe \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk update \
    && apk add --no-cache ca-certificates ttf-dejavu fontconfig tzdata \
    && cp -rf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone
    
COPY corehr.jar sahara.yml /
VOLUME ["/apps/logs", "/apps/file"]
ENTRYPOINT  ["java", "-jar", "/corehr.jar", "--sahara.config.file=/sahara.yml"]

参考网络的文章,发现这是一个通用的bug,其中的解决方案就是使用tini来接管java进程,在基础镜像中添加tini安装包:

FROM openjdk:8-jdk-alpine
LABEL maintainer="Qiu Shuhui<qiush01@haid.com.cn>"

RUN set -xe \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk update \
    && apk add --no-cache ca-certificates ttf-dejavu fontconfig tzdata tini \
    && cp -rf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

Docker启动换成以下:

ENTRYPOINT [ "/sbin/tini", "--", "java", "-XX:+UseG1GC", "-jar", "/app-salary.jar", "--sahara.config.file=/sahara.yml" ]

使用tini命令接管java进程时,可以发现多衍生了一个进程,当前的JAVA PID为6。

/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 /sbin/tini -- java -XX:+UseG1GC -jar /workflow.jar --sahara.config.file=/sahara.yml
    6 root      0:57 java -XX:+UseG1GC -jar /workflow.jar --sahara.config.file=/sahara.yml
   65 root      0:00 sh
   70 root      0:00 ps -ef

再使用jmap命令,一切正常。

文献参考: