无法远程连接JMX端口

6

我正在尝试远程连接到一个JMX端口,但即使该端口已打开,似乎仍无法连接。它是在Nomad工作节点上运行的容器内Java进程,正在运行于 29406 端口。

下面是 netstat 显示的信息:

netstat -tulpn | grep 29406
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 10.137.2.166:29406      0.0.0.0:*               LISTEN      -               
udp        0      0 10.137.2.166:29406      0.0.0.0:*                           -   

这是位于/etc/hosts中的内容。
cat /etc/hosts
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts

我已经在服务器上下载了jmxterm,并尝试连接它时发现了一个有趣的行为。当我尝试使用localhost来连接端口时,会得到以下结果:

#RuntimeIOException: Runtime IO exception: Failed to retrieve RMIServer stub: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: 
    java.net.ConnectException: Connection refused (Connection refused)]

当我使用自己的IP地址时,它似乎可以正常工作:
$>open 10.137.2.166:29406
#Connection to 10.137.2.166:29406 is opened
$>

想了解为什么在服务器本身上运行时本地主机(localhost)无法使用...

我唯一成功让我的笔记本电脑上运行的 jconsole 连接到它的方式是使用 ssh 隧道,像这样:

ssh -Nf -D 7777 10.137.2.166
jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=7777 service:jmx:rmi:///jndi/rmi://10.137.2.166:29406/jmxrmi -J-DsocksNonProxyHosts=

我感觉应该能够在不创建隧道的情况下连接到它,但不确定为什么不能。如果我从我的笔记本电脑本地运行telnet到主机,连接似乎是打开的...

telnet 10.137.2.166 29406
Trying 10.137.2.166...
Connected to 10.137.2.166.
Escape character is '^]'.

1
也许这个问题可以提供一些答案:https://dev59.com/rJXfa4cB1Zd3GeqPZAqb?rq=1?我还怀疑可能与防火墙有关? - Titulum
RMI(它驱动JMX的默认版本)会打开额外的网络流。这是一个不容易解决的问题。在容器内运行(允许使用attach api)是否是一个选项? - Thorbjørn Ravn Andersen
3个回答

5

要成功进行JMX握手,请注意以下几点:

  1. JMX服务器应该可以使用外部主机名访问(也需要通过java.rmi.server.hostname系统属性在服务器JVM上声明)

  2. 除了一个开放端口之外(可以通过com.sun.management.jmxremote.rmi.port JVM属性显式声明),JMX服务器还会选择随机的另一个端口用于新的JMX连接。这很麻烦,因为你无法预见特定端口,以便从服务器的防火墙限制中排除它,因此需要使用隧道。


我在Docker Compose上使用Prometheus-jmx-exporter和Kafka连接器时遇到了问题。我将这两个容器放在同一个网络上,这样它们就共享了localhost而不是暴露每个端口。感谢您的帮助。 - Martin Naughton

1

服务器仅在10.137.2.166上监听。

当您尝试使用localhost域创建新套接字时,您的应用程序会尝试建立127.0.0.1地址,但您的应用程序并未在此IP上进行监听。

如果您想连接到localhost域,有几个解决方法:

  1. 更改服务器配置以同时在127.0.0.1和10.137.2.166上进行监听。
  2. 更改服务器配置以侦听0.0.0.0

    由于安全原因,不建议侦听0.0.0.0

  3. 使用iptables转发端口。需要root权限。

sysctl net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -i lo --dport 29406 -j DNAT --to-destination 10.137.2.166:29406
iptables -A FORWARD -p tcp -d 10.137.2.166 --dport 29406 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
  1. 如果您没有root权限,可以使用socat。
socat TCP-LISTEN:29406,fork,bind=127.0.0.1 TCP:10.137.2.166:29406

您可以在所有接口(0.0.0.0)上进行监听,然后使用iptables限制使用。 - jiwopene

1

我只使用jmx进行visualvm连接,在这种情况下需要两个端口可用: com.sun.management.jmxremote.port=9010 com.sun.management.jmxremote.rmi.port=9011

此外,java.rmi.server.hostname需要根据正确的网络接口进行设置,因为端口仅绑定在该接口上。

一旦客户端的端口可用,您就可以在jmxremote.port端口上使用jmx连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接