Skip to main content

Prometheus Metrics

Prometheus is used to collect metrics from EKS clusters and microservices, and Alertmanager is used to send alerts.

Architecture

Prometheus Stack Configuration

Helm Values

prometheus:
prometheusSpec:
retention: 15d # 15-day retention
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
resources:
requests:
storage: 50Gi
serviceMonitorSelectorNilUsesHelmValues: false # Discover all ServiceMonitors
podMonitorSelectorNilUsesHelmValues: false
ruleSelectorNilUsesHelmValues: false
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
cpu: 2
memory: 4Gi

alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
storageClassName: gp3
resources:
requests:
storage: 10Gi

kubeStateMetrics:
enabled: true

nodeExporter:
enabled: true

prometheusOperator:
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 200m
memory: 512Mi

Service Discovery

Pod Annotation-based Discovery

apiVersion: v1
kind: Pod
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"

ServiceMonitor Example

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: order-service
namespace: core-services
labels:
app: order-service
spec:
selector:
matchLabels:
app: order-service
endpoints:
- port: http
interval: 30s
path: /metrics
namespaceSelector:
matchNames:
- core-services

Language-specific Metrics Setup

Go (Gin + Prometheus)

import (
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "endpoint", "status"},
)

httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: []float64{0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5},
},
[]string{"method", "endpoint"},
)

orderTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "orders_total",
Help: "Total number of orders",
},
[]string{"status", "region"},
)
)

func init() {
prometheus.MustRegister(httpRequestsTotal, httpRequestDuration, orderTotal)
}

func main() {
r := gin.New()

// Metrics middleware
r.Use(func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start).Seconds()

httpRequestsTotal.WithLabelValues(
c.Request.Method,
c.FullPath(),
strconv.Itoa(c.Writer.Status()),
).Inc()

httpRequestDuration.WithLabelValues(
c.Request.Method,
c.FullPath(),
).Observe(duration)
})

// Metrics endpoint
r.GET("/metrics", gin.WrapH(promhttp.Handler()))
}

Java (Spring Boot + Micrometer)

# application.yaml
management:
endpoints:
web:
exposure:
include: prometheus,health,info
endpoint:
prometheus:
enabled: true
metrics:
tags:
application: payment-service
region: ${AWS_REGION:unknown}
distribution:
percentiles-histogram:
http.server.requests: true
slo:
http.server.requests: 50ms,100ms,200ms,500ms,1s
// Custom metrics
@Component
public class PaymentMetrics {
private final Counter paymentSuccessCounter;
private final Counter paymentFailureCounter;
private final Timer paymentProcessingTime;

public PaymentMetrics(MeterRegistry registry) {
this.paymentSuccessCounter = Counter.builder("payments_total")
.tag("status", "success")
.description("Total successful payments")
.register(registry);

this.paymentFailureCounter = Counter.builder("payments_total")
.tag("status", "failure")
.description("Total failed payments")
.register(registry);

this.paymentProcessingTime = Timer.builder("payment_processing_seconds")
.description("Payment processing time")
.publishPercentiles(0.5, 0.9, 0.99)
.register(registry);
}

public void recordSuccess() {
paymentSuccessCounter.increment();
}

public void recordFailure() {
paymentFailureCounter.increment();
}

public void recordProcessingTime(Duration duration) {
paymentProcessingTime.record(duration);
}
}

Python (FastAPI + prometheus_fastapi_instrumentator)

from fastapi import FastAPI
from prometheus_fastapi_instrumentator import Instrumentator
from prometheus_client import Counter, Histogram, Gauge

app = FastAPI()

# Auto-instrumentation
Instrumentator().instrument(app).expose(app)

# Custom metrics
recommendation_requests = Counter(
"recommendation_requests_total",
"Total recommendation requests",
["user_tier", "category"]
)

recommendation_latency = Histogram(
"recommendation_latency_seconds",
"Recommendation generation latency",
buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0]
)

active_users = Gauge(
"active_users",
"Number of currently active users"
)

@app.get("/api/v1/recommendations/{user_id}")
async def get_recommendations(user_id: str):
with recommendation_latency.time():
recommendation_requests.labels(
user_tier="gold",
category="electronics"
).inc()
# Recommendation logic...
return {"recommendations": [...]}

Core Metrics (RED Method)

Core metrics that each service should collect:

MetricDescriptionPromQL
RateRequests per secondrate(http_requests_total[5m])
ErrorsError raterate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
DurationResponse timehistogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

Alert Rules (PrometheusRule)

Service Alerts

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: service-alerts
namespace: monitoring
spec:
groups:
- name: service.rules
rules:
# High error rate
- alert: HighErrorRate
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.service }}"
description: "{{ $labels.service }} 5XX error rate exceeds 5% (current: {{ $value | humanizePercentage }})"

# Slow response
- alert: HighLatency
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 2
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.service }} response delay"
description: "{{ $labels.service }} p99 response time exceeds 2 seconds"

# Pod restarts
- alert: PodRestartingTooOften
expr: |
increase(kube_pod_container_status_restarts_total[1h]) > 5
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.pod }} Pod frequent restarts"
description: "{{ $labels.namespace }}/{{ $labels.pod }} restarted more than 5 times in 1 hour"

Infrastructure Alerts

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: infrastructure-alerts
namespace: monitoring
spec:
groups:
- name: infrastructure.rules
rules:
# High node CPU
- alert: NodeHighCPU
expr: |
(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)) > 0.85
for: 10m
labels:
severity: warning
annotations:
summary: "High CPU on node {{ $labels.instance }}"
description: "CPU usage exceeds 85% (current: {{ $value | humanizePercentage }})"

# Node memory pressure
- alert: NodeMemoryPressure
expr: |
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.90
for: 5m
labels:
severity: critical
annotations:
summary: "Memory shortage on node {{ $labels.instance }}"
description: "Memory usage exceeds 90%"

# Low disk space
- alert: DiskSpaceLow
expr: |
(node_filesystem_avail_bytes{fstype!="tmpfs"} / node_filesystem_size_bytes) < 0.15
for: 15m
labels:
severity: warning
annotations:
summary: "Low disk space on node {{ $labels.instance }}"
description: "Free space on {{ $labels.mountpoint }} is below 15%"

Business Alerts

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: business-alerts
namespace: monitoring
spec:
groups:
- name: business.rules
rules:
# Order processing stopped
- alert: NoOrdersProcessed
expr: |
sum(increase(orders_total[10m])) == 0
for: 10m
labels:
severity: critical
annotations:
summary: "Order processing stopped"
description: "No orders processed in the last 10 minutes"

# High payment failure rate
- alert: HighPaymentFailureRate
expr: |
(
sum(rate(payments_total{status="failure"}[5m]))
/
sum(rate(payments_total[5m]))
) > 0.10
for: 5m
labels:
severity: critical
annotations:
summary: "High payment failure rate"
description: "Payment failure rate exceeds 10% (current: {{ $value | humanizePercentage }})"

Grafana Data Source Configuration

apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus-kube-prometheus-prometheus.monitoring:9090
isDefault: true
jsonData:
timeInterval: 15s
httpMethod: POST

- name: Alertmanager
type: alertmanager
access: proxy
url: http://prometheus-kube-prometheus-alertmanager.monitoring:9093
jsonData:
implementation: prometheus

Useful PromQL Queries

Service Status

# Requests per second by service
sum(rate(http_requests_total[5m])) by (service)

# Error rate by service
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/ sum(rate(http_requests_total[5m])) by (service)

# P99 response time by service
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
)

Resource Usage

# Pod CPU usage
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (pod, namespace)

# Pod memory usage (MB)
sum(container_memory_working_set_bytes{container!=""}) by (pod, namespace) / 1024 / 1024

# Total CPU requests by namespace
sum(kube_pod_container_resource_requests{resource="cpu"}) by (namespace)

Business Metrics

# Orders per minute
sum(rate(orders_total[1m])) * 60

# Payment success rate
sum(rate(payments_total{status="success"}[5m]))
/ sum(rate(payments_total[5m])) * 100

# Average order amount
sum(order_amount_sum) / sum(order_amount_count)

Troubleshooting

When Metrics Are Not Collected

# 1. Check ServiceMonitors
kubectl get servicemonitors -A

# 2. Check target status (Prometheus UI)
kubectl port-forward svc/prometheus-kube-prometheus-prometheus -n monitoring 9090:9090
# Access http://localhost:9090/targets

# 3. Verify Pod metrics endpoint
kubectl exec -it <pod-name> -- curl localhost:8080/metrics | head -50

Testing Alertmanager Notifications

# Send test alert
curl -X POST http://localhost:9093/api/v2/alerts \
-H "Content-Type: application/json" \
-d '[{
"labels": {
"alertname": "TestAlert",
"severity": "warning",
"service": "test-service"
},
"annotations": {
"summary": "This is a test alert",
"description": "This is a test alert"
}
}]'