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.