Create service discovery with a ServiceMonitor
Managed Service for Prometheus supports service discovery through the ServiceMonitor CRD. A ServiceMonitor defines the namespace scope for pod discovery and selects target Services using matchLabel. This walkthrough uses a Spring Boot application as an example.
Demo
Download the demo project for a complete ServiceMonitor-based service discovery example.
Step 1: Add dependencies
-
Create a Maven application and add the following dependencies to the pom.xml file.
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> -
Add the following configuration to the src/resources/applications.properties file in the project.
management.endpoints.web.exposure.include=prometheus -
Start the project and access
http://{host}:{port}/actuator/prometheusin a browser.JVM monitoring data is displayed. The following is sample output in Prometheus exposition format.
# HELP jvm_threads_daemon_threads The current number of live daemon threads # TYPE jvm_threads_daemon_threads gauge jvm_threads_daemon_threads 23.0 # HELP tomcat_sessions_rejected_sessions_total # TYPE tomcat_sessions_rejected_sessions_total counter tomcat_sessions_rejected_sessions_total 0.0 # HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use # TYPE jvm_memory_committed_bytes gauge jvm_memory_committed_bytes{area="heap",id="PSSurvivorSpace",} 1.31072E7 jvm_memory_committed_bytes{area="heap",id="PSOldGen",} 1.30023424E8 jvm_memory_committed_bytes{area="heap",id="PSEdenSpace",} 1.56762112E8 jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 3.670016E7 jvm_memory_committed_bytes{area="nonheap",id="CodeCache",} 7143424.0 jvm_memory_committed_bytes{area="nonheap",id="CompressedClassSpace",} 5242880.0 # HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine # TYPE jvm_classes_loaded_classes gauge jvm_classes_loaded_classes 6877.0 # HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset # TYPE jvm_threads_peak_threads gauge jvm_threads_peak_threads 28.0 # HELP system_cpu_count The number of processors available to the Java virtual machine # TYPE system_cpu_count gauge system_cpu_count 12.0 # HELP tomcat_sessions_expired_sessions_total # TYPE tomcat_sessions_expired_sessions_total counter tomcat_sessions_expired_sessions_total 0.0 # HELP process_files_max_files The maximum file descriptor count # TYPE process_files_max_files gauge process_files_max_files 10240.0 # HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool # TYPE jvm_buffer_total_capacity_bytes gauge jvm_buffer_total_capacity_bytes{id="direct",} 8192.0 jvm_buffer_total_capacity_bytes{id="mapped",} 0.0 # HELP jvm_threads_states_threads The current number of threads having NEW state # TYPE jvm_threads_states_threads gauge jvm_threads_states_threads{state="runnable",} 9.0 jvm_threads_states_threads{state="blocked",} 0.0 jvm_threads_states_threads{state="waiting",} 12.0 jvm_threads_states_threads{state="timed-waiting",} 6.0 jvm_threads_states_threads{state="new",} 0.0 jvm_threads_states_threads{state="terminated",} 0.0 # HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool # TYPE jvm_buffer_count_buffers gauge jvm_buffer_count_buffers{id="direct",} 1.0 jvm_buffer_count_buffers{id="mapped",} 0.0 # HELP process_files_open_files The open file descriptor count # TYPE process_files_open_files gauge process_files_open_files 93.0 # HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC # TYPE jvm_gc_memory_promoted_bytes_total counter jvm_gc_memory_promoted_bytes_total 5225384.0 # HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management # TYPE jvm_memory_max_bytes gauge jvm_memory_max_bytes{area="heap",id="PSSurvivorSpace",} 1.31072E7 jvm_memory_max_bytes{area="heap",id="PSOldGen",} 2.863661056E9 jvm_memory_max_bytes{area="heap",id="PSEdenSpace",} 1.40509184E9 jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0 jvm_memory_max_bytes{area="nonheap",id="CodeCache",} 2.5165824E8 jvm_memory_max_bytes{area="nonheap",id="CompressedClassSpace",} 1.073741824E9 # HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next # TYPE jvm_gc_memory_allocated_bytes_total counter jvm_gc_memory_allocated_bytes_total 1.14749824E8 # HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution # TYPE jvm_classes_unloaded_classes_total counter jvm_classes_unloaded_classes_total 10.0 # HELP tomcat_sessions_created_sessions_total # TYPE tomcat_sessions_created_sessions_total counter
Step 2: Deploy a Kubernetes cluster
-
Build an image and upload the image to an image repository. For more information, see Connect to a source code platform.
-
Create a deployment using the following YAML configuration.
apiVersion: apps/v1 kind: Deployment metadata: name: micrometer-prometheus namespace: default labels: app: demo-prometheus spec: replicas: 3 selector: matchLabels: app: demo-prometheus template: metadata: labels: app: demo-prometheus spec: containers: - name: micrometer-prometheus image: manjusakalza/micrometer-prometheus:latest ports: - containerPort: 8080 -
Create a Service using the following YAML configuration.
apiVersion: v1 kind: Service metadata: name: prometheus-metrics-demo namespace: default labels: micrometer-prometheus-discovery: 'true' spec: selector: app: demo-prometheus ports: - protocol: TCP port: 8080 targetPort: 8080 name: metrics
Step 3: Create a ServiceMonitor
-
Save the YAML file to your computer and run
kubectl apply -f {path/to/the/YAML/file}to apply the file.
Sample ServiceMonitor YAML:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: micrometer-demo
namespace: default
spec:
endpoints:
- interval: 15s
path: /actuator/prometheus
port: metrics # Note: Configure the port name, not the port number.
namespaceSelector:
any: true
selector:
matchLabels:
micrometer-prometheus-discovery: 'true'
YAML field descriptions:
-
The
metadatafieldsnameandnamespaceidentify the ServiceMonitor. -
The
specfieldendpointsdefines the scrape targets. Eachendpointin theendpointsarray (endpointssupports multiple entries) contains these fields:-
interval: Scrape interval for thisendpoint. Example:15s. -
path: Metrics scrape path. Example:/actuator/prometheus. -
port: Service port name (must match thenamedefined in your Service from Step 2). Example:metrics.ImportantConfigure the port name, not the port number.
-
-
The
specfieldnamespaceSelectorsets the Service discovery scope.namespaceSelectorsupports two mutually exclusive fields:-
any: Set totrueto monitor all matching Services across all namespaces. -
matchNames: Limits monitoring to specificnamespaces. For example, to monitor only the default and arms-prom namespaces, setmatchNamesas follows:namespaceSelector: matchNames: - default - arms-prom
-
-
The
specfieldselectorfilters Services by label.The example Service has the label micrometer-prometheus-discovery: 'true', so configure
selectoras follows:selector: matchLabels: micrometer-prometheus-discovery: 'true'
To enable basic auth, use the following YAML:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: cloud-open-api-monitor # Set a unique name for the ServiceMonitor.
namespace: default # Set the namespace where the ServiceMonitor resides.
spec:
endpoints:
- interval: 30s
# Specify the interval at which Prometheus scrapes the current endpoint.
port: tcp-8080
# Enter the path exposed in the Prometheus exporter code.
path: /api/actuator/prometheus
basicAuth:
password:
name: basic-auth
key: <password>
username:
name: basic-auth
key: <userName>
scheme: http
namespaceSelector:
any: true
selector:
matchLabels:
# Match Services with the following label.
edas.oam.acname: cloud-open-api
If you lack permissions for basic auth, create a ClusterRole with the required permissions and bind it to the ServiceAccount arms-prom-operator in the arms-prom namespace by using a ClusterRoleBinding.
-
ClusterRole YAML file
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus-agent-role labels: app: prometheus-agent rules: - apiGroups: [""] resources: ["pods", "services", "endpoints", "nodes"] verbs: ["get", "list", "watch"] # Adjust as needed. - apiGroups: ["monitoring.coreos.com"] # Adjust the apiGroups as needed. resources: ["*"] verbs: ["get", "list", "watch", "create", "update", "delete"] # Adjust as needed. -
ClusterRoleBinding YAML file
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: prometheus-agent-binding subjects: - kind: ServiceAccount name: arms-prom-operator # Service account name namespace: arms-prom # The namespace where the service account resides. roleRef: kind: ClusterRole name: prometheus-agent-role # The name of the ClusterRole defined above. apiGroup: rbac.authorization.k8s.io
Step 4: Verify the ServiceMonitor
Verify that Prometheus discovers your service:
Log on to the Managed Service for Prometheus console. In the left-side navigation pane, click Integration Management.
-
On the Integrated Environments tab, click the name of the target container environment in the Container Service list.
-
Click the Self-Monitoring tab.
On the Targets tab, check whether a target named {namespace}/{serviceMonitorName}/x exists.
The page displays the target group default/micrometer-demo/0 (3/3 up), indicating that the ServiceMonitor has been correctly identified by Prometheus. All targets show a green UP state, which confirms that the configuration is valid.
-
Expand the {namespace}/{serviceMonitorName}/x target row and click the endpoint link.
Verify that metrics display correctly. The page displays JVM and Tomcat runtime metrics in Prometheus exposition format, confirming that the ServiceMonitor is correctly configured.
# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool # TYPE jvm_buffer_total_capacity_bytes gauge jvm_buffer_total_capacity_bytes{id="mapped",} 0.0 jvm_buffer_total_capacity_bytes{id="direct",} 81968.0 # HELP jvm_threads_daemon_threads The current number of live daemon threads # TYPE jvm_threads_daemon_threads gauge jvm_threads_daemon_threads 29.0 # HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use # TYPE jvm_memory_committed_bytes gauge jvm_memory_committed_bytes{area="nonheap",id="miscellaneousnon-heapstorage",} 2.3068672E7 jvm_memory_committed_bytes{area="nonheap",id="classstorage",} 2.8471712E7 jvm_memory_committed_bytes{area="nonheap",id="JITcodecache",} 2.68435456E8 jvm_memory_committed_bytes{area="heap",id="tenured-LOA",} 671744.0 jvm_memory_committed_bytes{area="nonheap",id="JITdatacache",} 2097152.0 jvm_memory_committed_bytes{area="heap",id="nursery-survivor",} 1638400.0 jvm_memory_committed_bytes{area="heap",id="nursery-allocate",} 6881280.0 jvm_memory_committed_bytes{area="heap",id="tenured-SOA",} 1.2763136E7 # HELP process_start_time_seconds Start time of the process since the unix epoch. # TYPE process_start_time_seconds gauge process_start_time_seconds 1.622297808811E9 # HELP tomcat_sessions_expired_sessions_total # TYPE tomcat_sessions_expired_sessions_total counter tomcat_sessions_expired_sessions_total 0.0 # HELP jvm_threads_states_threads The current number of threads having NEW state # TYPE jvm_threads_states_threads gauge jvm_threads_states_threads{state="runnable",} 20.0 jvm_threads_states_threads{state="blocked",} 0.0 jvm_threads_states_threads{state="waiting",} 10.0 jvm_threads_states_threads{state="timed-waiting",} 3.0 jvm_threads_states_threads{state="new",} 0.0 jvm_threads_states_threads{state="terminated",} 0.0 # HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution # TYPE jvm_classes_unloaded_classes_total counter jvm_classes_unloaded_classes_total 0.0 # HELP tomcat_sessions_rejected_sessions_total # TYPE tomcat_sessions_rejected_sessions_total counter tomcat_sessions_rejected_sessions_total 0.0 # HELP tomcat_sessions_created_sessions_total # TYPE tomcat_sessions_created_sessions_total counter tomcat_sessions_created_sessions_total 0.0 # HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads # TYPE jvm_threads_live_threads gauge jvm_threads_live_threads 33.0 # HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management # TYPE jvm_memory_max_bytes gauge