我们在连接到在Amazon的EC2群集中运行的Java应用程序时遇到问题。我们肯定允许“JMX端口”(通常是RMI注册表端口)和服务器端口(完成大部分工作)到相关实例的安全组。 Jconsole连接但似乎挂起并且从不显示任何信息。
我们正在使用以下内容运行java:
java -server -jar foo.jar other parameters here > java.log 2>&1
我们尝试过:
jconsole
,它会连接并显示信息。所以JRE 在本地导出它。tcpdump
确保流量不会转到其他端口。 java -version
输出:
OpenJDK Runtime Environment (IcedTea6 1.11.5) (amazon-53.1.11.5.47.amzn1-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)
顺便说一下,我们正在使用我的Simple JMX软件包,它允许我们设置两者 RMI注册表和服务器端口,这些端口通常由RMI注册表半随机选择。您也可以使用以下JMX URI强制执行此操作:
service:jmx:rmi://localhost:" + serverPort + "/jndi/rmi://:" + registryPort + "/jmxrmi"
现在,我们对服务器和注册表使用相同的端口。在过去,我们使用X
作为注册表端口,使用X+1
作为服务器端口,以使安全组规则变得容易。您连接到jconsole
中的注册表端口或您正在使用的任何JMX客户端。
答案 0 :(得分:38)
我们在连接到在Amazon的EC2群集中运行的Java应用程序时遇到问题。
事实证明,问题是两个缺失设置的组合。第一个强制JRE更喜欢ipv4而不喜欢 v6。这是必要的(我猜),因为我们试图通过v4地址连接到它:
-Djava.net.preferIPv4Stack=true
真正的阻止是JMX首先联系RMI端口,该端口响应主机名和端口供JMX客户端连接。如果没有其他设置,它将使用框的本地IP,这是远程客户端无法路由到的10.X.X.X
虚拟地址。我们需要添加以下设置,即外部主机名或服务器的IP - 在这种情况下,它是服务器的弹性主机名。
-Djava.rmi.server.hostname=ec2-107-X-X-X.compute-1.amazonaws.com
诀窍,如果你试图自动化你的EC2实例(以及你为什么不这样做),是如何在运行时找到这个地址。为此,您需要在我们的应用程序启动脚本中添加以下内容:
# get our _external_ hostname
RMI_HOST=`wget -q -O - http://169.254.169.254/latest/meta-data/public-hostname`
...
java -server \
-Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=$RMI_HOST \
-jar foo.jar other parameters here > java.log 2>&1
上面169.254.169.254
命令中的神秘wget
IP提供了EC2实例可以请求自身的信息。我很失望,不包含仅在经过身份验证的电话中可用的标签。
我最初使用的是extern ipv4地址,但看起来JDK在启动时尝试连接到服务器端口。如果它使用外部IP,那么这会减慢我们的应用程序启动时间,直到超时。 public-hostname在本地解析为10-net地址,从外部解析为public-ipv4。因此,应用程序现在正在快速启动,JMX客户端仍在工作。呜呜!
希望这有助于其他人。今天花了我3个小时。
要强制您的JMX服务器在指定端口上启动服务器和 RMI注册表,以便您可以在EC2安全组中阻止它们,请参阅以下答案:
修改强>
我们刚刚重新出现这个问题。似乎Java JMX代码正在对框的主机名进行一些主机名查找,并使用它们来尝试连接并验证JMX连接。
问题似乎是要求盒子的本地主机名解析为盒子的local-ip。例如,如果您的/etc/sysconfig/network
有HOSTNAME=server1.foobar.com
,那么如果您在server1.foobar.com
上进行DNS查找,则应该转到10-NET虚拟地址。我们正在生成自己的/etc/hosts
文件,文件中缺少本地主机的主机名。这导致我们的应用程序要么在启动时暂停,要么根本不启动。
<强>最后强>
简化JMX创建的一种方法是使用我的SimpleJMX package。
答案 1 :(得分:12)
根据第二个答案Why does JMX connection to Amazon EC2 fail?,这里的难点是默认情况下,RMI端口是随机选择的,客户端需要访问JMX和RMI端口。如果您正在运行jdk7u4或更高版本,则可以通过app属性指定RMI端口。使用以下JMX设置启动我的服务器对我有用:
没有身份验证:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9998
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=<public EC2 hostname>
使用身份验证:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9998
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Djava.rmi.server.hostname=<public EC2 hostname>
我还在我的实例的EC2安全组中打开了端口9998-9999。
答案 2 :(得分:5)
使用ssh隧道有点不同的方法
-Dcom.sun.management.jmxremote.port=1099
-Djava.net.preferIPv4Stack=true
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=127.0.0.1
netstat -tulpn | grep java
tcp 0 0 0.0.0.0:37484 0.0.0.0:* LISTEN 2904/java
tcp 0 0 0.0.0.0:1099 0.0.0.0:* LISTEN 2904/java
tcp 0 0 0.0.0.0:45828 0.0.0.0:* LISTEN 2904/java
ssh -N -L 1099:127.0.0.1:1099 ubuntu@<ec2_ip>
ssh -N -L 37484:127.0.0.1:37484 ubuntu@<ec2_ip>
ssh -N -L 45828:127.0.0.1:45828 ubuntu@<ec2_ip>
答案 3 :(得分:1)
Gray给出的答案对我有用,但我发现我必须打开TCP端口0到65535或者我没有进入。我认为你可以在主JMX上连接端口,然后分配另一个。我从this blog post那里得到了那个对我来说一直很好的。
答案 4 :(得分:0)
我们正在使用AWS Elastic Container Service运行我们的Spring Boot服务。 下面的配置允许我们连接到我们的docker容器。
未经身份验证:
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9090 \
-Dcom.sun.management.jmxremote.rmi.port=9090 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=$(/usr/bin/curl -s --connect-timeout 2 \
http://169.254.169.254/latest/meta-data/public-ipv4)
我发现它很清晰,也不需要任何其他服务方初始化脚本。