Gibt es im Jahr 2019 eine Alternative zu Jenkins? Was ist mit Gitlab CI?
Wir wir schon in früheren DevOps Posts berichtet haben, nutzen wir Jenkins hauptsächlich für unsere alltäglichen CI und CD Tasks. Jenkins ist aktuell immer noch Industriestandard. Es gibt Berge von Resourcen Tutorials und Stackoverflow Threads über (so gut wie) jedes denkbare Problem. “So gut wie” heißt, dass man manchmal doch tief in den Java Code eintauchen und herausfinden muss, was zum Teufel das XYZ Plugin eigentlich genau macht. In solchen Fällen kann es dann auch richtig anstrengend werden. Aber genug gemeckert.
Warum also experimentieren wir mit einem anderen CI/CD Tool wenn wir eigentlich ganz zufrieden sind mit Jenkins? Das ist schlicht die Natur von Technologie Freaks. Das ist es, was die Welt voranbringt. Und das ist es, was wir sind: Technologie Begeisterte (Freaks).
Kurz zur Historie
Unsere Jenkins Tool Chain ist um die shared Jenkins Library herum aufgebaut mit Tausenden Zeilen coolen Codes. Der Hauptzweck ist, dass man die parametrierte Pipeline einmal schreibt und sie dann nur noch über das Jenkins-File aufruft. Und zwar so:
PipelineNodejs{
projectName = 'project123'
slackChannel = '#ci-project123'
appName = 'api'
cloudProject = [development: 'project1', master: 'project3', stage: 'project2']
buildCommand = 'npm install'
nodeImage = 'node:8.3.0'
nodeEnv = "-e NODE_PATH=./app:./config"
nodeTestEnv = '-e NODE_ENV=test -e NODE_PATH=./app:./config'
namespace = [development: "${projectName}-development", stage: 'stage', master: 'production']
}
Das ist eine großartige Methode für DRY (Don’t repeat yourself!), also um Wiederholungen zu vermeiden. Leider entwickelt sich die Codebase von jedem Projekt weiter, das von dieser Pipeline bedient wird - und zwar ungleichmäßig. Du baust also gerade neue Features ein, die die Prozesse in nicht aktualisierten älteren Apps nicht gefährden können. Das verursacht dann eine endlose if/else-Hölle zum Wohle der Abwärtskompatibilität.
Jenkins unterstützt auch nicht von selbst die Spezifizierung von Pipelines für Merge Request in der gleichen Datei, in der du dein Delivery/Deployment Rezept hast. Wir lösen dieses Problem mittels Merge Request Builders, die Merge Requests unabhängig voneinander in den unterschiedlichen Jenkins Jobs erledigen. Das erfüllt den Zweck, aber es ist irgendwie umständlich.
Lasst und jetzt mal ein paar Aspekte von Gitlab CI betrachten, die wirklich cool sind.
Pipeline als Code
Die vorher gezeigten Zeilen sehen fast aus wie eine Pipeline als Code. In meinen Augen sind sie das aber nicht. Wenn ich mir eine Pipeline als Code vorstelle, dann denke ich an etwas, das die komplette Logik auf den ersten Blick zeigt. Das bedeutet, dass die Pipeline Spezifikation zum Repository gehört, genau neben den Code der Haupt-App.
Wenn du eine solche Pipeline Spezifikation hast, dann kannst du jedes Projekt separat feintunen. Erfordert das neue Projekt eine spezielle Testmethode? Baue sie einfach direkt ins Repository ein. Hinterfragt jemand den übergeordneten Pipelineprozess? Konzentriert euch auf das Durchsehen der relevanten Bestandteile des Projekts und nicht die unendlichen Weiten von “wenn das eine 10 Jahre alte Version von NodeJS ist, dann….”
Gitlab ist perfekt in der Lage verschiedene Arten von Pipelines für unterschiedliche Ereignisse zu handeln. In einer einzigen Datei. Du kannst beispielsweise eine Jobgruppe für Push-Ereignisse festlegen, die deine App ausliefern. Ebenso kannst du verschiedene Jobgruppen für Merge Requests definieren.
test:mr: image: node:10.14.2 script: - npm install - npm run ci-test only: ["merge_requests"] build: image: docker:18.09.1 script: - docker build -t my-image . only: variables: - $CI_PIPELINE_SOURCE == "push" refs: ["master", "stage", "development"]
test:mr:
image: node:10.14.2
script:
- npm install
- npm run ci-test
only: ["merge_requests"]
build:
image: docker:18.09.1
script:
- docker build -t my-image .
only:
variables:
- $CI_PIPELINE_SOURCE == "push"
refs: ["master", "stage", "development"]
Wieder passiert alles im gleichen File: .gitlab-ci.yml. Du kannst deine Pipeline auch durch externen Content erweitern, sodass du ihn schön ordentlich hältst und Teile davon auch in anderen Projekten verwenden kannst.
Support von container-native CI / CD
Bevor ich mit den Container-native Aspekten anfange, möchte ich dir gern eine Frage stellen. Willst du alle deine Anwendungen aus verschiedenen Zeitaltern (die in verschiedenen Programmiersprachen geschrieben wurden!) in der gleichen Umgebung ausführen? Natürlich nicht!
Lass uns realistisch bleiben, das wäre störungsanfällig und damit nicht brauchbar. Du willst deine Anwendung in einer abgeschlossenen Umgebung haben, die voll deinen Erwartungen entspricht. Perfekte NodeJS Version, perfekte Glibc Version, etc. Außerdem willst du bestimmt, dass deine Umgebung sich am Ende in Wohlgefallen auflöst, damit ältere Versionen nicht die neueren mit irgendwelchen gecachten Bestandteilen verhunzen. Dieses Problem kann man heutzutage ganz leicht mittels Containern lösen. Und - stell dir vor - Gitlab CI ist in der Lage Container-native Prozesse nativ zu verwalten, und zwar ganz mühelos!
Ich gehe sogar noch weiter. Container eröffnen unendliche Möglichkeiten, was die Erweiterung von Hauptfunktionalitäten durch Plugins betrifft. Du kannst was du willst in jeder beliebigen Sprache schreiben, es einpacken und einem Docker-Image zuordnen - das ist es dann auch schon. Gut, das ist jetzt nicht die herkömmliche Sicht auf Plugins, dafür wird diese Vorgehensweise dein CI/CD Tool nicht kaputt machen und du musst damit keine super komplizierten APIs studieren.
Während meiner Experimente habe ich ein paar “Plugins” gebaut. Helmer-GKE ist verantwortlich für das GKE-Ausliefern mit Helm, Docker-Gcr baut Docker Container mit dem Hauptanwendungscode und lädt sie hoch zum Google Container Registry, während Aglio-Uploader verantwortlich ist für das Rendering und Hochladen der API Dokumentation.
Ich muss sagen, dass die Implementierung dieser Bestandteile richtig schnell ging und Spaß gemacht hat! Zudem können die implementierten Funktionalitäten sofort getestet werden, sogar ohne sie in die finale Pipeline zu integrieren.
Integration
Letzter, aber nicht unwichtiger Punkt: CI/CD Tools müssen sich anwenderfreundlich verhalten. Persönlich ist mir das nicht so wichtig, ich bin aber auch kein häufiger Nutzer von CI/CD Tools. Diese Tools sind mehr für Entwickler und Release Manager gedacht. Glaube es mir oder nicht, hervorragende Entwickler müssen nicht gleichzeitig herausragende Linux/Unix Superuser und Automation Gurus sein. Deswegen sollten CI/CD Tools cool aussehen und gut überblickbar sein für die gesamte Menschheit.
In dieser Disziplin ist Gitlab CI unschlagbar. Wenn du mit Gitlab/Gitlab CI arbeitest, dann ist es, als hättest du ein Control Panel für das gesamte Universum vor dir.
Alle oben genannten Punkte repräsentieren den aktuellen Status von Gitlab CI. Es ist eine wirklich erfreuliche Erfahrung, selbst wenn Gitlab CI nicht alle Funktionalitäten aufweist, die wir von dem gute alten Jenkins gewohnt sind. Zum Beispiel kann es keine hübschen Coverage oder Unit Test Grafiken zeichnen. Außerdem verursacht es kulturelle Spannungen, da… naja, Gitlab C ist einfach nicht Jenkins, deshalb löst es die Dinge eben auch auf andere Art.
Persönlich bin ich der Überzeugung, dass die Tools, mit denen du arbeitest, dir Spaß machen sollen (d.h. dass die Arbeit mit ihnen nicht das Stockholm-Syndrom auslösen soll). Und genau das bedeutet Giltab CI für mich. Ich denke immer: “Verdammt, das ist alles so einfach!”
Ist Jenkins also immer noch die einzige Wahl?
Wenn mir diese Frage vor fünf oder zehn Jahren gestellt worden wäre, dann hätte ich geantwortet: “Ja, ist es. Andere Tools beinhalten einfach nicht die Features, die wir brauchen und sie haben nicht diese Community.”
Aber heute sieht die Sache anders aus. Es gibt eine Handvoll von Tools mit einer steilen Lernkurve, die all deine Bedürfnisse abdecken. Gitlab C sticht hier wirklich hervor, weil es alle drei wichtigen Plattformen (Linux, MacOS und Windows) unterstützt, über detaillierte Dokumentationen verfügt und mega einfach ist.
Ich behaupte nicht, dass Gitlab CI hier bei Ackee Jenkins ersetzen wird. Aber wir werden es sicher weiter im Auge behalten und erforschen. Und ich werde der Chefforscher sein - und zwar mit Vergnügen.