[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 來獲取數據了。
// 结束男装