I want to monitor internals of JVM for my Spring Boot application inside a Docker which is running as a pod in a Kubernetes cluster. But I couldn't find satisfactory answer anywhere even after spending considerable time. I tried referring the accepted answer on this but it was connecting only when my docker was running locally, and ceased to connect while behind a Kubernetes cluster.
Asked
Active
Viewed 2,303 times
5
-
here is a working solution for AWS ECS https://stackoverflow.com/a/75806163/2852528 sure it's possible to adapt it for Kubernetes as well – Serhii Povísenko Mar 21 '23 at 20:59
1 Answers
10
Assume I wanted to monitor on port 8001 while my app was serving on 8000. Adding these to my VM options worked fine(VisualVM was showing this process for monitoring) while running Docker locally and mapping port 8001 from my local to Docker(-p 8001:8001)
-Dcom.sun.management.jmxremote \
-Djava.rmi.server.hostname=localhost \
-Dcom.sun.management.jmxremote.port=8001 \
-Dcom.sun.management.jmxremote.rmi.port=8001 \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false
But it didn't work on a pod in remote Kubernetes Cluster. I found this but my requirement was to monitor without going via Service and then by reading couple of other articles I got it working, so collating those steps below for saving someone's time:-
- Removed VM options mentioned above in the startup script
- Updated my application.yaml as below where I enabled jmx and added url for running JMXMP Connector server
spring:
application:
name: stack-application
jmx:
enabled: true
url: service:jmx:jmxmp://localhost:8001/
server:
port: 8000
- Updated my Kubernetes deployment YAML under Deployment block as:
apiVersion: apps/v1
kind: Deployment
----your content----
ports:
- name: stack-app-port
containerPort: 8000
- name: stack-jmx-port
containerPort: 8001
- Added following dependency to my pom.xml for downloading JMXMP as after my research I concluded that JMX monitoring over RMI is a tough job and hence JMXMP is everyone's recommendation.
<dependency>
<groupId>org.glassfish.main.external</groupId>
<artifactId>jmxremote_optional-repackaged</artifactId>
<version>5.0</version>
</dependency>
- Created a new class
ConnectorServiceFactoryBeanProvider
which fetches URL from our application.yaml
@Configuration
public class ConnectorServiceFactoryBeanProvider {
@Value("${spring.jmx.url}")
private String url;
@Bean
public ConnectorServerFactoryBean connectorServerFactoryBean() throws Exception {
final ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setServiceUrl(url);
return connectorServerFactoryBean;
}
}
- Build and deploy your docker on Kubernetes and find out the IP address of the pod. You may use
kubectl describe pod
for that on CLI - Now to start VisualVM, we also need to add the JMXMP jar downloaded above in classpath. I created an alias to do the same, and since the JAR was downloaded in my local .m2 directory the command looked like this:-
alias viz='jvisualvm -cp "$JAVA_HOME:~/.m2/repository/org/glassfish/main/external/jmxremote_optional-repackaged/5.0/jmxremote_optional-repackaged-5.0.jar"'
- Now, execute "viz" or your alias, it'll start the Visual VM application shipped with your Java.
- Click on the +JMX icon in the toolbar of VisualVM or go to (File -> Add JMX Connection...) add the link
service:jmx:jmxmp://<IP address obtained in step 6 above>:8001
and Check "Do not require SSL connection". Once you hit OK, you should see your remote application internals on VisualVM in a while. Screenshot attached below.

rohimsh
- 211
- 1
- 9
-
Great, this is the only solution I have been able to find anywhere to get this working. Thanks a lots! – Adriaan Jan 08 '22 at 16:41
-
@Adriaan checkout that one https://stackoverflow.com/a/75806163/2852528, it's for AWS ECS though, but sure could be adopted for Kubernetes as well – Serhii Povísenko Mar 21 '23 at 21:00