Observability: Prometheus, Grafana & AlertManager
Kubernetes observability is built from three tools: Prometheus collects metrics via pull-based scraping. Grafana reads from Prometheus to build dashboards. AlertManager receives alerts from Prometheus
Kubernetes observability is built from three tools: Prometheus collects metrics via pull-based scraping. Grafana reads from Prometheus to build dashboards. AlertManager receives alerts from Prometheus and routes them to notification channels.
-
Prometheus uses a pull (scrape) model -- it fetches metrics from HTTP /metrics endpoints on configured targets.
-
ServiceMonitor and PodMonitor CRDs (Prometheus Operator) enable dynamic target discovery by label selector.
-
Recording rules pre-compute expensive aggregations as new time-series for efficient reuse.
-
Alerting rules fire when PromQL expressions return results for a configured duration (for:) -- AlertManager handles routing.
-
AlertManager handles deduplication, grouping, inhibition, silencing, and routing to receivers.
-
Instrument or choose applications that expose metrics on an HTTP /metrics endpoint in Prometheus's text exposition format (many common libraries/exporters do this out of the box).
-
Deploy Prometheus (commonly via the Prometheus Operator) and define ServiceMonitor/PodMonitor CRDs with label selectors so Prometheus dynamically discovers new scrape targets as Pods/Services matching those labels appear.
-
Prometheus scrapes each target on its configured interval and stores the resulting time series in its local TSDB.
-
Write PromQL recording rules for any expensive, frequently-reused aggregation, so it's pre-computed rather than recalculated on every query/dashboard load.
-
Connect Grafana as a data source pointed at Prometheus, and build dashboards querying those metrics (raw or recording-rule-derived).
-
Write alerting rules in Prometheus (PromQL expression + for: duration) that fire into AlertManager, which handles deduplication, grouping, and routing to actual notification channels (Slack, PagerDuty, email).
-
Tracking Deployment rollout health via Prometheus metrics on Pod restart counts and readiness status, visualized on a Grafana dashboard the on-call team watches during a release.
-
An AlertManager rule paging on-call when error rate exceeds a threshold for 5 minutes, with routing that escalates to a secondary responder if unacknowledged.
-
Using ServiceMonitor CRDs so a newly-deployed microservice is automatically scraped the moment it's labeled correctly, with zero manual Prometheus config changes.
-
A capacity-planning dashboard built from recording rules aggregating per-node CPU/memory usage trends over weeks, too expensive to compute live on every dashboard load.
-
AlertManager's inhibition rules suppressing a flood of 'Pod not Ready' alerts during a known, deliberate node-drain maintenance window.
-
Expose metrics with meaningful labels (not high-cardinality ones like raw user IDs) -- cardinality explosions are the most common way Prometheus deployments run into memory/performance trouble.
-
Use ServiceMonitor/PodMonitor CRDs instead of hand-editing Prometheus's static scrape config -- keeps target discovery declarative and versioned like everything else.
-
Pre-compute expensive, frequently-dashboarded aggregations as recording rules rather than running the raw heavy PromQL query on every dashboard refresh.
-
Set alerting rule for: durations deliberately (not zero) to avoid paging on transient blips that self-resolve within seconds.
-
Use AlertManager's grouping and inhibition rules to prevent alert storms -- a single root-cause event shouldn't generate one page per affected Pod.
-
Set retention and storage sizing for Prometheus's TSDB based on real query/dashboard needs -- very long local retention on high-cardinality metrics can balloon disk usage fast.
-
Exposing metrics with unbounded-cardinality labels (user ID, request ID, raw URL path) -- this is the single most common cause of a Prometheus instance running out of memory.
-
Writing alerting rules with no for: duration, causing pages on momentary blips that resolve before anyone could plausibly act on them.
-
Treating Grafana as the source of truth instead of Prometheus -- Grafana only visualizes; if the underlying PromQL query or recording rule is wrong, the dashboard confidently shows wrong numbers.
-
Not setting up AlertManager routing/grouping at all, leading to alert fatigue that trains on-call engineers to ignore pages.
-
Forgetting that Prometheus's pull model means a target that's down looks identical to 'no alert configured' unless you specifically alert on scrape failures (
up == 0). -
Running a single, unreplicated Prometheus instance for production monitoring -- it's a single point of failure for the very system meant to tell you when something's failing.
-
High-cardinality labels are the dominant performance/memory cost driver in Prometheus -- audit label cardinality before it becomes an incident.
-
Recording rules trade write-time compute for read-time speed -- use them for any query hit frequently on dashboards or by alerting rules, not for one-off ad hoc queries.
-
Tune scrape_interval per target based on actual need -- scraping everything at a very tight interval multiplies storage and CPU cost without proportional observability benefit for slow-changing metrics.
-
For long-term retention beyond what local Prometheus storage should hold, use remote-write to a long-term store (e.g. Thanos, Mimir, Cortex) rather than growing local TSDB retention indefinitely.
-
Run Prometheus with adequate persistent storage and consider a long-term-storage/HA solution (Thanos, Mimir, or similar) for production, rather than a single ephemeral instance.
-
Define alerting rules around genuine user-impacting symptoms (error rate, latency, saturation) rather than only low-level causes -- pages that map directly to user impact are more actionable.
-
Route AlertManager alerts by real severity and team ownership, with escalation policies for unacknowledged critical alerts, not a single flat notification channel.
-
Regularly review and prune both dashboards and alerting rules -- stale, noisy, or duplicate alerts erode trust in the monitoring stack faster than missing coverage does.
-
Deploy the Prometheus Operator, a sample app exposing /metrics, and a ServiceMonitor selecting it -- confirm it appears as a scrape target in the Prometheus UI.
-
Write a recording rule aggregating a raw metric, and confirm it's queryable as its own new metric name.
-
Connect Grafana to Prometheus as a data source and build a simple dashboard panel from a PromQL query.
-
Write an alerting rule with a for: 1m duration on a test condition you can trigger manually, and confirm it reaches AlertManager and fires a notification.
-
Prometheus uses pull-based scraping -- metrics fetched from /metrics endpoints.
-
ServiceMonitors and PodMonitors enable dynamic scrape target discovery via label selectors.
-
Recording rules pre-compute expensive aggregations; alerting rules fire when conditions persist for 'for:' duration.
-
AlertManager handles deduplication, grouping, inhibition, silencing, and routing.
-
High label cardinality is the primary scalability risk for Prometheus.
Want a visual for this concept?
Generate a diagram tailored to “Observability: Prometheus, Grafana & AlertManager” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →