[Docker][Java] 在 Java 进程的容器中无法获取 jmap/jstack

在前一篇文章中,当解决了Java进程在Docker容器上无法使用jstat的问题后,之前可以使用的jmap/jstack也无法使用了。。

[Docker][Java] 在 Java 进程的容器中无法使用 jstat。

出现以下错误,jmap/jstack 的结果会输出到要附加的 Java 进程的标准输出。

Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file /proc/1/root/tmp/.java_pid1: target process 1 doesn't respond within 10500ms or HotSpot VM not loaded
        at jdk.attach/sun.tools.attach.VirtualMachineImpl.<init>(VirtualMachineImpl.java:100)
        at jdk.attach/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:58)
        at jdk.attach/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:207)
        at jdk.jcmd/sun.tools.jmap.JMap.executeCommandForPid(JMap.java:128)
        at jdk.jcmd/sun.tools.jmap.JMap.histo(JMap.java:174)
        at jdk.jcmd/sun.tools.jmap.JMap.main(JMap.java:112)

尽管目标Java进程以及jmap/jstack都已更改用户ID进行执行,但错误消息中提到的套接字文件名仍为/proc/1/root/tmp/.java_pid1,并且是root用户,因此即使以root用户身份尝试运行jcmd也是不可行的。

$ docker exec -t --user 1000 {container-id} jstack 1  #=> NG
$ docker exec -t             {container-id} jstack 1  #=> NG

进入容器的Shell后,即使尝试直接查看上述文件,也无法访问该文件。
连root也无法访问,真是…

原本问题是,尽管已更改用户ID并运行,但套接字文件名仍为root,这是不正常的。

最终结果似乎是由于Java进程在入口点内更改了用户ID并运行了java进程。
由于容器(PID=1)本身以root身份启动,因此套接字文件名应该是root。

chroot --userspec=1000:0 / java -ea ...

因此,需要通过chroot对jmap/jstack进行相同的操作才能执行。

$ docker exec -t {container-id} bash -c "chroot --userspec=1000:0 / jstack 1"

我們現在可以使用jmap / jstack 來獲取數據了。

// 结束男装

广告
将在 10 秒后关闭
bannerAds