如何从外部访问docker中的JMX接口?

我正在试图远程监视docker中运行的JVM。 configuration如下所示:

  • 机器1:在Ubuntu机器上的docker上运行一个JVM(在我的情况下,运行kafka) 本机的IP为10.0.1.201; 在Docker中运行的应用程序在172.17.0.85。

  • 机器2:运行JMX监视

请注意,当我从机器2运行JMX监视时,它会失败,出现以下错误(注意:运行jconsole,jvisualvm,jmxtrans和node-jmx / npm:jmx时会发生同样的错误):

对于每个JMX监视工具,失败时的堆栈跟踪如下所示:

java.rmi.ConnectException: Connection refused to host: 172.17.0.85; nested exception is java.net.ConnectException: Operation timed out at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619) (followed by a large stack trace) 

现在有趣的部分是当我运行相同的工具(jconsole,jvisualvm,jmxtrans和node-jmx / npm:jmx)在运行docker(从上面的机器1)的同一台机器上JMX监视工作正常。

我认为这表明我的JMX端口是活动的并且正常工作,但是当我从机器2远程执行JMX监控时,它看起来像JMX工具不能识别内部docker IP(172.17.0.85)

以下是JMX监视工作的计算机1上的相关(我认为)networkingconfiguration元素(请注意docker ip,172.17.42.1):

 docker0 Link encap:Ethernet HWaddr ... inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr:... Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:6787941 errors:0 dropped:0 overruns:0 frame:0 TX packets:4875190 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1907319636 (1.9 GB) TX bytes:639691630 (639.6 MB) wlan0 Link encap:Ethernet HWaddr ... inet addr:10.0.1.201 Bcast:10.0.1.255 Mask:255.255.255.0 inet6 addr:... Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:4054252 errors:0 dropped:66 overruns:0 frame:0 TX packets:2447230 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:2421399498 (2.4 GB) TX bytes:1672522315 (1.6 GB) 

这是远程机器(机器2)上的相关networkingconfiguration元素,从中我得到JMX错误:

 lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=3<RXCSUM,TXCSUM> inet6 ::1 prefixlen 128 inet 127.0.0.1 netmask 0xff000000 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 nd6 options=1<PERFORMNUD> en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether .... inet6 ....%en1 prefixlen 64 scopeid 0x5 inet 10.0.1.203 netmask 0xffffff00 broadcast 10.0.1.255 nd6 options=1<PERFORMNUD> media: autoselect status: active 

为了完整性,下面的解决scheme工作。 JVM应该在build立特定参数的情况下运行,以实现远程docker JMX监控:

 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.rmi.port=<PORT> -Djava.rmi.server.hostname=<IP> where: <IP> is the IP address of the host that where you executed 'docker run' <PORT> is the port that must be published from docker where the JVM's JMX port is configured (docker run --publish 7203:7203, for example where PORT is 7203) 

一旦完成,您应该能够从本地或远程机器上执行JMX监视(jmxtrans,node-jmx,jconsole等)。

感谢@克里斯 – 希尔德使这是一个非常快速和简单的修复!

我发现试图通过RMI设置JMX是一个痛苦,尤其是因为-Djava.rmi.server.hostname=<IP> ,您必须在启动时指定它。 我们在Kubernetes运行我们的泊坞窗图像,在那里一切都是dynamic的。

我最终使用JMXMP而不是RMI,因为这只需要打开一个TCP端口,而不需要主机名。

我目前的项目使用Spring,可以通过添加这个来configuration:

 <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean"/> 

(在Spring之外,你需要设置你自己的JMXConncetorServer来完成这个工作)

除了这个依赖(因为JMXMP是一个可选的扩展,而不是JDK的一部分):

 <dependency> <groupId>org.glassfish.main.external</groupId> <artifactId>jmxremote_optional-repackaged</artifactId> <version>4.1.1</version> </dependency> 

在启动JVisualVM时,为了通过JMXMP进行连接,您需要为类path添加相同的jar:

 jvisualvm -cp "$JAVA_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar" 

然后连接下面的连接string:

 service:jmx:jmxmp://<url:port> 

(默认端口是9875)

我创build了一个GitHub项目 ,其中包含一个准备好从一个Docker容器执行JMX的实现。

它包含一个Dockerfile和一个docker-compose.yml以便于部署。