When you run Java applications on Container Service for Kubernetes (ACK), you need visibility into heap memory, garbage collection (GC), threads, and class loading to diagnose performance issues. Managed Service for Prometheus collects these JVM metrics from your applications and makes them available in Grafana dashboards with alerting support.
The following procedure covers instrumenting a Spring Boot application with the Prometheus client library, deploying it to ACK, configuring Prometheus to scrape the metrics, and viewing the results in Grafana.
How it works
The monitoring pipeline has four stages:
Instrument -- Add the Prometheus client library to your JVM application so it exposes metrics on an HTTP endpoint.
Deploy -- Build a container image, push it to Container Registry, and deploy the application to an ACK cluster.
Scrape -- Configure a ServiceMonitor in Managed Service for Prometheus to discover and scrape the metrics endpoint automatically.
Visualize -- View the collected JVM metrics in a Managed Service for Grafana dashboard and create alert rules.

JVM metrics collected
The simpleclient_hotspot library exposes standard JVM metrics in the following categories:
| Category | Example metrics | Description |
|---|---|---|
| Memory | jvm_memory_bytes_used, jvm_memory_bytes_committed, jvm_memory_bytes_max | Heap and non-heap memory usage in bytes |
| Garbage collection | jvm_gc_collection_seconds_count, jvm_gc_collection_seconds_sum | GC invocation count and cumulative time per collector |
| Threads | jvm_threads_current, jvm_threads_daemon, jvm_threads_peak | Active, daemon, and peak thread counts |
| Classes | jvm_classes_loaded, jvm_classes_loaded_total, jvm_classes_unloaded_total | Currently loaded and historically loaded/unloaded class counts |
Prerequisites
Before you begin, make sure that you have:
An ACK cluster is monitored by Managed Service for Prometheus. For more information, see Monitor an ACK cluster
An image repository in Container Registry. For more information, see Step 2: Create an image repository
Sample project
A complete sample project is available on GitHub. The file paths referenced below correspond to that repository.
Step 1: Instrument the JVM application
Add the Prometheus client library to your Spring Boot application so it exposes JVM metrics on a dedicated HTTP endpoint.
Add the
simpleclient_hotspotdependency topom.xml.<dependency> <groupId>io.prometheus</groupId> <artifactId>simpleclient_hotspot</artifactId> <version>0.6.0</version> </dependency>Register the default JVM metrics collectors by adding the following method to your controller class.
DefaultExports.initialize()registers collectors for memory pools, GC, threads, and class loading. The@PostConstructannotation runs this method once at application startup. See/src/main/java/com/monitise/prometheus_demo/DemoController.javain the sample project.@PostConstruct public void initJvmExporter() { io.prometheus.client.hotspot.DefaultExports.initialize(); }Configure the metrics port and path in
application.properties. Port8081serves metrics separately from the application port (8080). The path/prometheus-metricsis where Prometheus sends scrape requests. See/src/main/resources/application.propertiesin the sample project.management.port: 8081 endpoints.prometheus.path: prometheus-metricsEnable the Prometheus endpoint in the main application class.
@EnablePrometheusEndpointexposes the/prometheus-metricsendpoint.@EnableSpringBootMetricsCollectorexports Spring Boot actuator metrics in Prometheus format. See/src/main/java/com/monitise/prometheus_demo/PrometheusDemoApplication.javain the sample project.@SpringBootApplication // sets up the prometheus endpoint /prometheus-metrics @EnablePrometheusEndpoint // exports the data at /metrics at a prometheus endpoint @EnableSpringBootMetricsCollector public class PrometheusDemoApplication { public static void main(String[] args) { SpringApplication.run(PrometheusDemoApplication.class, args); } }
Step 2: Build and push the container image
Package the instrumented application as a Docker image and push it to Container Registry.
Compile the project.
mvn clean install -DskipTestsBuild the Docker image. Example:
docker build -t <image-name>:<tag> . --no-cachedocker build -t promethues-demo:v0 . --no-cacheTag the image for Container Registry. Example:
sudo docker tag <image-name>:<tag> <registry-domain>/<namespace>/<image-name>:<tag>sudo docker tag promethues-demo:v0 registry.cn-hangzhou.aliyuncs.com/testnamespace/promethues-demo:v0Push the image to Container Registry. Example:
sudo docker push <registry-domain>/<namespace>/<image-name>:<tag>sudo docker push registry.cn-hangzhou.aliyuncs.com/testnamespace/promethues-demo:v0Verify the upload. Open the Container Registry console, navigate to your repository, and confirm the image appears on the Tags page.

Replace the placeholders with your values:
| Placeholder | Description | Example |
|---|---|---|
<image-name> | Docker image name | promethues-demo |
<tag> | Image version tag | v0 |
<registry-domain> | Container Registry endpoint | registry.cn-hangzhou.aliyuncs.com |
<namespace> | Container Registry namespace | testnamespace |
Step 3: Deploy to the ACK cluster
Deploy the JVM application to your ACK cluster and expose it as a Kubernetes Service.
Create the Deployment
Log on to the ACK console. In the left-side navigation pane, click Clusters.
On the Clusters page, find your cluster and click its name. In the left-side pane, choose Workloads > Deployments.
On the Deployments page, click Create from YAML in the upper-right corner and enter the following YAML: The three
prometheus.io/*annotations tell Managed Service for Prometheus how to discover and scrape this application: The Deployment runs two replicas. Each pod exposes port8080for application traffic and port8081for the Prometheus metrics endpoint. Example with concrete values: After you create the Deployment, the pods appear on the Deployments page.Annotation Purpose prometheus.io/scrape: 'true'Marks the pod as a scrape target prometheus.io/path: '/prometheus-metrics'HTTP path where metrics are exposed prometheus.io/port: '8081'Port to scrape (the management port from Step 1) apiVersion: apps/v1 # for versions before 1.8.0 use apps/v1beta1 kind: Deployment metadata: name: prometheus-demo spec: replicas: 2 template: metadata: annotations: prometheus.io/scrape: 'true' prometheus.io/path: '/prometheus-metrics' prometheus.io/port: '8081' labels: app: tomcat spec: containers: - name: tomcat imagePullPolicy: Always image: <registry-domain>/<namespace>/<image-name>:<tag> ports: - containerPort: 8080 name: tomcat-normal - containerPort: 8081 name: tomcat-monitorapiVersion: apps/v1 # for versions before 1.8.0 use apps/v1beta1 kind: Deployment metadata: name: prometheus-demo labels: app: tomcat spec: replicas: 2 selector: matchLabels: app: tomcat template: metadata: annotations: prometheus.io/scrape: 'true' prometheus.io/path: '/prometheus-metrics' prometheus.io/port: '8081' labels: app: tomcat spec: containers: - name: tomcat imagePullPolicy: Always image: registry.cn-hangzhou.aliyuncs.com/peiyu-test/prometheus-demo:v0 ports: - containerPort: 8080 name: tomcat-normal - containerPort: 8081 name: tomcat-monitor
Create the Service
In the left-side navigation pane, choose Network > Services.
On the Services page, click Create Resources in YAML.
On the Create page, enter the following YAML in the Template code editor and click Create: This NodePort Service exposes both the application port (
8080) and the metrics port (8081), making the metrics endpoint reachable by Managed Service for Prometheus. After you create the Service, it appears on the Services page.apiVersion: v1 kind: Service metadata: labels: app: tomcat name: tomcat namespace: default spec: ports: - name: tomcat-normal port: 8080 protocol: TCP targetPort: 8080 - name: tomcat-monitor port: 8081 protocol: TCP targetPort: 8081 type: NodePort selector: app: tomcat
Step 4: Configure service discovery
Configure a ServiceMonitor in Managed Service for Prometheus to automatically discover and scrape the JVM metrics endpoint. For detailed instructions, see Use ServiceMonitors to discover and monitor Services.
Verify the setup
After you complete all four steps, confirm that JVM metrics flow into Prometheus:
Open the Managed Service for Prometheus console and navigate to your ACK cluster.
On the Targets page, verify that your application pods appear as active scrape targets with a status of UP.
Open a Grafana dashboard and run a query such as
jvm_memory_bytes_usedto confirm data is flowing.
Troubleshooting
If metrics do not appear, check the following:
| Symptom | Possible cause | Resolution |
|---|---|---|
| Targets not listed | Pod annotations missing or incorrect | Verify that prometheus.io/scrape, prometheus.io/path, and prometheus.io/port in the Deployment YAML match the port and path configured in application.properties. |
| Target status is DOWN | Metrics endpoint unreachable | Make sure port 8081 is not blocked by network policies in the cluster. Confirm the application started and the endpoint returns data by running curl http://<pod-ip>:8081/prometheus-metrics from within the cluster. |
| Metrics exist but dashboard is empty | Grafana data source misconfigured | Verify that the Grafana data source points to the correct Managed Service for Prometheus instance and that the query uses the correct metric name (for example, jvm_memory_bytes_used). |
What to do next
Set up a Grafana dashboard -- Community dashboard templates such as JVM (Micrometer) or JVM (Prometheus) provide a ready-made starting point for visualizing JVM metrics.
Create alert rules -- Configure alerts for heap memory usage, long GC pauses, or thread count spikes. For more information, see the alert configuration documentation for Managed Service for Prometheus.