Stateless CI-Server mit Concourse

Keine Kommentare

Continuous Integration ist einer der wichtigsten Bestandteile der agilen Software-Entwicklung und in den meisten Teams so selbstverständlich wie Versionskontrolle geworden. Trotz der alten und bewährten Werkzeuge wie Jenkins, Bamboo oder TeamCity, ist es immer noch eine große Herausforderung, die Komplexität einer Continuous-Integration-Umgebung zu beherrschen. Das Entwicklungsteam aus der Software-Schmiede Pivotal hat sich vorgenommen, ein neues CI-System mit einer modernen Architektur und zukunftssicheren Technologien aufzubauen. Was vor drei Jahren mit einem eher unbekannten Open-Source-Projekt startete, ist nun eine reife Technologie mit stabilen Release-Zyklen geworden. In diesem Blog stelle ich die Kernkonzepte und die Architektur von Concourse CI vor.

Warum brauchen wir ein neues CI-System?

Einer der wichtigsten Gründe warum ein neues Werkzeug vorteilhaft sein kann, ist die Unabhängigkeit von alten Anforderungen, die über viele Jahre gewachsen sind und immer noch erfüllt werden müssen. Solche Systeme sind meistens stabil und zuverlässig, haben jedoch die Schwierigkeit, sich an die schnelle technologische Entwicklung anzupassen. Die Komplexität eines Build-Servers hat über die letzten Jahre enorm zugenommen, so dass immer mehr Plugins und Konfigurationen verwaltet werden müssen. Weiterhin besteht oft eine Lücke zwischen den Builds auf einem Entwicklungsrechner und auf einem CI-System. Denn die Konfiguration des CI-Servers muss mit jedem Entwicklungsrechner übereinstimmen. Durch zunehmende Komplexität der Build- und Auslieferungsprozesse hat sich auch der Aufbau der Jobs verändert:  von simplen Build- und Test-Jobs bis zu komplexen und langläufigen Pipelines, die den gesamten Prozess von Compile bis Deployment über mehrere Stages wie Integrationstest, Quality-Gates und Blue/Green-Deployments abdecken. Diese Komplexität hemmt eine schnelle Adaption neuer Technologien in bestehenden CI-Systemen, da es sehr oft umständlich ist alte Strukturen aufzubrechen und etwas Neues einzuführen.

Kernkonzepte von Concourse

In Concourse CI wurden neue Technologien und moderne Architekturen bereits beim Design berücksichtigt, wodurch das Plugin-Management und Konfiguration des CI-Systems vereinfacht wird. Das System basiert auf vier grundlegenden Konzepten: Resources, Tasks, Jobs und Pipelines.

Unter einer Resource versteht man eine Entität, die drei Merkmale erfüllen muss:

  • Eine Resource ist versionierbar.
  • Eine Resource wird aus einem anderen System ausgelesen.
  • Eine Resource wird in ein anderes System geschrieben.

Durch diese Abstraktion können viele verschiedene Resources für das CI-System definiert werden, beispielsweise Git Repository, S3 Bucket, Docker Image, NPM Paket oder sogar die Zeit selbst. Resources werden als Inputs oder Outputs für Tasks und Jobs verwendet. Entscheidend ist, dass die Konfiguration für das Lesen und das Schreiben der Resources nicht innerhalb des CI-Systems definiert wird. Concourse stellt viele Adapter für Resources zur Verfügung und lässt dabei die Freiheit eigene Resource-Adapter zu schreiben.

Ein Task ist eine Ausführung eines bestimmten Build-Skripts. Es entspricht dem bekannten Konzept von Steps innerhalb eines Jobs in Jenkins – mit dem entscheidenen Unterschied, dass alle Tasks immer in einem Docker-Container ausgeführt werden. Dadurch wird sichergestellt, dass alle benötigten Abhängigkeiten und Konfigurationen gekapselt und vom CI-System entkoppelt sind. Das Konzept wurde in ähnlicher Form von meinem Kollegen Tobias Flohre in einem Blog-Artikel diskutiert.

Ein Job besteht aus mehreren Tasks und definierten Inputs und Outputs, welche wiederum Resources sind. Wenn sich die Input-Resources ändern, wird der Job ausgelöst, und es werden neue Output-Resources erstellt. Ein Job innerhalb des CI-Systems ist dadurch stateless. In Concourse ist es gar nicht möglich Abhängigkeiten zum CI-Server innerhalb der Jobs aufzubauen. Dadurch kann ein Job auf einem beliebigen Concourse-System ausgeführt werden und wird exakt gleiche Ergebnisse produzieren.

Resources, Tasks und Jobs lassen sich zu einer Pipeline orchestrieren. Änderungen der Input-Resources lösen bestimmte Jobs aus, die wiederum neue Output-Resources erzeugen und dabei andere Jobs auslösen. Mit dieser Verkettung lassen sich beliebig komplexe Strukturen für Auslieferungsprozesse abbilden, wobei Jobs zusätzlich parallelisiert oder aggregiert werden können.

Eine weitere Stärke von Concourse ist die Benutzeroberfläche, in der die Pipelines, Jobs und Resources minimalistisch dargestellt werden. Aufgrund der zunehmenden Komplexität der Build-Pipelines ist es in anderen Systemen oft schwierig, die wesentliche Information möglichst schnell zu finden. Als Beispiel kann die Pipeline von Concourse selbst betrachtet werden.

Abbildung 1: CI-Pipeline von Concourse CI

Die Übersicht bietet eine gesamte Darstellung der Pipeline auf einen Blick und ermöglicht eine schnelle Navigation zu den Details eines Jobs oder Resources. Die grünen Blöcke zeigen die jeweiligen Jobs und ihre Input- und Output-Resourcen und werden je nach Dauer der Jobs skaliert dargestellt. Mit diesem Konzept wird der Aufbau und der Betrieb der Pipeline offen und präzise kommuniziert. Das Wissen über den Auslieferungsprozess sowohl innerhalb eines Entwicklungsteams als auch zwischen verschiedenen Teams kann besser verteilt werden, ohne sich in den Details zu verlieren.

Architektur

In Concourse haben viele Begriffe einen Bezug zur Luftfahrt, wodurch die Architektur und die Zusammensetzung der einzelnen Komponenten besser veranschaulicht wird. Das System ist in mehrere Module unterteilt: ATC, TSA, Workers und Fly. Die Architektur sieht wie folgt aus:


Abbildung 2: Concourse-CI-Architektur

Air Traffic Control (ATC) ist die zentrale Instanz des Systems und bietet eine Benutzeroberfläche zur Darstellung und eine REST API für das Management der Pipelines und deren Ausführung. Transport Security Administration (TSA) ist eine Schnittstelle zwischen ATC und den Workern, wobei die Worker lediglich registriert und an ATC weiter geleitet werden. Die Worker sind unabhängige und einheitliche Server, die als Container für die Ausführung der Jobs verwendet werden. Sie sind stateless, benötigen keine zusätzliche Konfiguration und registrieren sich am TSA als mögliche Laufzeitumgebung für die Pipeline. Wann, wo und wie ein Worker zum Einsatz kommt, wird von ATC gesteuert. Für das optimale Scheduling der Worker melden diese ihren Zustand periodisch an ATC.

Um die Pipelines innerhalb des ATC zu verwalten wird das CLI-Tool Fly verwendet. In Concourse gibt es keine Möglichkeit, eine Pipeline über die Benutzeroberfläche zu erstellen; alle Konfigurationen müssen mit Fly durchgeführt werden. Was im ersten Moment nach einem fehlendem Feature klingt, ist eine bewusste Designentscheidung. Denn oft sind die Entwickler dazu geneigt den Zustand des CI-Systems manuell in der Benutzeroberfläche zu verändern. Diese Änderungen werden über längeren Zeitraum oft vergessen oder nicht dokumentiert. Mit Fly lassen sich Pipelines ebenfalls lokal ausführen, was die Entwicklung der Pipeline stark vereinfacht und die gleiche Funktionalität auf einem CI-Server garantiert. In weiteren Blog-Artikeln werde ich auf die Architektur und das Pipeline-Management in Concourse detailliert eingehen und mögliche Einsatzszenarien diskutieren.

Fazit

Mit Concourse werden viele alte Probleme eines CI-Servers angegangen und elegant gelöst. Die Jobs werden in Docker-Containern ausgeführt, was den Konfigurationsaufwand des CI-Servers reduziert und die Reproduzierbarkeit der Builds garantiert. Die Abstraktion durch Resources, Tasks und Jobs bietet Spielraum für viele Technologien und Orchestrierung komplexer Build-Prozesse. Entwicklungsteams haben die Autonomie über ihre Pipeline und können das Wissen über den Auslieferungsprozess mit einer aufgeräumten Oberfläche besser verteilen.

Komplexe Konfiguration eines CI-Servers ist oft ein Hindernis für kleine Teams, um mit Continuous Integration zu starten. Ein CI-Server wird oft von mehreren Teams mit verschiedenen Plugins und Umgebungsvariablen überladen – das reduziert die Flexibilität der Entwicklung und erhöht den Wartungsaufwand. Concourse CI versucht dieses Problem durch Abstraktion und Container-Einstatz zu vermeiden. Letztlich muss jedes Team für sich selbst entscheiden, ob der Wechsel zu einem neuen CI-System Mehrwert bringt. In der Regel ist die Technologie allein nicht der entscheidende Faktor für den Erfolg eines Projekts.

Weitere Inhalte zu Continuous Delivery

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.