Exposing JVM Monitoring Metrics Using JMX Exporter¶
JMX Exporter provides two usage methods:
- Standalone Process: Specify parameters when starting the JVM to expose a JMX RMI interface. The JMX Exporter calls RMI to obtain the JVM runtime state data, converts it into Prometheus metrics format, and exposes a port for Prometheus to scrape.
- In-Process (JVM process): Specify parameters when starting the JVM to run the JMX Exporter jar file as a javaagent. This method reads the JVM runtime state data in-process, converts it into Prometheus metrics format, and exposes a port for Prometheus to scrape.
Note
The official recommendation is not to use the first method due to its complex configuration and the requirement for a separate process, which introduces additional monitoring challenges. Therefore, this article focuses on the second method, detailing how to use JMX Exporter to expose JVM monitoring metrics in a Kubernetes environment.
In this method, you need to specify the JMX Exporter jar file and configuration file when starting the JVM. Since the jar file is a binary file that is not ideal for mounting via a configmap, and the configuration file typically does not require modifications, it is recommended to package both the JMX Exporter jar file and the configuration file directly into the business container image.
For the second method, you can choose to include the JMX Exporter jar file in the application image or mount it during deployment. Below are explanations for both approaches:
Method 1: Building JMX Exporter JAR File into the Business Image¶
The content of prometheus-jmx-config.yaml
is as follows:
...
ssl: false
lowercaseOutputName: false
lowercaseOutputLabelNames: false
rules:
- pattern: ".*"
Note
For more configuration options, please refer to the introduction at the bottom or Prometheus official documentation.
Next, prepare the jar file. You can find the latest jar download link on the jmx_exporter GitHub page and refer to the following Dockerfile:
FROM openjdk:11.0.15-jre
WORKDIR /app/
COPY target/my-app.jar ./
COPY prometheus-jmx-config.yaml ./
RUN set -ex; \
curl -L -O https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.17.2/jmx_prometheus_javaagent-0.17.2.jar;
ENV JAVA_TOOL_OPTIONS=-javaagent:/app/jmx_prometheus_javaagent-0.17.2.jar=8088:/app/prometheus-jmx-config.yaml
EXPOSE 8081 8999 8080 8888
ENTRYPOINT java $JAVA_OPTS -jar my-app.jar
Note:
- The format for the startup parameter is:
-javaagent:=:
- Here, port 8088 is used to expose JVM monitoring metrics; you may change it if it conflicts with the Java application.
Method 2: Mounting via Init Container¶
First, we need to create a Docker image for the JMX Exporter. The following Dockerfile is for reference:
FROM alpine/curl:3.14
WORKDIR /app/
# Copy the previously created config file into the image
COPY prometheus-jmx-config.yaml ./
# Download the jmx prometheus javaagent jar online
RUN set -ex; \
curl -L -O https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.17.2/jmx_prometheus_javaagent-0.17.2.jar;
Build the image using the above Dockerfile: docker build -t my-jmx-exporter .
Add the following init container to the Java application deployment YAML:
Click to expand YAML file
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-demo-app
labels:
app: my-demo-app
spec:
selector:
matchLabels:
app: my-demo-app
template:
metadata:
labels:
app: my-demo-app
spec:
imagePullSecrets:
- name: registry-pull
initContainers:
- name: jmx-sidecar
image: my-jmx-exporter
command: ["cp", "-r", "/app/jmx_prometheus_javaagent-0.17.2.jar", "/target/jmx_prometheus_javaagent-0.17.2.jar"] ➊
volumeMounts:
- name: sidecar
mountPath: /target
containers:
- image: my-demo-app-image
name: my-demo-app
resources:
requests:
memory: "1000Mi"
cpu: "500m"
limits:
memory: "1000Mi"
cpu: "500m"
ports:
- containerPort: 18083
env:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/app/jmx_prometheus_javaagent-0.17.2.jar=8088:/app/prometheus-jmx-config.yaml" ➋
volumeMounts:
- name: host-time
mountPath: /etc/localtime
readOnly: true
- name: sidecar
mountPath: /sidecar
volumes:
- name: host-time
hostPath:
path: /etc/localtime
- name: sidecar # Shared agent folder
emptyDir: {}
restartPolicy: Always
With the above modifications, the example application my-demo-app
now has the capability to expose JVM metrics. After running the service, you can access the Prometheus formatted metrics at http://localhost:8088
.
Next, you can refer to Connecting Existing JVM Metrics of Java Applications to Observability.