8 Design und Entwicklung von Microservices 1

8.1 Die 12-Factor-App-Prinzipien

Die 12-Factor-App-Methodik repräsentiert einen der einflussreichsten Ansätze für die Entwicklung moderner, cloud-nativer Anwendungen. Diese Prinzipien wurden ursprünglich von den Entwicklern bei Heroku formuliert, basierend auf ihren Erfahrungen mit der Entwicklung, dem Betrieb und der Skalierung von tausenden Anwendungen auf ihrer Plattform. Obwohl nicht explizit für Microservices konzipiert, hat sich dieser Ansatz als außerordentlich wertvoll für die Gestaltung robuster, wartbarer und skalierbarer Microservices erwiesen. Im Folgenden erläutern wir diese Prinzipien im Kontext der Microservices-Architektur und betrachten, wie sie die Entwicklung qualitativ hochwertiger Services unterstützen.

8.1.1 Fundamentale Konzepte der 12-Factor-Methodik

Die 12-Factor-Methodik adressiert eine Vielzahl an Herausforderungen, die bei der Entwicklung moderner Anwendungen auftreten. Sie ist besonders relevant für Microservices, da sie explizit auf die Bedürfnisse verteilter, in der Cloud betriebener Software eingeht. Die Prinzipien fördern die Entwicklung von Services, die:

Diese Eigenschaften entsprechen genau den Anforderungen, die an gut gestaltete Microservices gestellt werden. Betrachten wir nun die einzelnen Faktoren im Detail.

8.1.2 Die zwölf Faktoren im Einzelnen

8.1.2.1 Codebase: Eine versionsverwaltete Codebase, viele Deployments

Prinzip: Jeder Microservice sollte genau eine dedizierte, versionsverwaltete Codebase haben, die für verschiedene Umgebungen (Entwicklung, Staging, Produktion) genutzt wird.

Implementierung in Microservices:

Bedeutung für Microservices: Dieses Prinzip unterstützt die unabhängige Entwicklung und Deployment-Fähigkeit einzelner Services. Während in monolithischen Anwendungen oft mehrere logische Komponenten in einer Codebase existieren, erfordert der Microservices-Ansatz eine strikte Trennung. Dies fördert:

Ein typisches Anti-Pattern wäre die Verwendung eines “Monorepos” ohne klare modulare Grenzen zwischen Services oder, noch problematischer, die Verteilung eines logischen Services auf mehrere Repositories.

8.1.2.2 Abhängigkeiten: Abhängigkeiten explizit deklarieren und isolieren

Prinzip: Ein Microservice deklariert alle seine Abhängigkeiten explizit und vollständig durch ein Abhängigkeitsdeklarationssystem.

Implementierung in Microservices:

Bedeutung für Microservices: In einer Microservices-Landschaft mit dutzenden oder hunderten Services ist die explizite Deklaration von Abhängigkeiten entscheidend für:

Ein häufiges Problem in nicht 12-Factor-konformen Systemen ist das “es funktioniert auf meinem Rechner”-Syndrom, das durch implizite Systemabhängigkeiten entsteht. Dieses Problem wird in Microservices-Architekturen durch die große Anzahl beteiligter Entwickler und Services noch verschärft.

8.1.2.3 Konfiguration: Konfiguration in der Umgebung speichern

Prinzip: Die Konfiguration eines Services sollte strikt vom Code getrennt und in der Umgebung gespeichert werden.

Implementierung in Microservices:

Bedeutung für Microservices: Die klare Trennung von Code und Konfiguration ermöglicht:

Dies ist besonders wichtig in Microservices-Umgebungen, wo Services zwischen Entwicklung, Test und Produktion migrieren und oft unterschiedliche Instanzen des gleichen Services unterschiedlich konfiguriert werden müssen (z.B. mit verschiedenen Ressourcenlimits).

Ein typisches Anti-Pattern ist die Verwendung von umgebungsspezifischen Konfigurationsdateien, die in der Codebasis gespeichert werden, oder schlimmer noch, hart codierte Konfigurationswerte.

8.1.2.4 Backing Services: Unterstützende Dienste als angehängte Ressourcen behandeln

Prinzip: Alle externen Services (Datenbanken, Messaging-Systeme, Cache-Dienste) werden als angehängte Ressourcen behandelt und über Konfiguration verbunden.

Implementierung in Microservices:

Bedeutung für Microservices: In einer Microservices-Architektur interagieren Services ständig mit anderen Services und Infrastrukturkomponenten. Die Behandlung all dieser Komponenten als austauschbare Ressourcen ermöglicht:

Dieses Prinzip ist eng mit dem Konfigurationsprinzip verbunden und unterstützt die lose Kopplung zwischen Services, eine Kernvoraussetzung für erfolgreiche Microservices-Architekturen.

8.1.2.5 Build, Release, Run: Buildphase und Ausführung strikt trennen

Prinzip: Die Softwarelieferung erfolgt in drei klar getrennten Phasen: Build (Kompilierung), Release (Kombination mit Konfiguration) und Run (Ausführung).

Implementierung in Microservices:

Bedeutung für Microservices: Die strikte Trennung dieser Phasen unterstützt:

In einer Microservices-Landschaft mit Dutzenden oder Hunderten von Services und häufigen Deployments ist diese Automatisierung und Nachvollziehbarkeit nicht nur wünschenswert, sondern notwendig. Ohne sie wird das Betreiben einer komplexen Microservices-Architektur schnell unbeherrschbar.

8.1.2.6 Prozesse: Anwendungen als zustandslose Prozesse ausführen

Prinzip: Services werden als zustandslose Prozesse ausgeführt, die keinen persistenten Zustand zwischen Anfragen speichern.

Implementierung in Microservices:

Bedeutung für Microservices: Zustandslosigkeit ist ein Kernprinzip von Microservices, das:

Dieses Prinzip steht im Einklang mit der Diskussion über stateful vs. stateless Services, die wir bereits betrachtet haben. Während nicht alle Services vollständig zustandslos sein können, sollte Zustandslosigkeit als Idealziel angestrebt werden, von dem nur abgewichen wird, wenn die Geschäftsanforderungen dies unbedingt erfordern.

8.1.2.7 Portbindung: Services über Ports exportieren

Prinzip: Ein Service ist vollständig eigenständig und exportiert seine Funktionalität durch Bindung an einen Port, ohne Abhängigkeit von einem externen Webserver.

Implementierung in Microservices:

Bedeutung für Microservices: Self-Contained Services sind ein zentrales Konzept in Microservices-Architekturen. Sie ermöglichen:

Dieses Prinzip unterstützt die Autonomie von Services und Teams, da es die Abhängigkeit von zentralisierten Webserver-Infrastrukturen reduziert und die Verantwortung für den vollständigen Service-Stack dem Entwicklungsteam überträgt.

8.1.2.8 Nebenläufigkeit: Durch den Prozessmodell skalieren

Prinzip: Anwendungen sollten horizontal skalieren, indem sie das Prozessmodell nutzen und zusätzliche Instanzen starten, anstatt vertikal durch Hinzufügen von Ressourcen zu einer einzelnen Instanz zu skalieren.

Implementierung in Microservices:

Bedeutung für Microservices: Die horizontale Skalierbarkeit ist ein zentraler Vorteil von Microservices und wird durch dieses Prinzip adressiert:

In der Praxis bedeutet dies, dass Microservices so gestaltet werden sollten, dass sie schnell starten, wenig Ressourcen benötigen und parallel arbeiten können. Dies steht im Gegensatz zu monolithischen Ansätzen, bei denen oft die vertikale Skalierung (größere Server) die einzige praktikable Option ist.

8.1.2.9 Wegwerfbarkeit: Maximiere Robustheit durch schnelles Starten und graceful Shutdown

Prinzip: Services sollten schnell starten, sauber herunterfahren und fehlerfrei ersetzt werden können.

Implementierung in Microservices:

Bedeutung für Microservices: Die Wegwerfbarkeit von Service-Instanzen ist entscheidend für:

Dieses Prinzip unterstützt einen der Hauptvorteile von Microservices: die Fähigkeit, einzelne Komponenten unabhängig zu aktualisieren und zu skalieren, ohne das Gesamtsystem zu beeinträchtigen. Es ermöglicht auch innovative Deployment-Techniken wie Canary Releases oder Blue-Green-Deployments.

8.1.2.10 Dev/Prod-Parität: Entwicklung, Staging und Produktion so ähnlich wie möglich halten

Prinzip: Die Entwicklungsumgebung sollte der Produktionsumgebung so ähnlich wie möglich sein, um “es funktioniert auf meinem Rechner”-Probleme zu vermeiden.

Implementierung in Microservices:

Bedeutung für Microservices: In einer komplexen Microservices-Landschaft ist die Umgebungsparität besonders wichtig:

Ein wesentlicher Aspekt dieses Prinzips ist die Verwendung der gleichen Backing Services (wie Datenbanken oder Message Broker) in allen Umgebungen, wenn auch möglicherweise in unterschiedlichen Skalierungen oder Konfigurationen.

8.1.2.11 Logs: Logs als Ereignisströme behandeln

Prinzip: Logs sollten als Ereignisströme behandelt werden, die in die Standardausgabe geschrieben und von der Ausführungsumgebung erfasst und verarbeitet werden.

Implementierung in Microservices:

Bedeutung für Microservices: In einer verteilten Architektur ist effektives Logging entscheidend für:

Dieses Prinzip steht im Einklang mit dem breiteren Konzept der Observability, das in Microservices-Architekturen essenziell ist. Durch die Behandlung von Logs als Streams werden sie zu einem integralen Bestandteil des Monitoring- und Beobachtungsökosystems.

8.1.2.12 Admin-Prozesse: Admin/Management-Aufgaben als einmalige Prozesse ausführen

Prinzip: Administrative oder Wartungsaufgaben sollten als einmalige Prozesse im gleichen Umfeld wie die reguläre Anwendung ausgeführt werden.

Implementierung in Microservices:

Bedeutung für Microservices: In einer Microservices-Umgebung sind administrative Aufgaben besonders herausfordernd, da sie oft serviceübergreifend sind und konsistente Umgebungen erfordern:

Durch die Behandlung dieser Aufgaben als reguläre Codeeinheiten, die die gleiche Pipeline und Infrastruktur nutzen, werden sie reproduzierbar, testbar und versionierbar.

8.1.3 Die Relevanz der 12 Faktoren für Microservices

Die 12-Factor-Methodik ist besonders relevant für Microservices aus folgenden Gründen:

1. Unabhängigkeit und Autonomie: Die Prinzipien fördern die Unabhängigkeit einzelner Services, was eine grundlegende Anforderung für Microservices ist.

2. Operationelle Exzellenz: Viele der Faktoren adressieren operationelle Aspekte wie Deployment, Skalierung und Monitoring, die in der verteilten Natur von Microservices besonders herausfordernd sind.

3. Entwicklungsgeschwindigkeit: Durch klare Richtlinien und Automatisierung wird die Entwicklung beschleunigt, was einen der Hauptvorteile von Microservices unterstützt.

4. Skalierbarkeit: Die Prinzipien unterstützen explizit horizontale Skalierung und dynamische Ressourcenzuweisung, was für Microservices essenziell ist.

5. Resilienz: Aspekte wie Wegwerfbarkeit, Prozessisolation und klare Konfiguration tragen zur Robustheit des Gesamtsystems bei.

Es ist wichtig zu verstehen, dass die 12-Factor-App-Methodik keine Blaupause für Microservices-Architekturen ist, sondern ein Satz von Prinzipien, die die Entwicklung cloud-nativer Anwendungen im Allgemeinen unterstützen. Für Microservices sind sie besonders relevant, da sie viele der spezifischen Herausforderungen dieser Architektur adressieren.

8.1.4 Über die 12 Faktoren hinaus: Moderne Erweiterungen

Seit der ursprünglichen Formulierung der 12 Faktoren hat sich die Landschaft der Cloud-nativen Anwendungsentwicklung weiterentwickelt. Einige zusätzliche Prinzipien, die oft als Erweiterung der ursprünglichen 12 Faktoren betrachtet werden, sind:

API-First: Services sollten ihre Funktionalität über klar definierte APIs exponieren, die als Vertrag zwischen Produzenten und Konsumenten dienen.

Telemetrie: Über Logging hinaus sollten Services umfassende Metriken, Traces und Gesundheitsindikatoren bereitstellen.

Sicherheit: Sicherheitsaspekte sollten von Anfang an in den Entwicklungsprozess integriert werden (Security by Design).

Automatisierte Tests: Umfassende automatisierte Tests auf verschiedenen Ebenen (Unit, Integration, End-to-End) sind für die Qualitätssicherung in komplexen Microservices-Landschaften unerlässlich.

Diese Erweiterungen reflektieren die Evolution der Branche und die zunehmende Reife von Microservices-Praktiken.

8.1.5 Praktische Umsetzung: Von Prinzipien zu Praktiken

Die Umsetzung der 12-Factor-Prinzipien in praktische Microservices-Implementierungen erfordert sowohl technologische als auch organisatorische Maßnahmen:

Technologische Unterstützung:

Organisatorische Praktiken:

Die erfolgreiche Implementierung der 12-Factor-Prinzipien erfordert eine holistische Betrachtung, die Technologie, Prozesse und Menschen einbezieht. Sie ist kein einmaliges Projekt, sondern eine kontinuierliche Reise zur Verbesserung der Anwendungsentwicklung und des Betriebs.

8.1.6 Die 12 Faktoren als Leitprinzipien

Die 12-Factor-App-Methodik bietet einen wertvollen Rahmen für die Entwicklung moderner, cloud-nativer Microservices. Sie adressiert viele der spezifischen Herausforderungen, die mit verteilten Architekturen verbunden sind, und fördert Praktiken, die zu robusten, skalierbaren und wartbaren Systemen führen.

Es ist jedoch wichtig zu verstehen, dass diese Prinzipien als Leitlinien und nicht als strenge Regeln betrachtet werden sollten. Jede Organisation und jedes Projekt hat spezifische Anforderungen und Einschränkungen, die die Anwendung dieser Prinzipien beeinflussen können. Die Kunst liegt darin, die richtige Balance zwischen der Befolgung dieser bewährten Praktiken und der Anpassung an die spezifischen Bedürfnisse und Kontexte zu finden.

Letztendlich ist die 12-Factor-Methodik ein Werkzeug, das Teams dabei unterstützen kann, bessere Microservices zu bauen – aber wie bei jedem Werkzeug liegt der Wert in seiner sachkundigen und angemessenen Anwendung.