如何从外部访问 docker 中的 JMX 接口?
How to access JMX interface in docker from outside?
我正尝试在 docker 中远程监控 JVM 运行ning。配置如下所示:
机器 1:运行在 ubuntu 机器上 docker 中的 JVM(在我的例子中,运行ning kafka);本机IP为10.0.1.201; docker 中的应用程序 运行ning 位于 172.17.0.85。
机器 2:运行s 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)
现在有趣的部分是,当我 运行 在 运行ning [=] 的同一台机器上使用相同的工具(jconsole、jvisualvm、jmxtrans 和 node-jmx/npm:jmx)时40=](上面的机器 1)JMX 监控工作正常。
我认为这表明我的 JMX 端口处于活动状态并且工作正常,但是当我远程执行 JMX 监视(从机器 2)时,JMX 工具似乎无法识别内部 docker IP( 172.17.0.85)
以下是 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)
这是我收到 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
为完整起见,以下解决方案有效。 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.
一旦完成,您应该能够从本地或远程计算机执行 JMX 监控(jmxtrans、node-jmx、jconsole 等)。
感谢 @Chris-Heald 让这个问题变得非常快速和简单!
我发现尝试通过 RMI 设置 JMX 很痛苦,尤其是因为您必须在启动时指定 -Djava.rmi.server.hostname=<IP>
。我们是 运行 我们的 docker Kubernetes 中的图像,其中一切都是动态的。
我最终使用了 JMXMP 而不是 RMI,因为这只需要打开一个 TCP 端口,并且不需要主机名。
我当前的项目使用Spring,可以通过添加这个来配置:
<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 时将相同的 jar 添加到您的类路径中,以便通过 JMXMP 进行连接:
jvisualvm -cp "$JAVA_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar"
然后使用以下连接字符串进行连接:
service:jmx:jmxmp://<url:port>
(默认端口为 9875)
对于开发环境,您可以将 java.rmi.server.hostname
设置为 catch-all IP address 0.0.0.0
示例:
-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
经过一番摸索,我找到了这个配置
-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
与上面的不同的是java.rmi.server.hostname
设置为localhost
而不是0.0.0.0
为了增加一些额外的见解,我使用了一些 Docker 端口映射,并且 none 之前的答案直接对我有用。经过调查,我在这里找到了答案: 以提供所需的见解。
这就是我认为会发生的事情:
我按照其他答案中的建议设置了 JMX:
-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
程序流程:
- I 运行 Docker 容器和 expose/map 从主机到容器的端口。假设我在 Docker.
中映射端口 host:1099->container:1098
- 我运行里面的JVMdocker用上面的JMX设置。
- Docker 容器内的 JMX 代理现在侦听给定端口 1098。
- 我在主机(Docker 之外)上使用 URL localhost:1099 启动 JConsole。我使用 1099,因为我使用
host:docker
1099:1098 的端口映射。
- JConsole 可以很好地连接到 Docker 中的 JMX 代理。
- JConsole 询问 JMX 从哪里读取监控数据。
- JMX 代理响应配置的信息和地址:
localhost:1098
- JConsole 现在尝试连接到给定地址
localhost:1098
- 这失败了,因为本地主机上的端口 1098(在 Docker 之外)没有监听。端口 1099 映射到
Docker:1098
。而不是 localhost:1098
,JMX 应该告诉 JConsole 从 localhost:1099
读取监控信息,因为 1099 是从主机映射到 Docker 容器内的 1098 的端口。
作为修复,我将 host:docker
端口映射从 1099:1098
更改为 1098:1098
。现在,JMX 仍然告诉 JConsole 连接到 localhost:1098
以获取监控信息。但现在它可以工作了,因为外部端口与 JMX 在 Docker.
中宣传的相同
我希望同样适用于 SSH 隧道和类似场景。您必须匹配您配置 JMX 进行广告的内容以及 JConsole 在您 运行 主机上看到的地址 space。
或许可以尝试使用 jmxremote.port
、jmxremove.rmi.port
和 hostname
属性来使用不同的端口映射来完成这项工作。但是我有机会使用相同的端口,所以使用它们简化了它,这对我来说很有效。
我正尝试在 docker 中远程监控 JVM 运行ning。配置如下所示:
机器 1:运行在 ubuntu 机器上 docker 中的 JVM(在我的例子中,运行ning kafka);本机IP为10.0.1.201; docker 中的应用程序 运行ning 位于 172.17.0.85。
机器 2:运行s 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)
现在有趣的部分是,当我 运行 在 运行ning [=] 的同一台机器上使用相同的工具(jconsole、jvisualvm、jmxtrans 和 node-jmx/npm:jmx)时40=](上面的机器 1)JMX 监控工作正常。
我认为这表明我的 JMX 端口处于活动状态并且工作正常,但是当我远程执行 JMX 监视(从机器 2)时,JMX 工具似乎无法识别内部 docker IP( 172.17.0.85)
以下是 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)
这是我收到 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
为完整起见,以下解决方案有效。 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.
一旦完成,您应该能够从本地或远程计算机执行 JMX 监控(jmxtrans、node-jmx、jconsole 等)。
感谢 @Chris-Heald 让这个问题变得非常快速和简单!
我发现尝试通过 RMI 设置 JMX 很痛苦,尤其是因为您必须在启动时指定 -Djava.rmi.server.hostname=<IP>
。我们是 运行 我们的 docker Kubernetes 中的图像,其中一切都是动态的。
我最终使用了 JMXMP 而不是 RMI,因为这只需要打开一个 TCP 端口,并且不需要主机名。
我当前的项目使用Spring,可以通过添加这个来配置:
<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 时将相同的 jar 添加到您的类路径中,以便通过 JMXMP 进行连接:
jvisualvm -cp "$JAVA_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar"
然后使用以下连接字符串进行连接:
service:jmx:jmxmp://<url:port>
(默认端口为 9875)
对于开发环境,您可以将 java.rmi.server.hostname
设置为 catch-all IP address 0.0.0.0
示例:
-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
经过一番摸索,我找到了这个配置
-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
与上面的不同的是java.rmi.server.hostname
设置为localhost
而不是0.0.0.0
为了增加一些额外的见解,我使用了一些 Docker 端口映射,并且 none 之前的答案直接对我有用。经过调查,我在这里找到了答案:
这就是我认为会发生的事情:
我按照其他答案中的建议设置了 JMX:
-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
程序流程:
- I 运行 Docker 容器和 expose/map 从主机到容器的端口。假设我在 Docker. 中映射端口 host:1099->container:1098
- 我运行里面的JVMdocker用上面的JMX设置。
- Docker 容器内的 JMX 代理现在侦听给定端口 1098。
- 我在主机(Docker 之外)上使用 URL localhost:1099 启动 JConsole。我使用 1099,因为我使用
host:docker
1099:1098 的端口映射。 - JConsole 可以很好地连接到 Docker 中的 JMX 代理。
- JConsole 询问 JMX 从哪里读取监控数据。
- JMX 代理响应配置的信息和地址:
localhost:1098
- JConsole 现在尝试连接到给定地址
localhost:1098
- 这失败了,因为本地主机上的端口 1098(在 Docker 之外)没有监听。端口 1099 映射到
Docker:1098
。而不是localhost:1098
,JMX 应该告诉 JConsole 从localhost:1099
读取监控信息,因为 1099 是从主机映射到 Docker 容器内的 1098 的端口。
作为修复,我将 host:docker
端口映射从 1099:1098
更改为 1098:1098
。现在,JMX 仍然告诉 JConsole 连接到 localhost:1098
以获取监控信息。但现在它可以工作了,因为外部端口与 JMX 在 Docker.
我希望同样适用于 SSH 隧道和类似场景。您必须匹配您配置 JMX 进行广告的内容以及 JConsole 在您 运行 主机上看到的地址 space。
或许可以尝试使用 jmxremote.port
、jmxremove.rmi.port
和 hostname
属性来使用不同的端口映射来完成这项工作。但是我有机会使用相同的端口,所以使用它们简化了它,这对我来说很有效。