Managing and Routing Alert Notifications with Alertmanager in Kubernetes

Core Capabilities and Prometheus Integration

Alertmanager functions as the centralized notification engine for the Prometheus ecosystem. While Prometheus excels at metric collection and rule evaluation, Alertmanager specializes in processing, deduplicating, and routing the resulting alerts to appropriate channels. Its primary responsibilities include handling alert lifecycle events, managing notification pipelines, and reducing operational noise through intelligent filtering.

Alert Processing Mechanisms

Grouping

Grouping aggregates multiple firing alerts that share common label dimensions into a single notification payload. This mechanism prevents notification storms during transient infrastructure events. For instance, a brief network partition in a containerized environment might trigger connectivity failures across dozens of microservices. Instead of flooding the operations team with hundreds of individual alerts, grouping consolidates them into one cohesive message, enabling faster root-cause analysis.

Inhibition

Inhibition suppresses secondary or dependent alerts when a primary, high-severity event occurs. Consider a disaster recovery scenario where a primary data center fails and traffic fails over to a backup site. Alerts generated by the failed nodes or their hosted services become irrelevant. By defining inhibition rules, Alertmanager automatically mutes lower-priority notifications that stem from the same underlying failure, ensuring engineers focus on the critical incident.

Silencing

Silences provide a temporary, label-based mute capability. When an incoming alert matches a defined silence rule, its notification is withheld until the silence expires or is manually removed. This is highly effective during scheduled maintenance windows, known incident response procedures, or when debugging noisy metrics that have been identified but not yet resolved.

Kubernetes Deployment Architecture

Persistent Storage

Alertmanager maintains an internal state for active alerts and silences. A PersistentVolumeClaim ensures data survives pod restarts.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: alertmanager-state
  namespace: observability
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ceph-rbd
  resources:
    requests:
      storage: 10Gi

Configuration and Routing Templates

The central configuration defines global settings, notification templates, routing trees, receivers, and inhibition logic.

apiVersion: v1
kind: ConfigMap
metadata:
  name: alertmanager-config
  namespace: observability
data:
  alertmanager.yaml: |
    global:
      resolve_timeout: 5m
      smtp_smarthost: smtp.internal.corp:587
      smtp_from: monitoring@yourcompany.com
      smtp_auth_username: monitoring@yourcompany.com
      smtp_auth_password: app-specific-password
      smtp_require_tls: true

    templates:
      - /etc/alertmanager/templates/*.tmpl

    route:
      receiver: fallback-ops
      group_by: [cluster, namespace, alertname]
      group_wait: 30s
      group_interval: 5m
      repeat_interval: 12h
      routes:
        - matchers:
            - severity=~"critical|warning"
            - alertname=~"NodeDown|ClusterUnhealthy"
          receiver: critical-incident
          group_wait: 10s
        - matchers:
            - team: database
          receiver: dba-alerts
          continue: false

    receivers:
      - name: fallback-ops
        email_configs:
          - to: ops-team@yourcompany.com
            send_resolved: true
            html: '{{ template "email.summary" . }}'

      - name: critical-incident
        webhook_configs:
          - url: http://pagerduty-proxy:8080/v2/enqueue
            send_resolved: true

      - name: dba-alerts
        email_configs:
          - to: dba-team@yourcompany.com
            send_resolved: true
            html: '{{ template "db.alert.html" . }}'

    inhibit_rules:
      - source_matchers:
          - severity="critical"
        target_matchers:
          - severity="warning"
        equal: [cluster, namespace]
  email.tmpl: |
    {{ define "email.summary" }}
    {{- range .Alerts }}
    <div style="border:1px solid #ccc; padding:10px; margin:5px;">
      <strong>Alert:</strong> {{ .Labels.alertname }}<br>
      <strong>Severity:</strong> {{ .Labels.severity }}<br>
      <strong>Instance:</strong> {{ .Labels.instance }}<br>
      <strong>Summary:</strong> {{ .Annotations.summary }}<br>
      <strong>Fired At:</strong> {{ .StartsAt.Format "2006-01-02 15:04:05" }}
    </div>
    {{- end }}
    {{- end }}
    {{ define "db.alert.html" }}
    {{- range .Alerts }}
    <p>Database alert triggered: {{ .Labels.alertname }} on {{ .Labels.instance }}</p>
    {{- end }}
    {{- end }}

Application Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: alertmanager-core
  namespace: observability
spec:
  replicas: 2
  selector:
    matchLabels:
      app: alertmanager
  template:
    metadata:
      labels:
        app: alertmanager
    spec:
      containers:
        - name: alertmanager
          image: prom/alertmanager:v0.27.0
          args:
            - --config.file=/etc/alertmanager/alertmanager.yaml
            - --storage.path=/alertmanager-data
            - --web.external-url=https://alerts.yourcompany.com
            - --cluster.peer=alertmanager-core-0.alertmanager-headless:9094
          ports:
            - containerPort: 9093
              name: web
            - containerPort: 9094
              name: cluster
          readinessProbe:
            httpGet:
              path: /-/ready
              port: web
          livenessProbe:
            httpGet:
              path: /-/healthy
              port: web
          volumeMounts:
            - name: config
              mountPath: /etc/alertmanager
            - name: storage
              mountPath: /alertmanager-data
        - name: config-reloader
          image: jimmidyson/configmap-reload:v0.8.0
          args:
            - --volume-dir=/etc/alertmanager/templates
            - --webhook-url=http://localhost:9093/-/reload
          volumeMounts:
            - name: config
              mountPath: /etc/alertmanager/templates
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: alertmanager-config
        - name: storage
          persistentVolumeClaim:
            claimName: alertmanager-state

Network Exposure

apiVersion: v1
kind: Service
metadata:
  name: alertmanager-svc
  namespace: observability
spec:
  selector:
    app: alertmanager
  ports:
    - port: 9093
      targetPort: 9093
      name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: alertmanager-web
  namespace: observability
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: alertmanager-auth
spec:
  ingressClassName: nginx
  rules:
    - host: alerts.yourcompany.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: alertmanager-svc
                port:
                  number: 9093

Integrating with Prometheus

Configure the Prometheus instance to forward evaluated alerts to the Alertmanager service. Update the central Prometheus configuration ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-central-config
  namespace: observability
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    alerting:
      alertmanagers:
        - static_configs:
            - targets:
                - alertmanager-svc.observability.svc.cluster.local:9093
    scrape_configs:
      - job_name: kubernetes-nodes
        kubernetes_sd_configs:
          - role: node

Apply the updated configuration and trigger a reload to activate the alert pipeline:

kubectl apply -f prometheus-central-config.yaml
kubectl rollout restart statefulset prometheus-server -n observability
curl -X POST http://prometheus-svc.observability.svc:9090/-/reload

Configuration Breakdown and Validation

The Alertmanager configuration follows a hierarchical structure designed for flexible routing and noise reduction:

  • Global Settings: Defines default timeouts, SMTP credentials, and HTTP client behavior applied across all receivers unless explicitly overridden.
  • Templates: References external Go template files that format notification payloads for emails, webhooks, or messaging platforms.
  • Route Tree: Establishes the decision logic for alert distribution. The root route acts as a catch-all, while child routes use label matchers to direct alerts to specialized receivers. Parameters like group_wait, group_interval, and repeat_interval control aggregation timing and retry behavior.
  • Receivers: Abstract endpoints for alert delivery. Supports email, PagerDuty, Slack, Webhook, and custom HTTP integrations.
  • Inhibition Rules: Defines logical relationships between alert severities or types. When a source alert matches, target alerts with identical equal labels are automatically suppressed.

To verify the routing pipeline with out waiting for real metric thresholds, inject synthetic alerts via the REST API:

curl -X POST http://alertmanager-svc.observability.svc:9093/api/v2/alerts \
     -H "Content-Type: application/json" \
     -d '[
       {
         "labels": {
           "alertname": "HighMemoryUsage",
           "instance": "worker-node-04",
           "severity": "critical",
           "cluster": "prod-east"
         },
         "annotations": {
           "summary": "Node memory consumption exceeds 95%",
           "description": "Investigate OOM risk on worker-node-04"
         },
         "startsAt": "2024-11-15T10:30:00Z"
       }
     ]'

After submission, navigate to the Alertmanager web interface or check the configured email/webhook endpoints to confirm that the synthetic alert traversed the correct routing branch and triggered the intended receiver. The UI dashboard also provides real-time visibility into active firing alerts, resolved events, and configured silences.

Tags: alertmanager prometheus kubernetes observability notification-routing

Posted on Sat, 25 Jul 2026 16:51:27 +0000 by robinas