Twelve-Factor App

Lesezeit: 7 Minuten

Die Twelve-Factor App ist eine Methode um Software as a Service (SaaS) zu bauen. Sie eignet sich grundsätzlich auch als Richtlinie zum Entwerfen von Microservices oder Cloud-basierten Anwendungen (cloud native) bzw. Software, die nach dem DevOps-Ansatz entwickelt und betrieben wird.

Die Methode zielt unter anderem darauf ab, Software zu entwickeln, die schnell deploybar, skalierbar, ersetzbar, portierbar und unabhängig von der Programmiersprache integrierbar ist.

Die zwölf Faktoren

Das Manifest zur Twelve-Factor App ist um 2011 herum bei Heroku entstanden und ursprünglich von Adam Wiggins veröffentlicht worden. Es handelt sich um eine Sammlung von Empfehlungen unterteilt in zwölf Faktoren, die für die Entwicklung und das Betreiben einer SaaS-Lösung wichtig sind.

Als App wird dabei eine deploybare Komponente aufgefasst. In einem verteilten System mit vielen verschiedenen Komponenten kann jede Komponente für sich die 12 Faktoren erfüllen.

Zu den 12 Faktoren führe ich im Folgenden stichpunktartig die aus meiner Sicht wesentlichen Kernaussagen auf. Für ein umfassenderes Bild verweise ich auf die am Ende des Blogbeitrags verlinkte Webpräsenz der Twelve-Factor App.

1. Codebase

  • Die Codebase wird über ein Versionsmanagementsystem verwaltet
  • Eine App hat genau eine Codebase
  • In einer Codebase ist genau eine App
  • Gemeinsamer Code kann als Bibliothek in eine eigene Codebase ausgelagert und als Abhängigkeit in die App geladen werden

2. Abhängigkeiten

Abhängigkeiten sind Bibliotheken oder Programme außerhalb der Codebase der App. Es kann sich bei abhängigen Bibliotheken sowohl um eigenen Code handeln, der von mehreren Apps verwendet wird, oder auch um Drittanbieter-Bibliotheken, mit denen im Code der App interagiert wird. Ruft die App Systemprogramme wie z.B. curl auf, so werden auch diese als Abhängigkeiten verstanden.

  • Alle Abhängigkeiten einer App werden explizit deklariert
  • Durch Isolation wird verhindert, dass es zu impliziten Abhängigkeiten kommt
  • Verwendete Systemwerkzeuge liefert die App mit

3. Konfiguration

Als Konfiguration wird die System- und Anwendungskonfiguration verstanden, z.B. Verbindungsinformationen für unterstützende Dienste wie Datenbanken und Message Broker, Logging, Tuning (Threadpools etc.) oder auch allgemeine Anwendungsparameter.

Nicht unter diesen Begriff fällt die interne Konfiguration der App, die über alle Umgebungen und Deployments hinweg gleich bleibt, wie etwa das Routing einer Single Page Application oder die REST-Endpunkte eines Backend-Services.

  • Konfiguration wird strikt vom Code getrennt und nicht in die Codebase eingecheckt
  • Konfiguration wird in Umgebungsvariablen gespeichert
  • Konfiguration kann für jedes Deployment unabhängig von der Codebase verwaltet werden

4. Unterstützende Dienste

Als unterstützende Dienste werden alle externen Dienste und Systeme bezeichnet, mit denen die App interagiert. Darunter fallen Datenspeicher, Mailserver, externe Caches, APIs unterschiedlichster Dienste wie Wikipedia oder OpenStreetMap.

  • Die App unterscheidet nicht zwischen einem bestimmten Dienst und anderen Diensten, die die gleiche Sprache (Protokoll, API) sprechen und ist damit möglichst lose an diesen Dienst gekoppelt
  • Unterstützte Dienste lassen sich rein über die Konfiguration für ein Deployment austauschen

5. Build, release, run

In der Build-Phase wird der Code der App inklusive Abhängigkeiten und Assets in ein ausführbares Artefakt übersetzt. In der Release-Phase wird das Artefakt mit der zum Deployment dazugehörigen Konfiguration verpackt. In der Run-Phase kann das Release in der Ausführungsumgebung gestartet werden.

  • Die drei Phasen build, release und run sind strikt voneinander getrennt
  • Builds werden durch das Einchecken neuen Codes durch Entwickler angestoßen
  • Releases sind unveränderlich und werden nicht gelöscht
  • Runs sollten möglichst einfach und statisch gehalten sein und im Optimalfall einfach nur das Release ausführen, da sie in der Ausführungsumgebung häufig automatisiert gestartet werden, etwa aufgrund dynamischer Skalierung oder Neustarts in der darunterliegenden Infrastruktur

6. Prozesse

Als Prozess wird eine ausgeführte Instanz der App verstanden.

  • Die App ist zustandslos – alle Daten werden in unterstützenden Diensten gespeichert
  • Wird die App in mehreren Prozessen gestartet, so kennen diese sich untereinander nicht und haben keinen gemeinsamen Zustand
  • Während einer Transaktion können Informationen zwischengespeichert werden, die App geht allerdings nie davon aus, dass diese Informationen bei einem zukünftigen Request weiterhin verfügbar sind oder dass dieser Request von der gleichen Instanz der App bedient wird

7. Bindung an Ports

  • Die App ist vollständig autark und nicht auf externe Dienste wie einen Webserver, der sie einbettet, angewiesen
  • Bietet die App eine protokollspezifische API über einen Port an, so bringt sie diese Funktionalität selbst mit, bindet sich an diesen Port und reagiert auf eingehende Anfragen an diesem Port

8. Nebenläufigkeiten

  • Nebenläufige Prozesse bearbeiten unterschiedliche Aufgaben wie die Entgegennahme von HTTP-Requests oder die Abarbeitung von Aufgaben aus einer Queue
  • Nebenläufigkeiten orientieren sich am Unix-Prozess-Modell für Service Daemons
  • Nebenläufigkeiten verlassen sich auf den Prozessmanager des Betriebssystems
  • Nebenläufigkeiten auf Prozessebene ermöglichen eine horizontale Skalierung gegenüber der Abbildung innerhalb einer Laufzeit-VM, die nur vertikal skalieren kann
  • Nebenläufigkeiten dürfen intern über asynchrone Mechanismen und Threading organisiert sein

9. Einweggebrauch

  • Die Prozesse einer App können schnell gestartet werden, optimalerweise sind sie in wenigen Sekunden einsatzbereit
  • Die Prozesse einer App können schnell und gefahrlos gestoppt (weggeworfen) werden, wenn sie ein SIGTERM-Signal erhalten
  • Die Prozesse fahren geregelt herunter, indem sie noch laufende Aufgaben zuende abarbeiten oder abgeben (z.B. zurück in eine Queue stellen)
  • Im Fall eines plötzlichen Prozesstods wird möglicher Schaden so gut es geht abgewendet, indem z.B. im Fall von Worker-Prozessen ein Backend wie Beanstalkd Jobs in die Queue zurückgibt, wenn Clients die Verbindung beenden

10. Dev-Prod-Vergleichbarkeit

  • Die Zeit zwischen Deployments sollte möglichst kurz sein
  • Code-Entwickler und Code-Deployer sollten die gleichen Leute sein (DevOps)
  • Entwicklungs- und Produktions-Umgebung sollten so ähnlich wie möglich sein
  • Es sollten die gleichen unterstützenden Dienste in Entwicklung und Produktion verwendet werden

11. Logs

  • Jeder Prozess schreibt seine Logs nach stdout

12. Admin-Prozesse

Admin-Prozesse werden als einmalige administrative oder Wartungsaufgaben verstanden.

  • Admin-Prozesse laufen in der gleichen Umgebung, wie die anderen Prozesse der App
  • Admin-Prozesse laufen gegen ein Release und verwenden dieselbe Codebase und Konfiguration wie jeder Prozess, der auf diesem Release basiert
  • Administrationscode ist Teil der Codebase und wird im Release mit ausgeliefert
  • Admin-Prozesse isolieren Abhängigkeiten auf die gleiche Art und Weise wie die anderen Prozesse
- Manifest zur Twelve-Factor App