Prometheus Cheatsheet

Prometheus CheatsheetAlle Kapitel

Prometheus Cheatsheet im Volltext

Stand Prometheus 3.13 LTS · Edition 2026.11

Cheatsheet im Volltext

Derselbe Inhalt wie im PDF, zum Mitlesen, Durchsuchen und direkten Kopieren der YAML-Snippets. Stand: Prometheus v3.13 LTS (Edition 2026.11).

Datenmodell

Metriktypen

Counter: monoton steigend, nur mit rate()/increase() auswerten. Gauge: frei beweglicher Momentanwert (Queue-Länge, Memory).

Histogram: kumulative le-Buckets + _sum/_count, serverseitig aggregierbar. Summary: client-seitig berechnete Quantile, nicht über Instanzen aggregierbar.

Labels, Serien, Cardinality

Jede eindeutige Label-Kombination erzeugt eine eigene Zeitserie. Serienzahl wächst multiplikativ mit den Wertemengen der Labels, Cardinality ist die zentrale Kostengröße für RAM, Ingest und Query-Latenz. Labels nur für Dimensionen mit kleiner, stabiler Wertemenge.

Native Histograms (stabil seit 3.8)

Exponentielle Buckets mit hoher Auflösung in einer Serie statt Dutzender le-Serien. Scraping explizit aktivieren: scrape_native_histograms: true (global oder pro Job); ohne gesetztes scrape_protocols (global oder im Job) verhandelt der Job dann Protobuf zuerst. Per Target überschreibbar über __scrape_native_histograms__ (ab 3.13); die Protokollwahl bleibt dabei auf Job-Ebene. Das alte Feature-Flag native-histograms ist seit 3.9 wirkungslos.

Prometheus 3.x

UTF-8 in Metrik-/Label-Namen (Rückfall: metric_name_validation_scheme: legacy). OTLP-Receiver: --web.enable-otlp-receiver.

Agent-Mode: --agent, nur Scrape + WAL + Remote-Write, kein Querying/Alerting/lokale TSDB. Defaults: scrape_interval 1m, scrape_timeout 10s, TSDB-Retention 15d. Retention gehört in die Config-Datei (storage.tsdb.retention.time/.size, reload-fähig), die gleichnamigen Flags sind deprecated; ab 3.15 gilt das auch für --log.level (→ runtime.log_level).

# Cardinality inspizieren
curl -s localhost:9090/api/v1/status/tsdb | jq .
# Top-10 Metriken nach Serienzahl (PromQL)
topk(10, count by (__name__)({__name__=~".+"}))

PromQL-Kern

rate vs irate

rate(v[5m]): per-second-Durchschnitt übers Fenster, extrapoliert an die Fensterränder, Counter-Resets werden korrigiert, Standard für Alerts und Dashboards.

irate(v[5m]): Momentanrate aus den letzten zwei Samples, reagiert schnell, verschluckt alles dazwischen. Nie für Alerts. Fenster immer groß genug für mehrere Samples wählen.

Aggregationen

sum, avg, min, max, count, topk, quantile, Dimensionen steuern mit by (labels) (behalten) oder without (labels) (entfernen). Regel: erst rate() pro Serie, dann sum(), nie umgekehrt.

histogram_quantile

histogram_quantile(0.99, ...) berechnet das φ-Quantil aus klassischen le-Buckets (vorher rate() auf _bucket, by (le) behalten!) oder direkt aus Native Histograms. Ergebnis ist eine Schätzung (Interpolation innerhalb des Buckets).

# Fehlerquote pro Service (5m-Fenster)
sum by (service)
  (rate(http_requests_total{code=~"5.."}[5m]))
/ sum by (service)
  (rate(http_requests_total[5m]))

# p99 aus klassischem Histogram
histogram_quantile(0.99, sum by (le)
  (rate(http_request_duration_seconds_bucket[5m])))

# p99 aus Native Histogram (keine _bucket-Serien)
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds[5m])))

Scrape-Config & Service Discovery

scrape_configs

Pro job_name entweder static_configs oder eine *_sd_configs-Discovery. Kubernetes-Rollen (kubernetes_sd_configs): endpointslice (statt endpoints, Endpoints-API seit K8s 1.33 deprecated), service, pod, node, ingress. Discovery liefert __meta_*-Labels als Rohmaterial fürs Relabeling.

relabel vs metric_relabel

relabel_configs: vor dem Scrape, auf Target-Ebene: Targets filtern (keep/drop), Adresse/Pfad setzen, __meta_* in echte Labels überführen.

metric_relabel_configs: nach dem Scrape, auf jede Serie, letzte Verteidigungslinie gegen Cardinality. Actions: replace, keep, drop, keepequal, dropequal, labelmap, labeldrop, labelkeep, hashmod, lowercase, uppercase.

scrape_configs:
- job_name: kubernetes-pods
  kubernetes_sd_configs:
  - role: pod
  relabel_configs:
  - source_labels:
    - __meta_kubernetes_pod_annotation_prometheus_io_scrape
    action: keep
    regex: "true"
  - source_labels: [__meta_kubernetes_pod_name]
    action: replace
    target_label: pod
  metric_relabel_configs:
  - source_labels: [__name__]
    action: drop
    regex: go_gc_.*

Recording & Alerting Rules

Recording Rules

Teure Ausdrücke vorberechnen, Dashboards/Alerts lesen die fertige Serie. Naming-Konvention: level:metric:operations, z.B. job:http_requests:rate5m. Auswertung pro Rule-Group sequenziell, Takt evaluation_interval (Default 1m).

Alerting Rules

expr + for: Alert ist erst pending, nach Ablauf von for firing, entprellt Flapping. labels (z.B. severity) steuern das Routing im Alertmanager, annotations sind für Menschen (summary, Runbook-Link).

groups:
- name: api.rules
  rules:
  - record: job:http_requests:rate5m
    expr: sum by (job) (rate(http_requests_total[5m]))
  - alert: HighErrorRate
    expr: |
      sum by (job)
        (rate(http_requests_total{code=~"5.."}[5m]))
      / sum by (job)
        (rate(http_requests_total[5m])) > 0.05
    for: 10m
    labels: {severity: page}
    annotations:
      summary: >-
        Fehlerquote über 5% in {{ $labels.job }}

Alertmanager

Routing-Tree

Ein Wurzel-route-Block, Kinder matchen per matchers. Erster Match gewinnt (außer continue: true). Die Root-Route muss alles matchen (keine Matchers), sie ist der Default-Receiver.

Grouping, Timing

group_by bündelt Alerts zu einer Notification. group_wait (Default 30s): Wartezeit vor der ersten Notification einer neuen Gruppe. group_interval (5m): Takt für Updates der Gruppe. repeat_interval (4h): Wiederholung unveränderter Alerts, als Vielfaches von group_interval wählen.

Inhibition & Silences

inhibit_rules: unterdrücken abhängige Alerts (z.B. warning, solange dasselbe critical feuert), equal: verhindert Querschüsse zwischen Clustern.

Silences: ad hoc via UI/amtool, immer mit Ablaufzeit. Geplante Wartungsfenster: Top-Level time_intervals definieren, an der Route per mute_time_intervals (oder active_time_intervals) referenzieren, nicht an der Root-Route.

API und Browser: ab 0.34.2 sendet /api/v2 keine CORS-Header mehr (GHSA-w5g2-x24w-p3fq). Web-Tools von fremden Origins per --web.cors.origin (Regex, voll verankert) freigeben.

route:
  receiver: default
  group_by: [alertname, cluster]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  routes:
  - matchers: [severity="page"]
    receiver: oncall
inhibit_rules:
- source_matchers: [severity="critical"]
  target_matchers: [severity="warning"]
  equal: [alertname, cluster]

Remote-Write vs Federation

Remote-Write

Streamt Samples (gefiltert per write_relabel_configs) an ein Langzeit-Backend. Remote-Write 2.0 (Spec 2.0-rc.6, experimentell): protobuf_message: io.prometheus.write.v2.Request, Default bleibt prometheus.WriteRequest. Metadata-Versand braucht --enable-feature=metadata-wal-records. Native Histograms gehen nur mit send_native_histograms: true raus, auch bei v2: die Doku nennt die Option dort No-op, ohne sie verwirft der Code die Histogramme aber (prometheus#20093, offen). Receiver: --web.enable-remote-write-receiver, nimmt per Default v1 und v2 an; einschränken per --web.remote-write-receiver.accepted-protobuf-messages.

TLS zum Backend: ab 3.13.5/3.15.1 verwirft crypto/x509 Ketten über die kompromittierten eMudhra-Intermediates (CVE-2026-111943), siehe Release-Zyklus.

Federation

/federate-Endpoint, Auswahl per match[]-Selektoren. Gedacht für aggregierte Serien (hierarchisch) oder gezielte Cross-Service-Metriken, kein Voll-Replikat und kein Langzeit-Backup. Für Langzeit/HA: Remote-Write.

remote_write:
- url: https://metrics.example.com/api/v1/push
  protobuf_message: io.prometheus.write.v2.Request
  send_native_histograms: true
  write_relabel_configs:
  - source_labels: [__name__]
    action: drop
    regex: go_.*

Langzeit & HA: Thanos / Mimir

Thanos (CNCF Incubating)

Sidecar neben jedem Prometheus lädt TSDB-Blöcke in Object Storage; Query liefert die globale Sicht und dedupliziert HA-Paare; Store Gateway liest alte Blöcke, Compactor verdichtet und downsampled, Receive nimmt Remote-Write an. Prometheus bleibt die Scrape-Quelle.

XOR2-Chunks (storage.tsdb.chunk_encoding.floats: xor2; in 3.13 experimentell und nur mit --enable-feature=xor2-encoding, stabil ab 3.15, dort auch implizit durch --enable-feature=st-storage) erst einschalten, wenn der Sidecar sie lesen kann. Ein Downgrade auf eine Version ohne XOR2 verlangt das Löschen der betroffenen Blöcke.

Grafana Mimir (AGPLv3)

Horizontal skalierbarer, nativ multi-tenanter Langzeit-Store; Ingest via Remote-Write oder OTLP (/otlp/v1/metrics), Ablage in Object Storage (S3/GCS/Azure). Projektangabe: bis zu 1 Mrd. aktive Serien. Wahl: Thanos hält Prometheus im Zentrum, Mimir zentralisiert.

HA-Grundmuster

Zwei Prometheus-Replicas scrapen dieselben Targets und unterscheiden sich nur in einem Replica-external_label; Dedup passiert downstream (Thanos Query --query.replica-label, Mimir-HA-Tracker mit cluster/__replica__, per Default aus). Beide melden an denselben Alertmanager-Cluster und listen jede Instanz einzeln, ohne Load Balancer dazwischen. Das Replica-Label per alert_relabel_configs (labeldrop) entfernen, sonst dedupliziert der Alertmanager nicht. Der Operator macht das automatisch (prometheus_replica).

Prometheus Operator

CRDs statt Config-Files

ServiceMonitor (Services), PodMonitor (Pods), Probe (Blackbox/Ingress), ScrapeConfig (Targets außerhalb des Clusters), PrometheusRule (Recording/Alerting), AlertmanagerConfig (Routing-Teilbäume, matchen per Default nur Alerts, deren namespace-Label dem eigenen Namespace entspricht). Der Operator generiert daraus die laufende Prometheus-Konfiguration; die Prometheus-CR wählt CRs per Label-Selektor aus.

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: api
  labels: {team: platform}
spec:
  selector:
    matchLabels: {app: api}
  endpoints:
  - port: http-metrics
    interval: 30s
    path: /metrics

Stolperfallen

port im ServiceMonitor ist der Port-Name des Service, nicht die Nummer. CR wird nicht gescraped? Label-Selektor der Prometheus-CR prüfen, nicht selektierte CRs werden still ignoriert: serviceMonitorSelector: {} wählt alle, fehlt er, wählt er keine; ohne serviceMonitorNamespaceSelector nur den eigenen Namespace. ServiceMonitors nutzen per Default die SD-Rolle endpoints; ab K8s 1.33 in der Prometheus-CR serviceDiscoveryRole: EndpointSlice setzen.

Release-Zyklus & LTS

Warum LTS die richtige Wahl ist

Alle sechs Wochen startet ein neuer Minor-Zyklus. Ein normaler Minor bekommt danach in der Regel keine Bugfixes mehr, der Nachfolger löst ihn ab. Wer nicht alle sechs Wochen hebt, läuft also ungepatcht. Aktueller Minor: 3.15, zuletzt 3.15.1 (21.10.2026).

LTS: ausgewählte Releases bekommen ein Jahr lang Fixes für ausgewählte Probleme hoher Schwere (CVSS ab 7.0), nach Möglichkeit weitere Bug- und Doku-Fixes, als Best Effort der Community. Ausgenommen sind experimentelle Features und alles, was die Stability-Guarantees als instabil führen, darunter Server-TLS/Basic-Auth (web.config.file), Remote Read und Service Discovery außer static/file/http_sd.

3.13 ist LTS (01.07.2026), Support bis 31.07.2027, zuletzt 3.13.5 (21.10.2026).

3.5 war die vorige LTS (14.07.2025), Support endete am 31.07.2026. Nächste LTS: geplant Juni 2027, Support bis 31.07.2028.

Sicherheit: 3.13.5 und 3.15.1 sind mit Go 1.26.10 bzw. 1.27.3 gebaut. Damit verwirft crypto/x509 Ketten über die kompromittierten eMudhra-Intermediates (CVE-2026-111943), bei jedem ausgehenden TLS (tls_config, etwa bei Scrape, Remote-Write und Alerting), auch mit eigenem ca_file. Die Container-Images streichen zusätzlich „emSign ECC Root CA - G3“ und „Comodo AAA Services root“ aus dem CA-Store. Ältere Releases und eigene Builds mit älterer Go-Toolchain haben diesen Filter nicht. Den Filter haben auch Alertmanager ab 0.34.2, Prometheus Operator ab 0.94.2, Thanos ab 0.42.5 und Mimir ab 3.2.3/3.1.8.

Für Plattform-Betrieb heißt das: auf der LTS-Linie bleiben und einmal jährlich auf die nächste heben, statt dem Sechs-Wochen-Takt hinterherzulaufen.

Anti-Patterns

Was du nicht tun solltest

Unbounded Labels: user_id, request_id, volle URLs als Label-Wert, Cardinality-Explosion bis zum OOM. IDs gehören in Logs/Traces, nicht in Labels.

irate() in Alerts: sieht nur die letzten zwei Samples, kurze Spikes und Lücken kippen den Alert. rate() nehmen.

sum() vor rate(): Counter-Resets einzelner Targets gehen als Sprünge in die Summe ein, immer erst rate(), dann sum().

Summary-Quantile mitteln: avg() über client-seitige Quantile ist statistisch bedeutungslos, Histogram + histogram_quantile.

Federation als Backup: /federate repliziert keine Historie und skaliert nicht für alles, Langzeit via Remote-Write.

Ein globaler Mega-Prometheus: pro Cluster/Zone scrapen, globale Sicht über Thanos/Mimir, nicht über ein einzelnes, vertikal gemästetes Prometheus.