Monitor custom kubernetes pod metrics using Prometheus
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Prometheus scrapes metrics from HTTP endpoints exposed by your application pods. To monitor custom metrics, your application must expose a /metrics endpoint in Prometheus text format, and Prometheus must be configured to discover and scrape that endpoint. The typical setup involves adding a metrics library to your application, annotating pods for auto-discovery, and configuring ServiceMonitor or Prometheus scrape annotations.
Step 1: Instrument Your Application
Add a Prometheus client library to expose custom metrics over HTTP.
Python (Flask)
Go
Step 2: Expose the Metrics Port in Kubernetes
The prometheus.io/* annotations tell Prometheus to auto-discover and scrape this pod.
Step 3: Configure Prometheus to Scrape Pods
Option A: Annotations-Based Discovery (prometheus.yml)
Option B: ServiceMonitor (Prometheus Operator)
If you use the Prometheus Operator (kube-prometheus-stack), create a ServiceMonitor:
Step 4: Install Prometheus with Helm
Step 5: Query Custom Metrics
Access the Prometheus UI and query your custom metrics:
Step 6: Create Grafana Dashboards and Alerts
Common Pitfalls
- Missing
prometheus.io/scrape: "true"annotation: Without this annotation, Prometheus with annotation-based discovery will not scrape the pod. This is the most common reason custom metrics do not appear in Prometheus. - ServiceMonitor label mismatch: The
ServiceMonitor's labels must match the Prometheus operator'sserviceMonitorSelector. If the operator is configured to selectrelease: prometheus, your ServiceMonitor must have that label. Check withkubectl get prometheus -o yaml. - Metrics endpoint returning wrong format: Prometheus expects the OpenMetrics/Prometheus text format. Returning JSON or other formats causes scrape failures. Use the official client libraries which handle formatting automatically.
- High cardinality labels: Adding labels with many unique values (user IDs, request IDs, timestamps) creates millions of time series and can crash Prometheus. Keep label cardinality low — use buckets for histograms and aggregate at query time.
- Scrape interval too aggressive: Scraping every 1-2 seconds generates massive amounts of data. The default 15-30 second interval is appropriate for most applications. Only decrease for truly real-time requirements.
Summary
- Instrument your application with a Prometheus client library to expose a
/metricsendpoint - Add
prometheus.io/scrape,prometheus.io/port, andprometheus.io/pathannotations to pod templates - Use
ServiceMonitorwith the Prometheus Operator for declarative scrape configuration - Install kube-prometheus-stack via Helm for a complete monitoring setup (Prometheus + Grafana + AlertManager)
- Query custom metrics with PromQL:
rate(),histogram_quantile(), and aggregation functions - Keep label cardinality low to avoid Prometheus performance issues
Related reading
- Monitoring HTTP Traffic in Kubernetes
- Mount add files to existing directory using configmap volume mount
- Mount local directory into pod in minikube
- Mounting kubernetes volume with User permission
- Monitoring a synchronous method for timeout
- Monitoring pending async operations in Node.js promised environment
- Mounting NFS Persistent Volumes with authentication
- MountVolume.SetUp failed for volume kube-api-access-cvwdt object default/kube-root-ca.crt not registered

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.