How do I attach VisualVM to a simple Java process running in a Docker container

visualvm connect to remote docker container
jvisualvm
docker java profiler
jstat inside docker
docker jmx
visualvm connect to remote jvm
jdwp visualvm
docker jstatd

Actually I wanted a solution working for JEE containers, specifically for Glassfish, but after I tried many combinations of settings and did not succeed, I reduced the setup to the simplest possible case.

Here is my Hello World daemon started in a Docker container. I want to attach jconsole or VisulaVM to it. Everything is on the same 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"]

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

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

Questions:

  • what JVM parameters should be added to CMD command line?
  • what ports should be exposed and published?
  • what network mode should Docker container be using?

I do not show my failed attempts here so that correct answers will not be biased. This should be a pretty common problem, yet I could not find a working solution.

Update. Worked solution

This Dockerfile works

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

in combination with the docker run command

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

VisualVM connects via right click Local->Add JMX Connection, and then entering localhost:9010, or through adding a remote host.

JConsole connects via selecting a Remote process with localhost:9010.

When defining the connection as remote, any interface listed by ifconfig can be used. For instance, docker0 interface with address 172.17.0.1 works. The container's address 172.17.0.2 works too.

At first you should run you application with these JVM params:

-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

Then you should expose port for docker:

EXPOSE 9010

Also specify port binding with docker run command:

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

After that you can connect with Jconsole to local 9010 port and manage application run in Docker.

Connecting VisualVM to a Local Docker Container From Scratch , Connecting VisualVM to a Local Docker Container From Scratch a simple Java app, deploy it to Docker, and attach the VisualVM profiler on my Mac. There's very little needed to get basic functionality up and running. How do I attach VisualVM to a simple Java process running in a Docker container Eigentlich wollte ich eine Lösung für JEE Container, speziell für Glassfish, aber nachdem ich viele Kombinationen von Einstellungen ausprobiert und nicht erfolgreich war, reduzierte ich das Setup auf den einfachsten möglichen Fall.

I followed an other SO response to a similar question and it worked.

I started my Java process inside the container by adding those JVM params:

-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

and started the Docker container specifying -e HOST_HOSTNAME=$HOSTNAME -p <port> to the docker run command.

Then I've been able to access to this remote Java app from my local JVisualVm by adding a remote JMX connection ("File" > "Add a JMX Connection...") and specifying <dockerhostname>:<port> in the "Connection" input, and checking "Do not require SSL connection".

Ethan's Tech Blog, Connecting to a JVM is easy with VisualVM, butwhen it's a remote machine you need to add a few Connect Visual VM to a docker container You need to start java with a few extra parameters, so your Dockerfile might end with something like this: Then you want to run your container with the port open and specified: Attach to a process running on a Linux Docker container. You can attach the Visual Studio debugger to a process running in a Linux .NET Core Docker container on your local or remote machine using the Attach to Process dialog box.

As answered by Anthony. I had to use the -Djava.rmi.server.hostname java option on my Windows machine.

Just be sure not to use the CMD in JSON format in your Dockerfile as this doesn't support shell expansion.

Dockerfile example:

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

broilogabriel/visualvm-docker, Contribute to broilogabriel/visualvm-docker development by creating an /how- do-i-attach-visualvm-to-a-simple-java-process-running-in-a-docker-container. I have a docker container that I can excecute fine locally. Yet when run on a mesos cluster, I get SIGTERMS /usr/my_script.sh: line 57: 310 Killed xsltproc sort.xsl ${2} > ${2}_bat W0703 09:09:54.465442 5074 logging.cpp:91] RAW: Received signal SIGTERM from process 2262 of user 0; exiting I don't

To all of you that still suffer from an error like the below:

In my case it was that i used in my Docker YML different port mappings for the ports:

e.g:

15100:9090

but apparently in your port bindings you must assign the SAME port for external port and internal port !

Reference: https://forums.docker.com/t/exposing-mapped-jmx-ports-from-multiple-containers/5287/5

How to establish JMX connection to JVM running in docker : Adam , How to establish JMX connection to JVM running in docker. For remote monitoring of JVM processes (running in a docker container) --name jmx airhacks/tomee-jmx and connect with jvisualvm, jconsole, See you at Java EE Microservices. and Tuning and troubleshooting Java 14: A Simple Record 46 How do I attach VisualVM to a simple Java process running in a Docker container Jan 31 '16 18 Java “100%” to number Jan 19 '16 7 java spring repositories - findBy() method using set of IDs/values Jan 31 '16

FWIW, this is how I was able to attach VisualVM to a Java process inside a Docker container running on macOS:

Main.java:

public class Main {
    public static void main(String args[]) throws Exception {
        while (true) {
            System.out.print("Hello ");
            System.out.println("world");
            Thread.sleep(1000);
        }
    }
}

Dockerfile:

FROM openjdk:11.0.2-slim
COPY Main.class /
WORKDIR /
ENTRYPOINT ["java", \
"-Dcom.sun.management.jmxremote=true", \
"-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", \
"-Dcom.sun.management.jmxremote.rmi.port=9010", \
"-Djava.rmi.server.hostname=localhost", \
"Main"]

Compile the Java code, build the image and run the container like this:

$ javac Main.java
$ docker build -t main .
$ docker run -p 9010:9010 -it main

Then attach VisualVM using JMX to localhost:9010

Monitoring Java in Docker: Overcoming past limitations, Common limitations with Java in Docker containers The Java JVM can be shared between any number of Java processes in the same OS. feature in tools such as JConsole and VisualVM will not be available anymore. version of Java that's running on a container with a simple application on top… If you do not want Java VisualVM to connect to the host on startup, you should right-click the remote host node and choose Remove before quitting Java VisualVM. Note: To retrieve and display information on applications running on the remote host, the jstatd utility needs to be running on the remote host.

Monitoring Java Applications Running Inside Docker Containers, Connect VisualVM to an Application through JMX agents You can also install it as a separate application. The tool connects to local Java processes directly, but in order to connect to a Java application running inside a Docker container, it needs to connect through a JMX port. Java VisualVM is able to access and display data about applications running on remote hosts. After connecting to a remote host, Java VisualVM can display general data about the application's runtime environment and can monitor memory heap and thread activity.

Docker Monitoring: 5 Methods for Monitoring Java Applications in , Running applications in containers is an increasingly popular way of For most, integrating with Docker is becoming just another basic step Docker containers have matured enough to become a step in the APM installation process. You can add custom collection points in your Java applications with� Incorrect JDK is used for running VisualVM - if you haven't defined a JDK to run VisualVM manually, make sure that the default Java on your system is Oracle JDK 8+ Incorrectly set JDK for running VisualVM - if you have defined a JDK to run VisualVM manually, make sure the path to the JDK is correct and doesn't end with a slash

Ninjas' guide to getting started with VisualVM | by Ivo Anjo, VisualVM is a free Java/JVM tool that ships with most Oracle This is a simple one step process. Step 1: Step 2: Then, when running your docker container, expose port 9010 to your local machine: $ docker-compose run -p 9010:9010 < your service>. Step 3: Now you're all set to connect using VisualVM. Java VisualVM discovers running applications using the jps tool, which can only discover Java applications started by the same user as the one who starts the Java VisualVM tool. The target application is running on a remote host where jstatd is not running or is running but was started by a different user.

Comments
  • Nope.. VisualVM: Cannot connect to localhost:9010 using service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi. Jconsole: Connection failed: error during JRMP connection establishment; nested exception is: java.net.SocketException: Connection reset
  • why do you expose same port twice?
  • Connect not to localhost, to your network interface.
  • You expose docker port to port on your network interface.
  • It worked finally. My mistake was that I appended JVM options after the Main class name in the command line. All -D options were silently ignored by java.
  • What is $HOST_HOSTNAME exactly? Is it host of machine running docker or something else?
  • Yes, it is the hostname of the host running docker. It can be the result of the hostname command, so you could pass it to docker while launching your container like this: -e HOST_HOSTNAME=`hostname`
  • This answer worked perfectly for me, and giving the example Dockerfile made it easy.