Cómo adjunto VisualVM a un proceso Java simple que se ejecuta en un contenedor Docker


En realidad quería una solución que funcionara para contenedores JEE, específicamente para Glassfish, pero después de probar muchas combinaciones de configuraciones y no tuve éxito, reduje la configuración al caso más simple posible.

Aquí está mi demonio Hello World iniciado en un contenedor Docker. Quiero adjuntarle jconsole o VisulaVM. Todo está en la misma máquina.

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"]

Edificio: docker build -t hello-world-daemon .

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

Preguntas:

  • ¿qué parámetros JVM se deben agregar a la línea de comandos CMD?
  • ¿qué puertos deben ser expuestos y publicados?
  • ¿qué modo de red debe usar el contenedor Docker?

No muestro mis intentos fallidos aquí para que las respuestas correctas no sean sesgadas. Esto debería ser un problema bastante común, sin embargo, no pude encontrar una solución de trabajo.

Actualización. Solución trabajada

Este archivo Dockerfile obras

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 combinación con el comando docker run

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

VisualVM se conecta haciendo clic con el botón derecho Local->Add JMX Connection, y luego ingresando localhost:9010, o agregando un host remoto.

JConsole se conecta mediante la selección de un proceso remoto con localhost:9010.

Al definir la conexión como remota, se puede utilizar cualquier interfaz listada por ifconfig. Por ejemplo, docker0 la interfaz con la dirección 172.17.0.1 funciona. La dirección del contenedor 172.17.0.2 funciona demasiado.

Author: nolexa, 2016-01-31

3 answers

Al principio debería ejecutar su aplicación con estos parámetros de 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

Entonces debería exponer el puerto para docker:

EXPOSE 9010

También especifique el enlace de puertos con el comando docker run:

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

Después de eso, puede conectarse con Jconsole al puerto local 9010 y administrar la ejecución de la aplicación en Docker.

 30
Author: eg04lt3r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-31 02:13:11

Seguí otra respuesta a una pregunta similar y funcionó.

Comencé mi proceso Java dentro del contenedor agregando esos parámetros 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

E inició el contenedor Docker especificando -e HOST_HOSTNAME=$HOSTNAME -p <port> al comando docker run.

Entonces he podido acceder a esta aplicación Java remota desde mi JVisualVm local agregando una conexión JMX remota ("Archivo" > "Agregar una conexión JMX...") y especificando <dockerhostname>:<port> en la entrada "Connection", y marcando " Do not require Conexión SSL".

 7
Author: Anthony O.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:03

Como respondió Anthony. Tuve que usar la opción -Djava.rmi.server.hostname java en mi máquina Windows.

Solo asegúrese de no usar el CMD en formato JSON en su Dockerfile ya que esto no soporta la expansión del shell.

Ejemplo 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
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-14 14:58:27