Как подключиться к экземплярам Java, работающим на EC2, используя JMX
У нас возникла проблема подключения к нашим Java-приложениям, работающим в кластере Amazon EC2. Мы определенно допустили как "порт JMX" (который обычно является портом реестра RMI), так и порт сервера (который выполняет большую часть работы) для группы безопасности для рассматриваемых экземпляров. Jconsole подключается, но, кажется, висит и никогда не показывает никакой информации.
Мы запускаем нашу java с чем-то вроде следующего:
java -server -jar foo.jar other parameters here > java.log 2>&1
Мы попытались:
- Telnets для подключения портов, но информация не отображается.
- Мы можем запустить
jconsole
в самом экземпляре, используя remote-X11 поверх ssh, и он соединяет и показывает информацию. Таким образом, JRE экспортирует его локально.
- Открытие всех портов в группе безопасности. Weeee.
- Использование
tcpdump
, чтобы убедиться, что трафик не идет на другие порты.
- Имитация локально. Мы всегда можем подключаться к нашим локальным JRE или тем, которые работают в другом месте в нашей сети, используя те же параметры приложения.
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, который вы используете.
Ответы
Ответ 1
У нас возникла проблема подключения к нашим Java-приложениям, работающим в кластере Amazon EC2.
Оказывается, проблема была комбинацией двух отсутствующих настроек. Первое заставляет 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 (и почему, черт возьми, не хотите), как найти этот адрес во время выполнения. Для этого вам нужно добавить в наше приложение что-то вроде следующего: script:
# 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
IP в команде wget
выше предоставляет информацию о том, что экземпляр EC2 может запросить о себе. Я разочарован тем, что это не включает теги, которые доступны только при аутентифицированном вызове.
Сначала я использовал адрес extern ipv4, но похоже, что JDK пытается подключиться к серверному порту, когда он запускается. Если он использует внешний IP-адрес, это замедляет время загрузки приложения до истечения этого времени. Имя общедоступного узла разрешается локально для адреса 10-net и для public-ipv4 извне. Таким образом, приложение теперь работает быстро, и клиенты JMX все еще работают. Woo hoo!
Надеюсь, это поможет кому-то другому. Стоимость мне сегодня 3 часа.
Чтобы заставить JMX-сервер запускать сервер и реестр RMI на определенных портах, чтобы вы могли заблокировать их в группах безопасности EC2, см. этот ответ:
Как закрыть rmiregistry, запущенный на определенном порту?
Edit:
У нас только что эта проблема повторилась. Кажется, что Java JMX-код выполняет поиск по имени хоста по имени хоста и использует их, чтобы попытаться подключиться и проверить соединение JMX.
Проблема заключается в том, что локальное имя хоста для этого поля должно быть разрешено для локального ip-поля. Например, если ваш /etc/sysconfig/network
имеет HOSTNAME=server1.foobar.com
, то если вы выполняете поиск DNS на server1.foobar.com
, вы должны перейти к виртуальному адресу 10-NET. Мы создали собственный /etc/hosts
файл и имя хоста локального хоста отсутствовало в файле. Это заставило наши приложения либо приостанавливаться при запуске, либо вообще не запускаться.
Наконец
Одним из способов упрощения создания JMX является использование пакета SimpleJMX.
Ответ 2
За второй ответ Почему соединение JMX с Amazon EC2 не удается?, сложность здесь заключается в том, что по умолчанию порт RMI выбирается произвольно, а клиентам нужен доступ как для портов JMX, так и для RMI. Если вы используете jdk7u4 или более позднюю версию, порт 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>
Я также открыл порты 9998-9999 в группе безопасности EC2 для моего экземпляра.
Ответ 3
Ответ, данный Gray, работал у меня, однако я обнаружил, что мне нужно открывать порты TCP от 0 до 65535, или я не могу войти. Я думаю, что вы можете подключиться к основному порту JMX, а затем получить еще один назначены. Я получил от этот пост в блоге, который всегда работал хорошо для меня.
Ответ 4
Немного другой подход с использованием туннелей ssh
- Передайте следующие флагов в JVM
-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
- Проверьте, какие порты java начали использовать
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 туннелями для всех портов
ssh -N -L 1099:127.0.0.1:1099 [email protected]<ec2_ip>
ssh -N -L 37484:127.0.0.1:37484 [email protected]<ec2_ip>
ssh -N -L 45828:127.0.0.1:45828 [email protected]<ec2_ip>
- Подключение с помощью Java Mission Control к "localhost: 1099"