web-dev-qa-db-fra.com

Comment attacher VisualVM à un simple processus Java exécuté dans un conteneur Docker

En fait, je voulais une solution fonctionnant pour les conteneurs JEE, en particulier pour Glassfish, mais après avoir essayé de nombreuses combinaisons de paramètres et sans succès, j'ai réduit la configuration au cas le plus simple possible.

Voici mon démon Hello World démarré dans un conteneur Docker. Je veux y attacher jconsole ou VisulaVM. Tout est sur la même machine.

public class Main {
  public static void main(String[] args) {
    while (true) {
      try {
        Thread.sleep(3000);
        System.out.println("Hello, World");
      } catch (InterruptedException e) {
        break;
      }
    }
  }
}

Dockerfile

FROM Java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.Java
CMD ["Java", "Main"]

Bâtiment: docker build -t hello-world-daemon .

Fonctionnement: docker run -it --rm --name hwd hello-world-daemon

Des questions:

  • quels paramètres JVM doivent être ajoutés à la ligne de commande CMD?
  • quels ports devraient être exposés et publiés?
  • quel mode réseau le conteneur Docker doit-il utiliser?

Je ne montre pas mes tentatives infructueuses ici afin que les bonnes réponses ne soient pas biaisées. Cela devrait être un problème assez courant, mais je n'ai pas pu trouver de solution de travail.

Mise à jour. Solution travaillée

Ce Dockerfile fonctionne

FROM Java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.Java
CMD ["Java", \
"-Dcom.Sun.management.jmxremote", \
"-Dcom.Sun.management.jmxremote.port=9010", \
"-Dcom.Sun.management.jmxremote.local.only=false", \
"-Dcom.Sun.management.jmxremote.authenticate=false", \
"-Dcom.Sun.management.jmxremote.ssl=false", "Main"]
EXPOSE 9010

en combinaison avec la commande docker run

docker run -it --rm --name hwd -p 9010:9010 hello-world-daemon

VisualVM se connecte via un clic droit Local-> Ajouter une connexion JMX , puis en saisissant localhost:9010, ou en ajoutant un hôte distant.

JConsole se connecte en sélectionnant un processus distant avec localhost:9010.

Lorsque vous définissez la connexion comme distante, n'importe quelle interface répertoriée par ifconfig peut être utilisée. Par exemple, docker0 interface avec l'adresse 172.17.0.1 travaux. L'adresse du conteneur 172.17.0.2 fonctionne aussi.

43
nolexa

Au début, vous devez exécuter votre application avec ces paramètres JVM:

-Dcom.Sun.management.jmxremote
-Dcom.Sun.management.jmxremote.port=9010
-Dcom.Sun.management.jmxremote.local.only=false
-Dcom.Sun.management.jmxremote.authenticate=false
-Dcom.Sun.management.jmxremote.ssl=false

Ensuite, vous devez exposer le port pour docker:

EXPOSE 9010

Spécifiez également la liaison de port avec la commande docker run:

docker run -p 9010:9010 -it --rm --name hwd hello-world-daemon

Après cela, vous pouvez vous connecter avec Jconsole au port 9010 local et gérer l'exécution des applications dans Docker.

38
eg04lt3r

J'ai suivi ne autre réponse SO à une question similaire et cela a fonctionné.

J'ai commencé mon processus Java à l'intérieur du conteneur en ajoutant ces paramètres JVM:

-Dcom.Sun.management.jmxremote.port=<port> \
-Dcom.Sun.management.jmxremote.authenticate=false \
-Dcom.Sun.management.jmxremote.ssl=false \
-Dcom.Sun.management.jmxremote.rmi.port=<port> \
-Djava.rmi.server.hostname=$Host_HOSTNAME

et a démarré le conteneur Docker en spécifiant -e Host_HOSTNAME=$HOSTNAME -p <port> au docker run commande.

Ensuite, j'ai pu accéder à cette application Java Java de mon JVisualVm local en ajoutant une connexion JMX distante ("Fichier"> "Ajouter une connexion JMX ...")) et en spécifiant <dockerhostname>:<port> dans l'entrée "Connexion" et en cochant "Ne nécessite pas de connexion SSL".

8
Anthony O.

Comme répondu par Anthony . J'ai dû utiliser le -Djava.rmi.server.hostname Java sur ma machine Windows.

Assurez-vous simplement de ne pas utiliser le CMD au format JSON dans votre Dockerfile car cela ne prend pas en charge l'expansion de Shell.

Exemple de Dockerfile:

FROM Java:8
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN javac Main.Java
#Do not use CMD in JSON format here because Shell expansion doesn't work in JSON format
#Shell expansion is needed for the ${Host} variable.
CMD Java -Dcom.Sun.management.jmxremote=true \
-Dcom.Sun.management.jmxremote.rmi.port=9010 \
-Dcom.Sun.management.jmxremote.port=9010 \
-Dcom.Sun.management.jmxremote.ssl=false \
-Dcom.Sun.management.jmxremote.authenticate=false \
-Dcom.Sun.management.jmxremote.local.only=false \
-Djava.rmi.server.hostname=${Host} \
Main
2
Chris