Probleme erkennen und lösen: Observability-Praxis im CI/CD-Prozess

Seite 2: Open Source: OpenTelemetry mit tracepusher

Inhaltsverzeichnis

Ein Beispiel ist das noch recht neue Tool Tracepusher, das Administratorinnen und Administratoren entweder in CI/CD-Pipelines integrieren oder eigenständig auf der Kommandozeile ausführen. Tracepusher erstellt Traces und Spans im CI/CD-Kontext (insbesondere GitLab) und schickt sie an einen OpenTelemetry-Collector. Ein Beispiel für ein OpenTelemetry-Setup mit einem vorkonfigurierten HTTP-Endpunkt und der Tracepusher-Integration in die Beispiel-CI/CD-Pipeline finden sich auf GitLab.

Das Tool Datadog bietet CI-Visibility für unterschiedlichste Plattformen an. Es sammelt CI/CD-Events entweder in eine SaaS-Plattform integriert oder lokal über den Datadog-Agent. Logs und Traces schickt es direkt an die Datadog-API. In der dortigen Weboberfläche lassen sich die Daten dann mit anderen Metriken, Logs und Traces korrelieren. Für eine Beispielkonfiguration mit dem Beispiel-Projekt erstellen Admins zunächst einen API-Key für Datadog. Im GitLab-Projekt navigieren sie zu "Settings/Integrations" und aktivieren die Datadog-Integration. Der richtige Datadog-Endpunkt hängt vom Standort ab, bei falscher Auswahl erhält man die Fehlermeldung "Error: API invalid or blacklisted". Das Skript hat datadoghq.com voreingestellt. Verwendet man die EU-SaaS-Instanz, muss der Wert datadoghq.eu heißen.

Die Weboberfläche von Datadog zeigt alle laufenden und historischen Pipelines und erlaubt tiefen Einblick in die CI/CD-Jobs inklusive einer Zeitlinie und Details zu den Fehlern. Admins verwenden dafür verschiedene Filter. Ein historischer Stage-Breakdown zeigt, wie stark sich die Laufzeiten in unterschiedlichen Commits verschoben haben. So lassen sich etwa Ausreißer von Merge-Request-Pipelines mit neuen Features einfacher identifizieren. Anwender finden auch schnell heraus, dass eine neue Software viele Abhängigkeiten herunterlädt, ohne dass Caching aktiviert ist.

CI-Visibility in Datadog am Beispiel einer langsamen GitLab-Pipeline (Abb. 3).

Das Open-Source-Projekt buildevents von Honeycomb.io war eines der ersten zum Sammeln von CI/CD-Informationen. Das Kommandozeilenprogramm verwendet den globalen Kontext mit den Umgebungsvariablen, um Trace IDs und Span IDs zu erstellen. Alle Jobs befüllen die Traces, bis am Ende der Pipeline ein extra definierter Job die Sammlung zur Honeycomb.io-API schickt. OpenTelemetry als generisches Ziel unterstützt es bedauerlicherweise bisher noch nicht.

New Relic hat eine experimentelle Integration für GitLab-CI/CD-Pipelines bereitgestellt, die Logs, Traces und Metriken sammelt und an den OpenTelemetry-Endpunkt von New Relic schickt. Administratorinnen und Administratoren definieren in der CI/CD-Pipeline eine neue Stage mit einem abschließenden Job, der über Parent-Child-Pipelines eine weitere Pipeline startet. Diese holt sich die Parent-Daten von der GitLab-API, erstellt Logs, Traces und Metriken, die sie anschließend an den OpenTelemetry-Endpunkt schickt. Standalone-Support für OpenTelemetry funktioniert nicht, sodass ein API-Key für New Relic erforderlich ist.

Mit einigen schnell umsetzbaren Maßnahmen lassen sich CI/CD-Pipelines optimieren. Nicht alle Jobs müssen beispielsweise immer ausgeführt werden: In einem großen Mono-Repository konfigurieren Admins Backend- und Frontend-Jobs in einer Pipeline. Wenn ein Merge-Request nur mit Änderungen im Backend startet, müssen die anschließenden Frontend-Jobs nicht zwingend laufen. Diese Strategie reduziert Laufzeiten und spart Ressourcen.

Das Tool Circle CI erlaubt es, Jobs nur dann auszuführen, wenn ein entsprechender Branch-Name oder Git-Tag dafür erscheint. In GitHub Actions gibt es Filter für Aktions-Trigger und in GitLab steuern Anwenderinnen und Anwender Jobs mit Regeln, die Pipelines für unterschiedliche Anwendungsfälle erzeugen. Es lässt sich so nach Git-Branch-Name oder -Tag filtern, Merge Requests als Trigger-Event einschränken oder eigene CI/CD-Variablen prüfen. Diese Regeln greifen über Template-Grenzen hinweg, und erlauben eine Abstraktion für Endnutzer.

Eine effiziente Maßnahme ist "Fail fast": Wenn Admins aus Erfahrung wissen, dass bestimmte Jobs fehlschlagen (etwa Programmierfehler in einer neuen Sprache oder Tests, die niemand lokal ausführt), sollten diese mit Priorität starten und schnell wieder enden, um Ressourcen nur kurz zu binden. Nachfolgende Jobs müssen dann in Abhängigkeit definiert sein.

Caching ist ein wichtiges Thema für Frameworks mit vielen Abhängigkeiten oder großen Paketen, die andernfalls bei jeder Ausführung von Neuem heruntergeladen werden. Caching verringert auch den Traffic in Cloud-Umgebungen – der je nach Dienstanbieter teuer sein kann. Eine weitere Optimierungsstrategie sind reduzierte Container-Images. Blockierend kann bei großen Projekten auch die Git-Historie wirken. Hier hilft eine Clone-Strategie, die nur den aktuellen HEAD auscheckt und auf Historie verzichtet (Shallow Clone).

Jobs, die die gleichen Workflows ausführen, aber auf unterschiedlichen Distributionen getestet werden, lassen sich parallelisieren (Tags in GitLab). Gängige CI/CD-Systeme beherrschen diese Matrix Builds und können zusätzlich Sourcecode unterschiedlicher Sprachversionen testen. Eine wichtige Optimierung gilt auch der Hardware-Konfiguration, denn ressourcenhungrige Jobs sollten auf leistungsstärkeren Geräten laufen, während für die leichtgewichtigen kleiner dimensionierte VMs genügen. Hierzu bietet es sich an, Jobs auf bestimmten Exekutoren festzupinnen. In Kubernetes verwenden Admins node und pod affinity.