Einführung in CI/CD-Pipelines

Wenn Sie bereits unsere Leitfäden für Continuous Integration, Continuous Delivery und Continuous Deployment (zusammenfassend als CI/CD bezeichnet) kennen, sind Sie mit ziemlicher Sicherheit auf den Begriff „automatisierte Pipeline“ gestoßen und wissen, dass diese bei der CI/CD-Umsetzung eine zentrale Rolle spielt. Aber was genau ist eine Pipeline im Kontext von Continuous Integration/Delivery? Und wie baut man eine Pipeline auf?

Das Ziel von CI/CD ist es, Software schneller bereitzustellen, ohne bei der Qualität Kompromisse einzugehen. Dies können Sie erreichen, indem Sie Änderungen häufig einchecken, gründliche Tests durchführen und unmittelbar auf Feedback reagieren. Auf diese Weise können Sie Ihre Änderungen in beliebig kurzen Abständen live bereitstellen.

Was ist eine CI/CD-Pipeline?

Wenn wir über eine CI/CD-Pipeline sprechen, meinen wir damit eine Reihe von Schritten, die Ihr Code durchläuft, um von Ihrem Entwicklungssystem über Test- und Staging-Phasen in die Hände Ihrer Benutzercommunity zu gelangen.

Es gehört zum Kern einer CI/CD-Strategie, diesen Prozess regelmäßig durchzuführen – meist mehrmals am Tag. Daher ist es wichtig, den Vorgang so weit wie möglich zu automatisieren, wobei jeder Schritt entweder den nächsten auslöst oder einen Fehler zurückmeldet.

Die Automatisierung beschleunigt nicht nur den Gesamtprozess und damit die einzelnen Feedback-Schleifen, sondern sorgt auch dafür, dass jeder Schritt stets zuverlässig und auf die gleiche Weise ausgeführt wird.

Phasen einer Build-Pipeline

Zwar hängt die genaue Gestaltung Ihrer CI/CD-Pipeline von der Art des erstellten Produkts und den Anforderungen Ihres Unternehmens ab, doch alle Pipelines folgen grob betrachtet einem allgemeinen Muster, das wir im Folgenden vorstellen.

Der Prozess beginnt mit einem Commit in den Master-Branch (oder einen beliebigen anderen Branch, den Sie zum CI-Branch erkoren haben). Dieser Commit löst entweder einen Buildvorgang oder eine erste Unit-Test-Phase aus. Die Ergebnisse werden in einem Dashboard angezeigt, und wenn der Build oder ein Test fehlschlägt, wird darüber mithilfe einer automatischen Benachrichtigung Meldung erstattet.

Sie können die Pipeline entweder so konfigurieren, dass der Vorgang abgebrochen wird, um das Problem zu beheben und mit einem neuen Commit von vorn zu beginnen, oder Sie können Ausnahmen für bestimmte Fehlertypen zulassen, damit der Vorgang fortgesetzt werden kann.

Die nächste Phase umfasst eine Reihe von automatisierten Tests, wobei nach jeder Testrunde Feedback bereitgestellt wird. Üblicherweise sind die Tests so angeordnet, dass die schnellsten Tests zuerst ausgeführt werden, um so früh wie möglich Feedback zu erhalten.

Komplexere Tests, die Server länger auslasten, wie beispielsweise End-to-End-Tests, werden erst ausgeführt, wenn die vorherigen Tests erfolgreich bestanden wurden. Dies gewährleistet eine effiziente Nutzung Ihrer Ressourcen.

Sobald die automatisierten Tests abgeschlossen sind, wird die Software in der Regel in verschiedenen Staging-Umgebungen bereitgestellt, von denen einige für weitere manuelle Tests und andere für Schulungen, Support oder Kundenvorführungen verwendet werden.

In der letzten Phase der CI/CD-Pipeline-Architektur werden die Änderungen live geschaltet. Dies kann entweder manuell (bei Continuous Delivery) oder automatisch (bei Continuous Deployment) erfolgen.

Sehen wir uns jetzt einige Aspekte dieser Phasen etwas genauer an.

Flags und Branches

Der erste Schritt zur Einführung von Continuous Integration besteht darin, Ihren gesamten Codebestand in ein Versionsverwaltungssystem (VCS, auch Source Control Management oder SCM genannt) zu überführen – zum Beispiel Git, Mercurial oder Perforce. Wenn das geschafft ist, müssen Sie alle Mitglieder Ihres Teams dazu bringen, häufige Commits vorzunehmen. Jeder Commit in den Master-Branch löst einen Pipeline-Lauf aus: Der Code wird kompiliert und getestet, um Ihnen schnelles Feedback zu Ihren Änderungen zu geben.

Häufige Commits sind zwar ein wichtiger Bestandteil der CI/CD-Pipeline, aber während der Arbeit an einem größeren Feature, das mehrere Tage oder Wochen in Anspruch nimmt, können sich regelmäßige Commits wie ein zweischneidiges Schwert anfühlen.

Wenn Sie Ihre Änderungen in regelmäßigen Abständen die Pipeline durchlaufen lassen, erhalten Sie schnelleres Feedback und reduzieren die Wahrscheinlichkeit komplexer Konflikte im Vergleich zu einem einmaligen Durchlauf am Ende des Entwicklungsprozesses.

Auf der anderen Seite möchten Sie Ihren Kunden sicherlich kein halbfertiges Feature vorsetzen, und auch interne Benutzer*innen der Staging-Umgebungen sollen oft nicht mit laufenden Entwicklungen behelligt werden.

Feature-Flags und Feature-Branches bieten eine Lösung für dieses Problem. Mit Feature-Flags können Sie angeben, in welchen Umgebungen Ihr Code sichtbar sein soll. Ihre Änderungen sind zwar im Master-Branch vorhanden und für Ihr Team sichtbar, aber Sie können frei entscheiden, wann die Funktionalität auch in den Staging-Umgebungen und in der Produktion freigeschaltet wird.

Mit Feature-Branches entwickeln Sie Ihr Feature in einem separaten Branch, ohne auf die Vorteile automatisierter Build- und Testabläufe zu verzichten. Indem Sie die CI/CD-Pipeline bei jedem Commit in einen Feature-Branch auslösen, erhalten Sie wie bei einem Master-Commit schnelles Feedback zu Ihrer Arbeit.

Build- und Testablauf

Nachdem Sie mit einem Commit eine Instanz Ihrer Pipeline ausgelöst haben, sind als Nächstes die Build- und Testvorgänge an der Reihe. Wenn Sie über automatisierte Unit-Tests verfügen, werden diese normalerweise zusammen mit Linting- und statischen Analyseprüfungen vor dem Buildvorgang ausgeführt.

Das verwendete Build-Tool (z. B. Ant oder Maven) sowie die Details der Build-Schritte hängen von der Sprache und dem Framework ab, mit denen Sie arbeiten. Indem Sie den automatisierten Buildvorgang auf einem dedizierten Buildserver ausführen, können Sie das klassische, durch fehlende Abhängigkeiten verursachte „Aber auf meinem System funktioniert es doch“-Syndrom vermeiden.

Die Ausgabe des Build-Schrittes umfasst Installationsprogramme, Binärdateien oder Container (die „Build-Artefakte“), die dann in Testumgebungen bereitgestellt und mit anderen Teilen des Systems kombiniert werden, um auf höherer Ebene angesiedelte automatisierte Tests auszuführen: Integrationstests, Komponententests und End-to-End-Tests sowie nicht funktionsbezogene Tests wie Performance- und Sicherheitsanalysen.

Diese Tests können parallel ausgeführt werden, um die Pipeline zu beschleunigen und Ihnen schneller Feedback zu geben.

Container und VMs

Damit Ihre automatisierten Tests zuverlässige Ergebnisse liefern, müssen Sie sicherstellen, dass sie stets auf die gleiche Weise ausgeführt werden.

Idealerweise sollten Ihre Testumgebungen so konfiguriert werden, dass sie der Produktionsumgebung möglichst ähnlich sind, und sie sollten zwischen den Testläufen zurückgesetzt werden, um zu vermeiden, dass Variationen in der Umgebung Ihre Testergebnisse verfälschen.

Virtuelle Maschinen (VMs) sind seit langem eine beliebte Wahl für die Ausführung von Testumgebungen, da Sie die Umgebung für jeden neuen Buildvorgang skriptbasiert zurücksetzen können.

Das Herunterfahren und Hochfahren neuer VMs kostet jedoch Zeit, und Ihre Skripte müssen eine Konfiguration für jede virtuelle Umgebung enthalten, um alle zum Ausführen der Software notwendigen Abhängigkeiten bereitzustellen. Wenn neue Abhängigkeiten hinzukommen, müssen die Umgebungsskripte angepasst werden – ein Detail, das gerne übersehen wird, mit dem Ergebnis, dass der Build nicht durchläuft.

Diese Probleme können Sie vermeiden, indem Sie Ihren Code in einem ersten Build-Schritt in einen Container packen. Ein Container enthält alle Abhängigkeiten, die die Software zum Ausführen benötigt. Dies sorgt für eine einfache Portabilität und eine leichte Bereitstellung in verschiedenen Umgebungen.

Wenn Sie Ihre CI/CD in Ihrer eigenen Infrastruktur hosten, benötigen Sie immer noch VMs für die Container, aber die Bereitstellung der Testumgebung erfordert weniger Aufwand, und dadurch wird Ihre Pipeline effizienter. Wenn Sie Ihre Pipeline in der Cloud ausführen, können Sie durch die Verwendung von Containern Managed Services nutzen und den gesamten Infrastrukturaufwand an Ihren Cloud-Anbieter auslagern.

Vorproduktionsumgebungen

Die Anzahl der Test- und Staging-Umgebungen in Ihrer Pipeline-Architektur hängt von Ihrem Produkt und den Anforderungen der Beteiligten ab. Mögliche Einsatzbereiche sind explorative Tests, Sicherheitsüberprüfungen, Benutzerforschung, Verkaufsvorführungen, Schulungsumgebungen und Sandbox-Umgebungen zum Reproduzieren von Kundenproblemen.

Das automatisierte Erstellen und Bereitstellen dieser Umgebungen ist effizienter als das manuelle Zurücksetzen, und Sie können verschiedene Pipeline-Trigger für verschiedene Umgebungen konfigurieren.

So lässt sich beispielsweise festlegen, dass Testumgebungen für jeden Buildvorgang aktualisiert werden, während in Staging-Umgebungen nur einmal täglich oder wöchentlich der neueste erfolgreiche Build bereitgestellt wird.

Bereitstellung

Wenn Ihre Codeänderungen alle vorherigen Pipeline-Phasen erfolgreich durchlaufen haben, sind sie bereit für die Produktionsfreigabe. Dieser letzte Schritt kann manuell oder automatisch erfolgen.

Die manuelle Veröffentlichung (auch als Continuous Delivery bezeichnet) ist nützlich, wenn Sie den Einführungszeitpunkt neuer Features selbst bestimmen möchten, wenn Ihr Bereitstellungsprozess mit Ausfallzeiten verbunden ist oder wenn Ihr Produkt eine Installation erfordert und Sie Änderungen gemäß einem regelmäßigen Release-Plan gebündelt bereitstellen möchten.

Bei einem vollständig automatisierten Continuous-Deployment-Prozess werden Änderungen automatisch bereitgestellt, sofern sie alle vorangehenden Phasen erfolgreich durchlaufen haben.

Je nach Anzahl der Mitwirkenden und der Häufigkeit ihrer Commits kann dies bedeuten, dass Sie Dutzende Male am Tag Updates bereitstellen – eine Leistung, die ohne eine automatisierte Pipeline praktisch unmöglich ist.

CI/CD-Pipelines verstehen: Zusammenfassung

CI/CD macht die Softwareentwicklung effizienter, indem Probleme so früh wie möglich erkannt werden. Durch den sogenannten „Linksshift“, also indem Interaktionen vorverlagert werden und Rückmeldungen früher erfolgen, treten Fehler schneller zutage. Der Aufbau einer automatisierten Pipeline hilft Ihnen, diese Techniken in die Praxis umzusetzen.

Bei der Gestaltung Ihres eigenen CI/CD-Prozesses empfiehlt es sich, schrittweise vorzugehen und mit Continuous Integration zu beginnen. Die genauen Phasen der Pipeline und die logischen Schritte zum Auslösen der einzelnen Phasen hängen von Ihrem Produkt und Ihrer Organisation ab.

Wenn Sie sich für eine CI/CD-Plattform entscheiden, die eine flexible Anpassung der Pipeline an Ihre Anforderungen ermöglicht und trotzdem einfach zu verwalten ist, können Sie einen zuverlässigen Releaseprozess aufbauen und die Qualität Ihrer Software verbessern.