Microservices im Zusammenspiel mit Continuous Delivery, Teil 1 – die Theorie

Architektur/Methoden  –  2 Kommentare

Durch Continuous Delivery wird Software viel öfter und zuverlässiger in Produktion gebracht. Wesentliches Werkzeug dafür ist eine Continuous Delivery Pipeline. Auf den ersten Blick scheint dazu nur eine Optimierung der Prozesse nötig, aber moderne Architekturansätze wie Microservices spielen ideal mit Continuous Delivery zusammen.

Zentrum von Continuous Delivery [1] [2] ist ein Deployment-Prozess, wie ihn unten stehende Abbildung zeigt: Die Releases werden in einer Pipeline immer weiter propagiert. Letztere besteht aus einer Reihe von Stadien. Während der anfänglichen Commit-Phase kompiliert das System die Software, führt Unit-Tests aus und unterzieht den Code einer statischen Analyse.

Im Anschluss prüfen die Akzeptanztests die Software auf fachliche Korrektheit. Die Tests sind automatisiert, sodass sie reproduzierbar sind und jeder einzelne Lauf keinen besonderen Aufwand darstellt. Bei den Kapazitätstests lässt sich die Software danach darauf untersuchen, ob sie bei der
in Produktion zu erwartenden Last die notwendige Performance liefert – auch diese Tests sind automatisiert. Fachliche Experten begutachten schließlich bei den explorativen Tests neue Features genauer. Am Ende lässt sich die Software der Produktion übergeben.

Eine klassische Continuous Delivery Pipeline

Die Pipeline wird sehr oft durchlaufen, durchaus auch mehrere Male pro Tag. Da solch ein Vorgehen mit manuellen Tests zeitlich und kostengünstig wohl kaum umsetzbar wäre, ist eine weitgehende Automatisierung die Grundlage der Pipeline.

Continuous Delivery ist eine Erweiterung von Continuous Integration: Letztere stellt sicher, dass Software sich jederzeit kompilieren lässt und alle Änderungen der Entwickler regelmäßig integriert werden. Sie ist weitgehend mit der Commit-Phase in Continuous Delivery deckungsgleich und erweitert den kontinuierlichen Prozess so bis zur Auslieferung in Produktivbetrieb.

Die Automatisierung macht dabei auch vor der Installation der Software nicht halt: Da die Software getestet werden muss und schließlich in Produktion gebracht wird, sind dazu der Installationsprozess und die Konfiguration der Server zu automatisieren.

Das wesentliche Ziel von Continuous Delivery ist schnelles Feedback. Damit steht das Verfahren in der Tradition agiler Prozesse: Sie setzen auf das Deployment in Produktion und das Feedback vom Kunden, um so neue Anforderungen zu ermitteln. Continuous Delivery kann die Softwareverteilung im Produktivbetrieb beschleunigen. Dank der erwähnten Pipeline wird nach jedem Commit eines Entwicklers untersucht, ob der Commit neue fachliche Fehler oder ein unzureichendes Verhalten ergeben hat. Ohne diese Pipeline müssten Programmierer dazu die entsprechenden Testphasen abwarten, was durchaus Wochen oder Monate dauern kann. In der Zwischenzeit hat sich die Software oft so umfassend geändert, dass es schwierig ist, die für einen Fehler verantwortliche Änderung zu identifizieren.

Das Feedback lässt sich sogar noch weiter beschleunigen, indem man zuerst alle fachlichen Features für einfache Fälle testet, bevor man sich an komplexere Fälle begibt. Beispielsweise lässt sich zunächst überprüfen, ob eine Bestellung und die Registrierung eines neuen Kunden grundsätzlich funktionieren, bevor man die Features mit all ihren Regeln und Sonderfällen im Detail testet. Wenn Unternehmen die Reihenfolge der Tests so ändern, lassen sich fundamentale Probleme mit einem Feature schneller identifizieren, als wenn jedes sofort in voller Tiefe getestet würde.

Continuous Delivery ist also ein Vorgehen der Softwareentwicklung, das Techniken in den Mittelpunkt stellt, bei denen es vor allem um das Bauen und das Testen von Software geht. Eigentlich sollte das keinen Einfluss auf die Architektur haben – denn der Aufbau der Software ist von solchen Aspekten unabhängig.

In der Wirklichkeit hat Continuous Delivery jedoch durchaus Einfluss auf die Architektur. Wenn es gewünscht ist, Software jederzeit auszuliefern, ist das beim Umsetzen neuer Features zu beachten. Oft werden in der Versionskontrolle die Änderungen für ein neues Feature in einem eigenen Branch angelegt. Erst wenn es in Produktion gehen soll, werden die Änderungen in den Haupt-Branch übernommen. Anschließend kann die neue Funktion live gehen.

Das widerspricht der grundlegenden Idee von Continuous Integration: Statt ständig alle Änderungen zu integrieren, werden die Änderungen für ein neues Feature getrennt und erst später mit den anderen – beispielsweise für andere Features – integriert. Erst bei der Integration des Feature-Branches treten die Probleme auf, die sich durch Inkompatibilitäten und Fehler der verschiedenen Entwicklungszweige ergeben.

Wenn aber alle Änderungen für alle Features in der Versionskontrolle landen und das Ziel ist, den Code möglichst oft auszuliefern – wie lässt sich dann verhindern, dass halbfertige Features plötzlich im Produktivbetrieb sind? Die Lösung für dieses Problem sind Feature Toggles. Sie ermöglichen das Aktivieren und Deaktivieren der Funktionen. So lässt sich ein Feature entwickeln, ohne dass es in Produktion gleich aktiv ist. Das fügt zur Architektur eine weitere Dimension hinzu: Für jede Funktion gibt es einen eigenen Feature Toggle. Ebenso ist es aber auch möglich, nur ein Toggle zu implementieren, der zwischen Entwicklungs- und Produktivumgebungen unterscheidet. Der Code jedes Features muss dann entscheiden, ob es in Produktion aktiv sein sollen oder nicht. So kann das Feature zunächst nur in Test-Umgebungen aktiv sein, bevor es auch für den Produktivbetrieb aktiviert wird.

Und es kann auch sinnvoll sein, sie aus anderen Gründen zu deaktivieren: Wenn beispielsweise das System nicht bereitsteht, das die Verfügbarkeit von Produkten überprüft, lassen sich dieses Feature deaktivieren und stattdessen bestimmte Standardeinstellungen nutzen. Dann sind nicht mehr genutzte Toggles aus den Konfigurationen und dem Code zu entfernen, damit der Code auch langfristig wartbar bleibt.