我正在尝试在远程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
我已经使用netcat验证了端口是否已打开,我可以与它建立TCP连接。
我在同一个Docker容器中打开了其他端口,客户端成功连接到这些端口。它们以相同的方式暴露并映射到主机端口(-p port:port),并以相同的方式在防火墙中打开。
我正在传递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打开匿名端口,并且您可以(至少部分?)通过指定两者来禁用此行为:
"-Dcom.sun.management.jmxremote.port=9010", \
"-Dcom.sun.management.jmxremote.rmi.port=9010", \
但是,在我的情况下,它并没有做到这一点。
我已阅读here您需要指定rmi服务器主机名:
-Djava.rmi.server.hostname='192.168.99.100'
但我的服务器IP是短暂的 - 它是在我创建实例时由Google Compute Engine分配的,因此我无法将其与其他Java args一起硬连接到Dockerfile中。
我是否需要获取静态IP地址才能使其正常工作?
答案 0 :(得分:3)
一种可能的解决方案是将ssh插入您的GCE盒和端口转发端口9010.这可以通过本地控制台完成:
gcloud compute ssh name-of-your-gce-engine -- -L 9010:localhost:9010
然后在jconsole
或jvisualvm
中,您将连接到localhost:9010
。在这里使用localhost意味着jconsole/jvisualvm
将连接到您的本地计算机,此连接通过ssh隧道传输到您的GCE引擎以及-L
参数中定义的主机和端口,{{1}但是从GCE引擎的角度来看。这意味着你将最终得到你的申请。
您仍然必须在启动程序之前设置rmi服务器名称,但必须使用
localhost:9010
以便RMI告诉-Djava.rmi.server.hostname='localhost'
使用localhost,然后这将解析为本地隧道端点。当然,你仍然需要这些:
jconsole/jvisualvm