Подтвердить что ты не робот

Как получить доступ к интерфейсу JMX в докере извне?

Я пытаюсь удаленно контролировать JVM, работающий в докере. Конфигурация выглядит так:

  • машина 1: запускает JVM (в моем случае, работает kafka) в докере на машине ubuntu; IP этой машины составляет 10.0.1.201; приложение, работающее в докере, составляет 172.17.0.85.

  • машина 2: запускает мониторинг JMX

Обратите внимание, что когда я запускаю мониторинг JMX с машины 2, он терпит неудачу с версией следующей ошибки (обратите внимание: такая же ошибка возникает при запуске 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)

Теперь интересная часть заключается в том, что я запускаю те же инструменты (jconsole, jvisualvm, jmxtrans и node -jmx/npm: jmx) на том же компьютере, на котором работает докер (машина 1 сверху) работает JMX-мониторинг должным образом.

Я думаю, это говорит о том, что мой порт JMX активен и работает нормально, но при удаленном удалении JMX-мониторинга (с машины 2) похоже, что JMX-инструмент не распознает внутренний IP-адрес докеров (172.17.0.85)

Ниже приведены соответствующие элементы конфигурации сети (я думаю) на машине 1, где работает мониторинг JMX (обратите внимание на докер 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
4b9b3361

Ответ 1

Для полноты работы сработало следующее решение. JVM должна быть запущена с определенными параметрами, установленными для включения мониторинга 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 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 за то, что сделали это действительно быстрым и простым исправлением!

Ответ 2

Для среды разработки вы можете установить java.rmi.server.hostname на java.rmi.server.hostname IP-адрес 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

Ответ 3

Я обнаружил, что попытка настроить JMX поверх RMI - это боль, особенно из-за -Djava.rmi.server.hostname=<IP>, которую вы должны указать при запуске. Мы запускаем наши фотографии докеров в Кубернете, где все динамично.

В итоге я использовал 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, чтобы подключиться через JMXMP:

jvisualvm -cp "$JAVA_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar"

Затем подключитесь к следующей строке подключения:

service:jmx:jmxmp://<url:port>

(порт по умолчанию - 9875)

Ответ 4

Я создал проект GitHub, который содержит готовую реализацию JMX из контейнера Docker.

Он содержит Dockerfile с правильным entrypoint.sh и a docker-compose.yml для легкого развертывания.

Ответ 5

Покопавшись довольно много, я нашел эту конфигурацию

-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