Alerting with Alertmanager

Observability

Chapter 6 · Alerting with Alertmanager

cloud1-9 named alert fatigue as a real problem back in the Cloud Platforms course, without the tooling to actually fix it. This chapter is where that gets addressed directly — Prometheus's own alert rules, and Alertmanager, the separate component that decides who actually gets told, and how.

Two Separate Jobs — Prometheus Rules vs. Alertmanager

Prometheus itself evaluates alert rules — PromQL expressions that, when true, mark something as firing. That's a deliberately separate concern from Alertmanager, which receives fired alerts and decides who gets notified, through which channel, and on what schedule. Prometheus decides what is wrong; Alertmanager decides who hears about it and how.

Alert Rules — Defining "This Is a Problem"

groups: - name: example rules: - alert: HighErrorRate expr: sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05 for: 10m labels: severity: critical annotations: summary: "Error rate above 5% for {{ $labels.job }}"

expr reuses obs1-4's own error-rate query directly. labels attach values used for routingseverity: critical is what a routing rule matches against, not something a human reads. annotations are the reverse — human-readable context, with templating access to the alert's own labels and the value that triggered it, meant to be read by whoever gets paged.

The for: Duration and Alert States

for: 10m means the condition has to stay true continuously for ten minutes before the alert actually fires — a deliberate guard against a single brief blip triggering a page. An alert moves through real, named states: pending (the condition just became true, but for hasn't elapsed yet), firing (the full duration has passed, and it's now been sent to Alertmanager), and resolved (the condition is no longer true — Alertmanager can notify on this too, so a resolved incident doesn't require someone to manually confirm it's over).

Alertmanager — Routing, Grouping, and Silencing

  • Routing — a tree of label matchers deciding which receiver (Slack, email, PagerDuty, ...) a given alert goes to, based on its own labels.
  • Grouping — multiple alerts sharing similar labels get bundled into one notification, rather than flooding a channel with dozens of separate messages during one widespread incident — directly answering cloud1-9's own alert-fatigue warning.
  • Silencing — temporarily mutes alerts matching a given label set, for planned maintenance or a known ongoing issue, without touching the underlying rule itself.

A Routing Tree Example

route: receiver: 'default-slack' group_by: ['alertname', 'job'] group_wait: 30s group_interval: 5m repeat_interval: 4h routes: - match: severity: critical receiver: 'pagerduty' - match: severity: warning receiver: 'slack-warnings'

group_wait is how long Alertmanager waits after the first alert in a new group before sending the initial notification, giving related alerts a chance to arrive and be bundled together. group_interval controls how long to wait before sending an update about new alerts joining an already-notified group. repeat_interval is how long to wait before re-sending a notification for a group that's still firing, unresolved — these three timers together are what actually implement grouping's own noise reduction, not just a conceptual idea.

Avoiding Alert Fatigue — Directly Building On cloud1-9

cloud1-9 named the problem without the tooling; this chapter's routing, grouping, and the for duration together are the concrete fix. Route by real urgency — not everything to the same pager. Group related alerts so one incident produces one notification, not fifty. And before ever setting severity: critical, ask the honest question: if this fires at 3am, does someone genuinely need to get out of bed for it? An alert that doesn't clear that bar belongs at a lower severity, or shouldn't page a human at all.

SeverityTypical routingThe real question
criticalPages a human immediately (PagerDuty, phone)Does someone need to act right now, even at 3am?
warningA chat channel, seen during working hoursWorth knowing about soon, not worth waking anyone for
infoDashboard only, no active notificationUseful context if you're already looking, not urgent on its own
Every alert should point to a next action
An annotation linking to a runbook, or containing enough context to act on immediately, is what turns an alert into something actionable rather than just another notification to dismiss. An alert with no clear next step is itself a fatigue source, whatever its severity label says.
A for: duration that's too short trains people to ignore alerts
Firing on a single slow request or a brief network hiccup — anything that resolves itself before a human could realistically act — produces noise, not signal. Once people learn that a given alert "usually clears itself," they stop reacting to it at all, which defeats the entire purpose of alerting in the first place. A deliberately chosen for duration, long enough to filter out transient blips, is a real defense against exactly this.

Hands-On Exercises

Exercise 1

Write a Prometheus alert rule named "HighMemoryUsage" that fires when a gauge metric memory_usage_percent exceeds 90 for at least 15 minutes, with an annotation including the current value.

📄 View solution
Exercise 2

Explain, using this chapter's own group_by/group_wait/group_interval settings, what would happen if 30 instances of the same service all fired the same alert within a few seconds of each other, and why this matters for avoiding alert fatigue.

📄 View solution
Exercise 3

A team sets for: 30s on every single alert rule "to be safe." Explain what's likely to go wrong with this choice, and what a better default might look like for most rules.

📄 View solution

Chapter 6 Quick Reference

  • Prometheus evaluates alert rules (what's wrong); Alertmanager routes fired alerts (who's told, how)
  • for: duration — the condition must hold continuously before firing, filtering out transient blips
  • Alert states: pendingfiringresolved
  • labels drive routing; annotations give humans context, with $labels/$value templating
  • Routing sends by severity/team; grouping bundles related alerts into one notification; silencing mutes without disabling the rule
  • group_wait/group_interval/repeat_interval are the concrete timers implementing grouping's own noise reduction
  • Before marking anything critical, ask: does this genuinely need someone up at 3am? — the real answer to cloud1-9's own alert-fatigue warning