Projektpraxis & Tools

So misst du, ob dein DevOps-Tool in Produktion wirkt

Eine grüne Pipeline und ein erfolgreich ausgeführtes Skript können sich in Produktion trotzdem als Fehlinvestition erweisen. Ich würde Automatisierung deshalb nicht an eingesparten Klicks oder bestandenen Builds messen, sondern an ihren Auswirkungen auf Änderungen, Störungen und manuelle Eingriffe. Wer DevOps-Workflows betreibt, braucht dafür eine durchgehende Messkette vom Commit bis zum Dienstverhalten – und muss Fehlschläge der Automatisierung selbst mitzählen.

Ein grüner Build ist kein Produktionssignal

Ich lese Automatisierung und Skripting: Effiziente DevOps Workflows kritisch, weil ein erfolgreiches Skript noch nicht zeigt, ob nach seinem Lauf weniger Arbeit oder weniger Störungen entstehen. Der Unterschied ist im Betrieb erheblich: Ein Job kann mit Exit-Code 0 enden, obwohl ein Mensch anschließend Berechtigungen korrigiert, einen fehlerhaften Rollout zurücknimmt oder Daten von Hand bereinigt.

Die erste Messgröße sollte deshalb eine durchgängige Änderungs-ID sein. Git-SHA und Deployment-ID gehören in die Ereignisse von GitHub Actions oder GitLab CI, in die Synchronisationshistorie von Argo CD und in die Incident-Dokumentation. Für eine Anwendung auf Kubernetes lässt sich zusätzlich die ausgerollte Image-Digest erfassen; ein Tag wie latest reicht zur Zuordnung nicht aus, weil er später auf ein anderes Artefakt zeigen kann. Erst diese Verknüpfung beantwortet die Frage, welche Änderung tatsächlich hinter einer Störung stand.

Ich würde drei Zeitpunkte getrennt speichern: Commit angenommen, Artefakt veröffentlicht und Änderung in Produktion wirksam. Wer nur die CI-Laufzeit misst, übersieht Wartezeiten vor Freigaben und während des Rollouts. Die DORA-Metrik Lead Time for Changes ist dafür ein brauchbarer Rahmen, sofern der Start- und Endpunkt im Team fest definiert sind; andernfalls lassen sich Werte verschiedener Wochen nicht sinnvoll vergleichen. Ebenso braucht Deployment Frequency eine feste Zählregel: Ein wiederholter Argo-CD-Sync desselben Artefakts ist nicht automatisch eine neue Änderung.

Ein sinnvoller Einstieg ist ein Beobachtungsfenster von 28 Tagen; diese Dauer ist ein einstellbarer Startwert, kein universeller Grenzwert. Erfasst werden pro Änderung Deployment-ID, SHA, Beginn und Ende des Rollouts, Rollback, verknüpfter Incident und nachträglicher manueller Eingriff. Fehlende Verknüpfungen bleiben als „unbekannt“ sichtbar. Sie stillschweigend als erfolgreiche Deployments zu zählen, würde die Erfolgsquote gerade dort verbessern, wo die Nachverfolgung versagt.

Auch der Nenner zählt. Wenn eine Pipeline nach einem fehlerhaften Testlauf gar nicht deployt, gehört das Ergebnis in die Statistik der CI-Qualität, aber nicht in die Change-Failure-Rate der produktiven Deployments. Umgekehrt muss ein ausgelöster Rollback als produktives Ergebnis sichtbar bleiben, selbst wenn die Pipeline nach erfolgreichem Rollback wieder grün wird. Diese Trennung verhindert, dass Prozessmetriken und Produktionswirkung ineinander verschwimmen.

Die Change-Failure-Rate braucht eine überprüfbare Fehlerdefinition

Die Change-Failure-Rate klingt eindeutig, ist es aber ohne Zuordnungsregel nicht: Zählt ein Alarm, ein Rollback, ein Hotfix oder erst ein Incident? Ich würde eine produktive Änderung als fehlgeschlagen markieren, wenn sie innerhalb eines festgelegten Zuordnungsfensters einen nutzerrelevanten Incident verursacht oder zur Wiederherstellung zurückgenommen werden muss. Ein bloßer Alarm zählt nicht, weil ein falsch konfigurierter Schwellwert sonst die Rate verändern könnte, ohne dass der Dienst schlechter geworden ist.

Als abstimmbare Zuordnungsfrist bieten sich zunächst 24 Stunden nach dem Rollout an. Für Batch-Verarbeitung kann sie zu kurz sein, weil Fehler erst beim nächsten Lauf auftreten; für einen häufig deployten API-Dienst kann sie zu lang sein, weil sich mehrere Änderungen überlagern. Die Regel sollte deshalb vor der Auswertung feststehen und bei Anpassungen versioniert werden. Mehrdeutige Fälle gehören in eine eigene Kategorie und in ein Review, statt automatisch dem letzten Commit zugeschrieben zu werden.

In einem ausdrücklich fiktiven Datensatz wurden 40 produktive Deployments und 4 zugeordnete Fehlschläge erfasst; die daraus berechneten 10 % sind eine Illustration, kein Benchmark. Eine sinkende Rate wäre nur dann ein Fortschritt, wenn Definition, Zuordnungsfenster und Erfassungsgrad gleich bleiben. Wird der Incident-Link in Jira oder PagerDuty nicht mehr gepflegt, kann die Kennzahl sinken, obwohl der Bereitschaftsdienst unverändert oft eingreifen muss.

Ich würde Automatisierung, CI CD und Clean Code fuer Softwarequalitaet selektiv lesen, weil weder eine grüne CI-Pipeline noch eine hohe Testabdeckung allein belegt, dass ein Rollout nutzerrelevante Fehler verhindert. JaCoCo kann ausgeführte Java-Codezeilen ausweisen, aber keine fehlenden Assertions erkennen. pytest kann Tests zuverlässig ausführen, aber nur für Fälle, die jemand formuliert hat. Deshalb sollten Testresultate und Coverage als Diagnose für die Pipeline dienen, während Produktionsmetriken ihre tatsächliche Schutzwirkung prüfen.

Daneben ist Time to Restore Service nützlich, wenn Start und Ende klar definiert sind. Beginnt die Uhr mit dem ersten fehlgeschlagenen Request oder erst mit dem PagerDuty-Alarm? Endet sie beim Rollback-Befehl oder wenn die Fehlerrate wieder stabil ist? Für den Betrieb zählt die Wiederherstellung des Dienstes, weil ein erfolgreiches Kommando ohne verbesserte Nutzerwirkung keine Störung beendet. Dokumentiert außerdem, ob ein Hotfix, ein Rollback oder eine Datenkorrektur geholfen hat; sonst bleibt verborgen, welche Art Automatisierung tatsächlich Zeit spart.

Service-Level-Indikatoren schlagen Pipeline-Dashboards bei der Ursachenprüfung

Eine Pipeline kann die Zahl ihrer Stages, Laufzeit und Erfolgsquote präzise melden. Für die Frage nach der Produktionswirkung ist sie trotzdem nur eine Hälfte der Messung. Ich würde je Dienst mindestens einen nutzerbezogenen Service-Level-Indikator, kurz SLI, mit Deployments verknüpfen: etwa den Anteil erfolgreicher HTTP-Anfragen und eine Latenzverteilung für eine zentrale Operation. Der Grund ist einfach: Ein Deployment kann technisch abgeschlossen sein und zugleich die Antwortzeiten verschlechtern.

Prometheus kann dafür HTTP-Counter und Histogramme auswerten; Grafana macht Zeitverläufe neben Rollout-Markierungen sichtbar. Bei HTTP-Metriken müssen Labels und Bedeutung feststehen: Ein status-Label mit 5.. erfasst serverseitige Fehler, aber nicht jede für Nutzer gescheiterte Anfrage. Ein Dienst, der trotz fachlich falscher Antwort HTTP 200 liefert, benötigt zusätzlich eine fachliche Erfolgsmetrik. OpenTelemetry und der OpenTelemetry Collector helfen bei konsistentem Transport von Metriken und Traces, ersetzen aber keine Entscheidung darüber, was als Erfolg zählt.

Die folgende Abfrage funktioniert gegen die Prometheus-HTTP-API, wenn der Job api einen Counter http_requests_total mit dem Label status liefert. Sie zeigt den Anteil der 5xx-Antworten im zurückliegenden Fenster; PROM lässt sich auf die eigene Instanz setzen. curl und jq müssen installiert sein.

#!/usr/bin/env bash
set -euo pipefail
PROM=${PROM:-http://localhost:9090}
QUERY='(sum(increase(http_requests_total{job="api",status=~"5.."}[30m])) or vector(0)) / sum(increase(http_requests_total{job="api"}[30m]))'
curl -fsSG "$PROM/api/v1/query" \
  --data-urlencode "query=$QUERY" |
  jq -er '.data.result[0].value[1]'

Die 30 Minuten im Query sind eine an die Verkehrslage anzupassende Auswertungsdauer: Bei wenig Traffic schwankt der Anteil stark, bei langen Fenstern können kurze Rollout-Fehler untergehen. Gibt es im Fenster keine Anfragen, soll die Abfrage keinen scheinbar guten Wert liefern; fehlender Traffic ist kein Nachweis für Verfügbarkeit. Für einen Alarm mit Alertmanager braucht es deshalb zusätzlich eine Mindestmenge an Anfragen und eine bewusst gewählte Haltezeit über die Regeloption for.

Besonders aufschlussreich ist der Vergleich vor und nach einem Deployment bei ähnlicher Last. Er ist kein automatischer Kausalitätsbeweis, weil externe Abhängigkeiten oder gleichzeitige Konfigurationsänderungen ebenfalls wirken können. Traces mit derselben Deployment-ID und eine dokumentierte Rollout-Zeit helfen, Kandidaten einzugrenzen; die endgültige Zuordnung gehört bei strittigen Fällen ins Incident-Review. So wird aus einem Dashboard eine prüfbare Aussage statt einer optischen Korrelation.

Weniger Handarbeit zählt nur, wenn die Ausnahmen mitgezählt werden

Der häufigste blinde Fleck einer Automationsbilanz ist Nacharbeit. Ich würde für jeden Workflow neben Erfolgsquote und Laufzeit die Zahl manueller Eingriffe erfassen: erneuter Start, übersprungener Check, korrigierte Konfiguration, zurückgesetzter Rollout und Reparatur von Daten. Das lässt sich als Ereignis im CI-System und als kurzer Eintrag im Incident oder Change-Record dokumentieren. Ohne diese Ausnahmen kann ein Team eine scheinbar stabile Pipeline betreiben, deren Fehler regelmäßig vom Bereitschaftsdienst abgefangen werden.

GitHub Actions und Argo CD bieten hier zwei unterschiedliche Messpunkte. GitHub Actions gewinnt bei Fragen nach Build-, Test- und Freigabeproblemen, weil dort Job-Abbrüche und manuelle Wiederholungen sichtbar sind; sein Preis ist, dass ein erfolgreicher Job noch nichts über den tatsächlichen Clusterzustand aussagt. Argo CD gewinnt bei Drift und Synchronisationsproblemen, weil es den gewünschten mit dem beobachteten Kubernetes-Zustand vergleicht; sein Preis ist zusätzlicher Betriebsaufwand und die begrenzte Aussagekraft eines „Healthy“-Status über fachliche Nutzerergebnisse. Ich würde beide Ereignisströme über Deployment-ID verbinden, statt einen als Ersatz für den anderen zu behandeln.

Auch Qualitätswerkzeuge brauchen eine Kostenrechnung. ShellCheck kann riskante Shell-Konstrukte früh markieren und Trivy kann bekannte Schwachstellen in Images finden; beide vermeiden aber nur dann Produktionsaufwand, wenn ihre Befunde bearbeitet und falsch positive Meldungen nachvollziehbar behandelt werden. Gemessen werden sollten deshalb nicht bloß gefundene Befunde, sondern ihre Bearbeitungszeit und die Häufigkeit begründeter Ausnahmen. Eine dauerhaft übersteuerte Prüfung ist teuer, weil sie Zeit bindet, ohne die Freigabeentscheidung zuverlässig zu verbessern.

Ich würde nicht alle fehlgeschlagenen CI-Jobs automatisch erneut starten, weil ein Retry instabile Tests und intermittierende Infrastrukturfehler verdecken kann. Stattdessen sollten erster Fehlschlag, Retry-Zahl und endgültiges Ergebnis getrennt erfasst werden. Steigt die Quote der erst beim zweiten Lauf erfolgreichen Jobs, während die grüne Abschlussquote gleich bleibt, ist das ein Wartungssignal – kein Beleg für höhere Softwarequalität. Dasselbe gilt für manuelle Overrides: Sie sind manchmal nötig, müssen aber im Messbild bleiben.

Beginne beim nächsten produktiven Deployment mit einem einzigen Datensatz: Halte SHA, Deployment-ID, Rollout-Zeit, Nutzer-SLI und jeden manuellen Eingriff fest. Verknüpfe einen späteren Incident ausdrücklich mit dieser Änderung oder markiere die Ursache als unbekannt. Wiederhole das für die folgenden Deployments, bevor du eine Erfolgsquote veröffentlichst. Die erste belastbare Verbesserung ist möglicherweise keine neue Automatisierung, sondern ein Fehler, den der Bereitschaftsdienst nicht mehr unsichtbar beheben muss.