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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31257968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:51:00  来源:igfitidea点击:

How to access JMX interface in docker from outside?

javadockerjmxjmxtrans

提问by Eric Broda

I am trying to remotely monitor a JVM running in docker. The configuration looks like this:

我正在尝试远程监控在 docker 中运行的 JVM。配置如下所示:

  • machine 1: runs a JVM (in my case, running kafka) in docker on an ubuntu machine; the IP of this machine is 10.0.1.201; the application running in docker is at 172.17.0.85.

  • machine 2: runs JMX monitoring

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

  • 机器 2:运行 JMX 监控

Note that when I run JMX monitoring from machine 2, it fails with a version of the following error (note: the same error occurs when I run jconsole, jvisualvm, jmxtrans, and node-jmx/npm:jmx):

请注意,当我从机器 2 运行 JMX 监控时,它失败并显示以下错误版本(注意:运行 jconsole、jvisualvm、jmxtrans 和 node-jmx/npm:jmx 时发生相同的错误):

The stack trace upon failing looks something like the following for each of the JMX monitoring tools:

对于每个 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)

Now the interesting part is when I run the same tools (jconsole, jvisualvm, jmxtrans, and node-jmx/npm:jmx) on the same machine that is running docker (machine 1 from above) the JMX monitoring works properly.

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

I think this suggests that my JMX port is active and working properly, but that when I execute JMX monitoring remotely (from machine 2) it looks like the JMX tool does not recognize the internal docker IP (172.17.0.85)

我认为这表明我的 JMX 端口处于活动状态并且工作正常,但是当我远程执行 JMX 监控(从机器 2)时,JMX 工具似乎无法识别内部 docker IP (172.17.0.85)

Below are the relevant (I think) network configuration elements on machine 1 where JMX monitoring works (note the docker ip, 172.17.42.1):

以下是 JMX 监控工作的机器 1 上的相关(我认为)网络配置元素(注意 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)

And this is the relevant network configuration elements on the remote machine (machine 2) from which I am getting the JMX errors:

这是我收到 JMX 错误的远程机器(机器 2)上的相关网络配置元素:

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

采纳答案by Eric Broda

For completeness, the following solution worked. The JVM should be run with specific parameters established to enable remote docker JMX monitoring were as followed:

为了完整起见,以下解决方案有效。JVM 应使用特定参数运行以启用远程 docker JMX 监控,如下所示:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=<PORT>
-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). Both `port` and `rmi.port` can be the same. 

Once this is done you should be able to execute JMX monitoring (jmxtrans, node-jmx, jconsole, etc) from either a local or remote machine.

完成此操作后,您应该能够从本地或远程机器执行 JMX 监控(jmxtrans、node-jmx、jconsole 等)。

Thanks to @Chris-Healdfor making this a really quick and simple fix!

感谢@Chris-Heald使这个修复变得非常快速和简单!

回答by Morten Berg

I found it that trying to set up JMX over RMI is a pain, especially because of the -Djava.rmi.server.hostname=<IP>which you have to specify on startup. We're running our docker images in Kubernetes where everything is dynamic.

我发现尝试通过 RMI 设置 JMX 很痛苦,尤其是因为-Djava.rmi.server.hostname=<IP>您必须在启动时指定它。我们在一切都是动态的 Kubernetes 中运行我们的 docker 镜像。

I ended up using JMXMP instead of RMI, as this only need one TCP port open, and no hostname.

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

My current project uses Spring, which can be configured by adding this:

我当前的项目使用Spring,可以通过添加以下内容进行配置:

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

(Outside Spring you need to set up your own JMXConncetorServer in order to make this work)

(在 Spring 之外,您需要设置自己的 JMXConncetorServer 才能使其工作)

Along with this dependency (since JMXMP is an optional extension and not a part of the JDK):

连同此依赖项(因为 JMXMP 是一个可选扩展,而不是 JDK 的一部分):

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

And you need to add the same jar your your classpath when starting JVisualVM in order to connect over JMXMP:

并且您需要在启动 JVisualVM 时在您的类路径中添加相同的 jar 以便通过 JMXMP 进行连接:

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

Then connect with the following connection string:

然后使用以下连接字符串连接:

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

(Default port is 9875)

(默认端口为 9875)

回答by Serge

For dev environment you can set java.rmi.server.hostnameto the catch-all IP address0.0.0.0

对于开发环境,您可以设置java.rmi.server.hostname全能 IP 地址0.0.0.0

Example:

例子:

 -Djava.rmi.server.hostname=0.0.0.0 \
                -Dcom.sun.management.jmxremote \
                -Dcom.sun.management.jmxremote.port=${JMX_PORT} \
                -Dcom.sun.management.jmxremote.rmi.port=${JMX_PORT} \
                -Dcom.sun.management.jmxremote.local.only=false \
                -Dcom.sun.management.jmxremote.authenticate=false \
                -Dcom.sun.management.jmxremote.ssl=false
 -Djava.rmi.server.hostname=0.0.0.0 \
                -Dcom.sun.management.jmxremote \
                -Dcom.sun.management.jmxremote.port=${JMX_PORT} \
                -Dcom.sun.management.jmxremote.rmi.port=${JMX_PORT} \
                -Dcom.sun.management.jmxremote.local.only=false \
                -Dcom.sun.management.jmxremote.authenticate=false \
                -Dcom.sun.management.jmxremote.ssl=false

回答by snovelli

After digging around for quite a lot, I found this configuration

挖了很多,我找到了这个配置

-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.port=1098
-Dcom.sun.management.jmxremote.rmi.port=1098
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.local.only=false

The difference with the other above is that java.rmi.server.hostnameis set to localhostinstead of 0.0.0.0

与上面另一个的区别java.rmi.server.hostname是设置为localhost而不是0.0.0.0