在GCE上的Docker中将VisualVM或JConsole附加到Java

我正在尝试在远程Java-in-Docker进程中获取一些CPU采样。

我已经在这里看到了相关的问题,并尝试了一切,没有用,所以我在这里发布我的设置。

我有一个在Google Compute Engine(GCE)实例的Docker容器中运行的Java进程(openjdk-8)。 GCE实例和容器都运行Debian-9。 我想将VisualVM或JConsole附加到我的Java进程。

我能够在本地运行我的docker容器,并使用localhost:9010连接到visualvm和jconsole。

我使用以下命令启动VM启动脚本中的容器:

docker run -d -p 9010:9010 <my container> 

Dockerfile还有:

 EXPOSE 9010 

由Dockerfile CMD启动的Java进程具有以下相关的参数:

 "-Dcom.sun.management.jmxremote", \ "-Dcom.sun.management.jmxremote.port=9010", \ "-Dcom.sun.management.jmxremote.rmi.port=9010", \ "-Dcom.sun.management.jmxremote.local.only=false", \ "-Dcom.sun.management.jmxremote.authenticate=false", \ "-Dcom.sun.management.jmxremote.ssl=false", \ 

我在我的gcloud防火墙中打开了端口9010,使用:

 gcloud compute firewall-rules create jmx-port --allow=tcp:9010,udp:9010 

我已经validation与netcat的端口是开放的,我可以做一个TCP连接到它。

我从同一个Docker容器中打开了其他端口,客户端成功连接到这些端口。 他们被暴露并以相同的方式映射到主机端口(-p端口:端口),并以相同的方式在防火墙中打开。

我正在传递GCE实例的外部IP地址。 例如,如果我这样做:

 gcloud compute instances list 

它告诉我:

 NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS my-server-b23j us-central1-d n1-standard-1 10.240.0.2 108.357.213.99 RUNNING 

然后我会使用这个论点:

 108.357.213.99:9010 

作为远程jmx连接主机:端口对。

VisualVM和JConsole都告诉我他们不能连接到远程JMX服务。 在这两种情况下,我拒绝安全连接,然后他们说:

 Cannot connect to 108.357.213.99:9010 using service:jmx:rmi:////jndi/rmi://108.357.213.99:9010/jmxrmi 

无奈之下,我添加了一个防火墙规则,可以在所有端口0-65535上启用TCP / UDP连接,但是没有什么区别 – 它们仍然无法连接。

我读过JMX-RMI打开匿名端口,并且可以(至less部分)通过指定两个来禁用这种行为:

 "-Dcom.sun.management.jmxremote.port=9010", \ "-Dcom.sun.management.jmxremote.rmi.port=9010", \ 

但是,在我的情况下,这并不能解决问题。

我读过这里 ,你需要指定rmi服务器主机名:

 -Djava.rmi.server.hostname='192.168.99.100' 

但是我的服务器IP是短暂的 – 当我创build实例时,它由Google Compute Engine分配,所以我无法将其与Java参数的其余部分硬连接到Dockerfile中。

我将不得不得到一个静态的IP地址,使之工作?

一个可能的解决scheme是ssh到您的GCE箱和端口转发端口9010.这可以从本地控制台完成:

 gcloud compute ssh name-of-your-gce-engine -- -L 9010:localhost:9010 

然后在jconsolejvisualvm连接到localhost:9010 。 在这里使用localhost意味着jconsole/jvisualvm将连接到本地计算机,这个连接通过ssh隧道到你的GCE引擎,并在-L参数中定义的主机和端口是localhost:9010 ,但是从GCE-引擎的看法。 这意味着你将最终在你的申请。

在启动程序之前,您仍然需要设置rmi服务器名称,但是您必须使用

 -Djava.rmi.server.hostname='localhost' 

所以RMI会告诉jconsole/jvisualvm使用本地主机,然后这将parsing到您的本地隧道端点。 当然,你仍然需要这些:

 "-Dcom.sun.management.jmxremote", \ "-Dcom.sun.management.jmxremote.port=9010", \ "-Dcom.sun.management.jmxremote.rmi.port=9010", \ "-Dcom.sun.management.jmxremote.local.only=false", \ "-Dcom.sun.management.jmxremote.authenticate=false", \ "-Dcom.sun.management.jmxremote.ssl=false", \