J'essaie de surveiller à distance une JVM fonctionnant dans Docker. La configuration ressemble à ceci:
machine 1: exécute une machine virtuelle Java (dans mon cas, exécutant kafka) dans docker sur une machine ubuntu; l'IP de cette machine est 10.0.1.201; l'application s'exécutant dans docker est à 172.17.0.85.
machine 2: exécute la surveillance JMX
Notez que lorsque j'exécute la surveillance JMX à partir de la machine 2, il échoue avec une version de l'erreur suivante (remarque: la même erreur se produit lorsque j'exécute jconsole, jvisualvm, jmxtrans et node-jmx/npm: jmx):
La trace de la pile en cas d'échec ressemble à ceci pour chacun des outils de surveillance 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)
Maintenant, la partie intéressante est que lorsque j'exécute les mêmes outils (jconsole, jvisualvm, jmxtrans et node-jmx/npm: jmx) sur la même machine qui exécute docker (machine 1 à partir du haut), la surveillance JMX fonctionne correctement.
Je pense que cela suggère que mon port JMX est actif et fonctionne correctement, mais que lorsque j'exécute la surveillance JMX à distance (à partir de la machine 2), il semble que l'outil JMX ne reconnaisse pas l'IP docker interne (172.17.0.85)
Voici les éléments de configuration réseau pertinents (je pense) sur la machine 1 où la surveillance JMX fonctionne (notez l'IP docker, 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)
Et ce sont les éléments de configuration réseau pertinents sur la machine distante (machine 2) à partir de laquelle je reçois les erreurs 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
Pour être complet, la solution suivante a fonctionné. La machine virtuelle Java doit être exécutée avec des paramètres spécifiques définis pour activer la surveillance JMX du docker distant:
-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's JMX port is configured (docker run --publish 7203:7203, for example where PORT is 7203). Both `port` and `rmi.port` can be the same.
Une fois cela fait, vous devriez pouvoir exécuter la surveillance JMX (jmxtrans, node-jmx, jconsole, etc.) à partir d'une machine locale ou distante.
Merci à @ Chris-Heald pour en avoir fait une solution vraiment rapide et simple!
Pour l'environnement de développement, vous pouvez définir Java.rmi.server.hostname
à adresse IP catch-all 0.0.0.0
Exemple:
-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
J'ai trouvé qu'il était difficile de configurer JMX sur RMI, en particulier à cause du -Djava.rmi.server.hostname=<IP>
que vous devez spécifier au démarrage. Nous exécutons nos images de docker dans Kubernetes où tout est dynamique.
J'ai fini par utiliser JMXMP au lieu de RMI, car cela n'a besoin que d'un seul TCP ouvert et pas de nom d'hôte).
Mon projet actuel utilise Spring, qui peut être configuré en ajoutant ceci:
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean"/>
(En dehors de Spring, vous devez configurer votre propre JMXConncetorServer pour que cela fonctionne)
Parallèlement à cette dépendance (puisque JMXMP est une extension facultative et ne fait pas partie du JDK):
<dependency>
<groupId>org.glassfish.main.external</groupId>
<artifactId>jmxremote_optional-repackaged</artifactId>
<version>4.1.1</version>
</dependency>
Et vous devez ajouter le même pot que votre chemin de classe lors du démarrage de JVisualVM afin de vous connecter via JMXMP:
jvisualvm -cp "$Java_HOME/lib/tools.jar:<your_path>/jmxremote_optional-repackaged-4.1.1.jar"
Connectez-vous ensuite avec la chaîne de connexion suivante:
service:jmx:jmxmp://<url:port>
(Le port par défaut est 9875)
Après avoir beaucoup fouillé, j'ai trouvé cette configuration
-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
La différence avec l'autre ci-dessus est que Java.rmi.server.hostname
est défini sur localhost
au lieu de 0.0.0.0