How to access JMX interface in docker container on VM from outside? - java

I am trying to remotely monitor a JVM running in docker. The configuration looks like this:
machine: runs a JVM (in my case, Hello-World springboot app) in docker on an ubuntu machine (VM);
the IP of this machine is 10.10.1.29;
docker container has IP 172.28.0.3;
and to connect to VM by ssh I putted my creds
I have DockerFile of myApp
// some docker commands
EXPOSE 9010
CMD ["java", \
"-Dcom.sun.management.jmxremote", \
"-Dcom.sun.management.jmxremote.authenticate=false", \
"-Dcom.sun.management.jmxremote.ssl=false", \
"-Dcom.sun.management.jmxremote.port=9010", \
"-Dcom.sun.management.jmxremote.rmi.port=9010", \
"-Djava.rmi.server.hostname=10.10.1.29", \
"-jar /app/myApp-1.0.0.jar"]
the container starts and everything is super by docker-compose
config docker-compose.yaml:
// some yaml config
ports:
- "9010:9010" # JMX
I am running jconsole locally and tried to run this
service:jmx:rmi:///jndi/rmi://10.10.1.29:9010/jmxrmi
but connection failed
I tried different options but unfortunately unsuccessfully
Does anyone have a solution to this? Maybe the configuration is incorrect?

You will have to look into several issues here:
run the JVM with JMX enabled. Be aware of the port that is opened to access these values
run the docker container such that the port to the outside of the container
as the container is running inside some OS ensure there is no firewall preventing access to this port from outside the OS
as the OS is running inside a VM ensure that VM is fowarding traffic to the correct port
from outside the VM access the correct interface/port. If this access is from outside the host OS, ensure the host OS does not implement a firewall and forwards the traffic correctly
Failure on any of these points will simply not give you access.

Related

How to connect to JMX server running inside WSL2

I'm running my Java application with the following parameters that enable JMX server's remote connections:
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=9998
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
I can successfully connect to that JMX server via VisualVM by adding a new JMX Connection to address: <HOSTNAME>:9998
But when i run that application inside Windows Subsystem for Linux 2 (WSL2) Visual VM cannot connect to localhost:9998:
connection failed
For what I know, every port that the application is listening on in WSL2 is also opened in host machine (Windows itself), and I can check that using Win+R -> cmd -> telnet localhost 9998 (connected successfully).
Also, I'm running an nginx instance inside WSL2 that I can connect to by any browser on my host machine (Windows) using localhost.
I had the same problem and finally I found a working set of properties for my WSL2. Additionally I had additional requirement to set it up for docker container running inside WSL2, while JConsole/VisualVM was running on Windows host. I have also a VPN running which probably mess up networking even more.
I found this application https://github.com/cluther/jmx-tester to be useful in debugging the connection.
inside WSL2
java \
-Dcom.sun.management.jmxremote=true \
-Djava.rmi.server.hostname=127.0.0.1 \
-Dcom.sun.management.jmxremote.port=9991 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.registry.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.net.preferIPv4Stack=true \
-jar jmx-tester-1.0.0.jar
Then on Windows host connect JMX to 127.0.0.1:9991
docker container inside WSL2
java \
-Dcom.sun.management.jmxremote=true \
-Djava.rmi.server.hostname=127.0.0.1 \
-Dcom.sun.management.jmxremote.host=0.0.0.0 \
-Dcom.sun.management.jmxremote.port=9991 \
-Dcom.sun.management.jmxremote.rmi.port=9991 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.registry.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.net.preferIPv4Stack=true \
-jar jmx-tester-1.0.0.jar
Then on Windows host connect JMX to 127.0.0.1:9991
I wasn't able to get Windows jconsole to connect to a JVM running in WSL2 using any of the suggestions above, however it is now possible to run Linux jconsole in WSL2, using Windows 11's Linux GUI support. Works perfectly.
In my case it depends on java.net.preferIPv6Addresses https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/net/doc-files/net-properties.html
Default value is false
I have server running on WSL2 and client running on Win11:
c:>java -Djava.net.preferIPv6Addresses=system my.My2 http://localhost:8025
http://localhost:8025
{"timestamp":"2022-04-22T10:25:03.819+00:00","status":"404","error":"Not Found","path":"/"}
c:>java -Djava.net.preferIPv6Addresses=true my.My2 http://localhost:8025
http://localhost:8025
{"timestamp":"2022-04-22T10:25:14.544+00:00","status":"404","error":"Not Found","path":"/"}
c:>java -Djava.net.preferIPv6Addresses=false my.My2 http://localhost:8025
http://localhost:8025
Exception in thread "main" java.net.ConnectException
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:571)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:123)
at my.My2.main(My2.java:15)
Caused by: java.net.ConnectException
...
c:>java my.My2 http://localhost:8025
http://localhost:8025
Exception in thread "main" java.net.ConnectException
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:571)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:123)
at my.My2.main(My2.java:15)
Caused by: java.net.ConnectException
...
This seems to be a general issue with Java.
https://github.com/microsoft/WSL/discussions/6253
A workaround that worked for me was listening on '0.0.0.0' instead of '127.0.0.1' in WSL2 with the JMX server.

Web server failed to start. Port 8080 was already in use

I am trying to develope a webapp using spring boot in STS. While running my app i am getting
Description:
Web server failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or
configure this application to listen on another port.
I have tried to close the application for port 8080. I found the PID for the port and terminated it using
taskkill /F /PID pidname
I restarted the STS and tried to run again but its throwing the same error.
If port is acquired by some OS thread, it would be a bit tricky to stop it. Although it's not always great solution, but if you still want to continue with your development without any issue you can use this alternative solution (as you are in development environment).
Here is another thing you can use. You can replace the default port for Spring Boot server to some other port number.
For server port the property is server.port.
If you are using application.properties file:
server.port=8081
It will start server on port 8081.
Similarly, you can do the same if using an application.yml file:
server:
port : 8081
Each file is loaded by Spring Boot if placed in the src/main/resources directory of a Maven application.
Your only other option (beside making port 8080 available or using another port for spring boot) is running the application in docker:
Create a Dockerfile in your application directory
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Run in terminal
sudo docker build -t spring-app . && docker run -d -p 8080:8080 -t springapp
(This assumes you have docker installed, please install it if you don’t have it)

Not able to access the docker containerised java web app on exposed port

I have Java web app in docker container.
Now container is exposed on host's port 8080 from container's port 8080 by running docker run command.
docker run -d -p 8080:8080 --name myTomcat -v $(pwd)/out/artifacts/DockerJavaWebAppWarExploded:/usr/local/tomcat/webapps/ tomcat:latest
There is no other process running on 8080 port ,but i am not able to access the application from browser http://localhost:8080/.
Container logs :
Please help.
It would be appreciated.
Check if http://0.0.0.0:8080 returns values. If yes, you may add an enrty for 0.0.0.0 in your hosts file.

Run a Docker Image as a Container (for windows users)

I built a docker image from a dockerfile. I see the image was built successfully (
$ docker images) and when I use this command to run the image as a container :
$ docker run -i -t 8dbd9e392a96
My application was running successfully, but when I'm trying to open I've this message
This site can’t be reached
This is my list of images :
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest b9c52b9f2999 About an hour ago 143MB
openjdk 8-jre-alpine 14a48fdee8af 3 days ago 83MB
and my containers list :
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4dbb68c87813 b9c52b9f2999 "./entrypoint.sh" 27 minutes ago Up 27 minutes 8080/tcp dazzling_shirley
I got this result after running the app using docker image :
----------------------------------------------------------
Application 'blog' is running! Access URLs:
Local: http://localhost:8080
External: http://172.17.0.2:8080
Profile(s): [dev, swagger]
----------------------------------------------------------
I dunno why the app didn't work any help please ?? !
Are you using docker toolbox for windows. Docker toolbox on windows runs docker in a Linux based virtualbox vm. You might have to open the port in the virtual box VM itself. So your host os can access the guest os's port.
See https://www.simplified.guide/virtualbox/port-forwarding
You have to map the docker container port to the host port. The reason is docker container is an isolated environment and it's public ip is same as that of the host machine. You have to ensure that host knows when to redirect requests to the container. So when you map the host port to docker container port, all the requests coming to HOST_IP_ADDRESS:HOST_PORT are redirected to the docker container whose port is mapped to the HOST_PORT.
You do that by using -p flag while using the docker run command as shown below:
docker run -it -p 8080:8080 IMAGE_NAME
Now all the requests coming to localhost:8080 will be directed to application running in container.

Ignite running in Docker (is: General Java-Docker issue)

I am trying to run ignite in a Docker container (Mac OS X, Docker 1.9.1) as committed in git:
# Start from a Java image.
FROM java:7
# Ignite version
ENV IGNITE_VERSION 1.5.0-b1
WORKDIR /opt/ignite
ADD http://www.us.apache.org/dist/ignite/1.5.0-b1/apache-ignite-fabric-1.5.0-b1-bin.zip /opt/ignite/ignite.zip
# Ignite home
ENV IGNITE_HOME /opt/ignite/apache-ignite-fabric-1.5.0-b1-bin
RUN unzip ignite.zip
RUN rm ignite.zip
# Copy sh files and set permission
ADD ./run.sh $IGNITE_HOME/
RUN chmod +x $IGNITE_HOME/run.sh
CMD $IGNITE_HOME/run.sh
After building it locally to apache/ignite and running the image with following command, the container 'hangs'
docker run --expose=4700-4800 -it -p 47500-47600:47500-47600 -p 47100-47200:47100-47200 --net=host -e "CONFIG_URI=https://raw.githubusercontent.com/apache/ignite/master/examples/config/example-default.xml" apacheignite/ignite-docker
When connecting to the container (docker exec -ti apache/ignite /bin/bash) and running the command in verbose mode via bash, it hangs on org.apache.ignite.startup.cmdline.CommandLineRandomNumberGenerator:
bash -x /opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/bin/ignite.sh https://raw.githubusercontent.com/apache/ignite/master/examples/config/example-default.xml
Output where it hangs:
+ CP='/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-indexing/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-spring/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/licenses/*'
++ /usr/bin/java -cp '/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-indexing/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-spring/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/licenses/*' org.apache.ignite.startup.cmdline.CommandLineRandomNumberGenerator
Looking at the code of CommandLineRandomNumberGenerator, I don't see anything special, just one line to generate a UUID. Are there other things that are automatically started somehow that causes locking a threat so that the application cannot exit?
This seems to be a docker issue with java in general, see also:
https://github.com/docker/docker/issues/18180
Several solutions possible:
create a docker machine as follows and run it in here (cfr. https://github.com/docker/docker/issues/18180#issuecomment-162568282):
docker-machine create -d virtualbox --engine-storage-driver overlay overlaymachine
Add System.exit(0) explicit at the end of each main method (cfr. https://github.com/docker/docker/issues/18180#issuecomment-161129296)
Wait for next docker patched version (https://github.com/docker/docker/issues/18180#issuecomment-170656525)
I think it would be good practice (for now) to add System.exit to all main methods in Ignite since this is independent of alternative hacks on docker or linux in general (linux kernel need AUFS upgrade and many machine may lag behind before that). This way future Ignite version can safely be installed on older kernels also.

Categories

Resources