我正在尝试远程监控在docker中运行的JVM。配置如下所示:
- 机器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)
现在有趣的部分是,当我在运行docker的同一台机器(上面的机器1)上运行相同的工具(jconsole,jvisualvm,jmxtrans和node-jmx/npm:jmx)时,JMX监控工作正常。
我认为这表明我的JMX端口是活动的并且工作正常,但是当我远程执行JMX监视时(从机器2),JMX工具看起来不识别内部docker IP(172.17.0.85)
下面是机器1上的相关(我认为)网络配置元素,其中JMX监控工作(注意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)上的相关网络配置元素,我从该远程机器上获得了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
6条答案
按热度按时间y1aodyip1#
为了完整起见,下面的解决方案是可行的。JVM应该使用特定的参数来运行,以启用远程docker JMX监控,如下所示:
完成后,您应该能够从本地或远程机器执行JMX监视(jmxtrans、node-jmx、jconsole等)。
感谢@Chris-Heald使这成为一个真正快速和简单的解决方案!
62lalag42#
对于开发环境,您可以将
java.rmi.server.hostname
设置为catch-all IP address0.0.0.0示例:
xzlaal3s3#
我发现尝试在RMI上设置JMX是一件痛苦的事情,特别是因为你必须在启动时指定
-Djava.rmi.server.hostname=<IP>
。我们在Kubernetes中运行我们的Docker镜像,一切都是动态的。我最终使用了JMXMP而不是RMI,因为这只需要打开一个TCP端口,而不需要主机名。
我当前的项目使用Spring,可以通过添加以下内容来配置:
(在Spring之外,您需要设置自己的JMXConncetorServer才能使其工作)
沿着这个依赖关系(因为JMXMP是一个可选的扩展,而不是JDK的一部分):
在启动JVisualVM时,您需要在类路径中添加相同的jar,以便通过JMXMP进行连接:
然后使用以下连接字符串进行连接:
(默认端口为9875)
omvjsjqw4#
在周围挖了相当多,我发现这个配置
与上面另一个的区别是
java.rmi.server.hostname
被设置为localhost
而不是0.0.0.0
wlsrxk515#
为了补充一些额外的见解,我使用了一些Docker端口Map,之前的答案都没有直接适用于我。经过调查,我在这里找到了答案:How to connect with JMX from host to Docker container in Docker machine?以提供所需的见解。
这就是我所相信的:
我按照其他答案中的建议设置了JMX:
程序流程:
host:docker
端口Map。localhost:1098
localhost:1098
Docker:1098
。JMX应该告诉JConsole从localhost:1099
读取监控信息,而不是localhost:1098
,因为1099是从主机Map到Docker容器内1098的端口。作为修复,我将我的
host:docker
端口Map从1099:1098
更改为1098:1098
。现在,JMX仍然告诉JConsole连接到localhost:1098
以获取监视信息。但现在它可以工作,因为外部端口与Docker中的JMX广告相同。我希望这同样适用于SSH隧道和类似的场景,你必须匹配你配置的JMX广告和JConsole看到的主机上的地址空间。
也许可以使用
jmxremote.port
、jmxremove.rmi.port
和hostname
属性来使用不同的端口Map,但我有机会使用相同的端口,所以使用它们简化了它,这是可行的(对我来说)。nnvyjq4y6#
AWS ECS等动态云解决方案
随后,在容器化应用程序的情况下,这意味着JMX/RMI配置需要JVM应用程序的预定义/静态端口,并且该端口应该在容器外部Map到容器内部的等效端口。这是使其工作的唯一方法。
因此,现在我想回答的主要问题是如何连接到运行在云中的JVM应用程序,该应用程序位于私有网络后面,并且只有当该端口由云管理而不是由我们管理时才由动态端口公开。
解决方案是存在的!它需要一些基础设施的巧妙方法。让我们看一下图表。
为了构建我们的JMX路由器,我们将使用HAproxy。为了构建镜像,我们需要
Dockerfile
:其中
entrypoint.sh
:haproxy.cfg
:在我们的JMX路由器映像准备好(发布到我们的寄存器)之后,我们可以在任务定义中使用它作为容器定义之一,例如。
这里我们将JMX静态端口定义为
9090
。您可以选择允许使用的任何端口。但是在您选择之后-这正是我们在启动JVM应用程序时用来查找ECSMap到它的动态端口的端口。现在,剩下的唯一任务就是获取分配给JMX路由器的动态端口,并将其用作JVM应用程序的RMI端口。为此,在
entrypoint.sh
中,我们为JVM应用程序映像创建了以下内容:因此,现在只要两个容器都启动并运行,就可以使用
HOST_SERVER_IP
和JMX_PORT
连接到ECS集群中的JVM应用程序。希望能帮上忙。