In einer Zeit, in der sich KI-gestützte Programmierung rasant weiterentwickelt, kann die Bedeutung robuster DevOps-Praktiken nicht hoch genug eingeschätzt werden. In diesem Blogbeitrag zeige ich, wie sich KI effizient zum Aufbau und zur Optimierung von CI/CD-Pipelines nutzen lässt. Dabei wird deutlich: KI bringt erhebliche Fortschritte, doch menschliche Expertise bleibt unverzichtbar.
Alex Jantunen
Alex is an experienced software architect specializing in solving complex problems and optimizing CI/CD pipelines. He is particularly skilled in microservices, backend, and DevOps.
Eine solide DevOps-Grundlage aufzubauen, ist längst kein monatelanges Vorhaben mehr. Mit dem richtigen Ansatz und den passenden Tools können und sollten selbst kleine Projekte innerhalb weniger Tage oder Wochen ein funktionierendes DevOps-Setup haben. Wenden wir uns nun den Grundlagen von CI/CD zu und beginnen mit dem Git-Workflow.
Git-Workflow: Das Fundament für gutes CI/CD
Wie wir alle wissen, sind klare und gut dokumentierte Git-Workflow-Praktiken für jedes erfolgreiche Entwicklungsprojekt entscheidend – insbesondere im DevOps. Hier zeige ich, wie sich ein solcher Workflow mit Unterstützung von ChatGPT 4 von Grund auf erstellen lässt. Ihr könnt die Ergebnisse mit genau denselben Prompts testen, die ich hier verwendet habe (ChatGPT-4-Version erforderlich).
Prompt Nr. 1
Der erste Prompt dient in der Regel als Einführung in das Thema. So könnt ihr die erste Antwort betrachten und nachvollziehen, in welche Richtung sich die Diskussion entwickelt. Ein einzelner Prompt reicht selten aus. Lest weiter, um zu sehen, wie ich die Diskussion weiter lenke. Mein erster Prompt lautet:
Bitte gib mir eine Grundlage für einen Git-Workflow, damit ich später Continuous-Integration- und Deployment-Pipelines auf Basis dieser Workflow-Praktiken implementieren kann.
GPT-Antwort
Eine solide Grundlage für einen Git-Workflow ist essenziell, um Continuous-Integration-(CI)- und Continuous-Deployment-(CD)-Pipelines effektiv zu implementieren. Hier ist ein vorgeschlagener Basis-Workflow, den du als Ausgangspunkt verwenden kannst: ...
Branching-Strategie:
Main-Branch: Dies ist der primäre Branch, in dem der Quellcode bei HEAD stets einen produktionsreifen Zustand widerspiegelt.
Develop-Branch: Dieser Branch dient als Integrations-Branch für Features. Er enthält immer die neuesten bereitgestellten Entwicklungsänderungen für das nächste Release.
Feature-Branches: Erstellt diese Branches, wenn ihr mit der Arbeit an einem neuen Feature beginnt. Erstellt sie auf Basis von „develop“ und führt sie nach Abschluss des Features wieder mit „develop“ zusammen.
Release-Branches: Erstellt sie auf Basis von „develop“, wenn ihr ein neues Produktions-Release vorbereiten möchtet. So kann ein Team das aktuelle Release fertigstellen, während ein anderes Team weiter an Features für das nächste Release arbeitet.
Hotfix-Branches: Diese Branches werden verwendet, um Produktions-Releases schnell zu patchen. Sie ähneln Release- und Feature-Branches, basieren jedoch auf „main“ und werden sowohl in „main“ als auch in „develop“ zusammengeführt.
Continuous Integration (CI):
Richtet eine CI-Pipeline ein, die automatisierte Tests und weitere Prüfungen, etwa Linting, ausführt, sobald ein neuer Commit in einen Branch gepusht wird – insbesondere in die Branches „develop“ und „feature“.
Continuous Deployment (CD):
Wenn die CI-Pipeline erfolgreich durchläuft und Änderungen in den Main-Branch gemergt werden, führt automatisch ein Deployment in die Produktion durch, sofern euer Setup dies zulässt.
Für Umgebungen mit mehr Kontrolle könnt ihr Deployments auch manuell über den Main-Branch auslösen.
Versionierung mit Tags:
Taggt den Code im Main-Branch nach jedem Release mit einer Versionsnummer.
Dokumentation:
Haltet eure Projektdokumentation aktuell. Dazu gehören nicht nur eure Code-Dokumentation, sondern auch eure Workflow- und Pipeline-Prozesse.
Darüber hinaus gibt es Abschnitte zu Commit-Richtlinien, Code-Reviews und Merging. Obwohl sie wichtig sind, konzentrieren wir uns in diesem Blogbeitrag nicht darauf.
Fazit zur Verwendung einer Git-Workflow-Grundlage
Selbst die KI scheint die Bedeutung von Git-Workflows zu betonen. Sie schlägt separate Entwicklungs- und Release-Branches vor – eine gute Strategie, wenn sie richtig umgesetzt wird. Zur Veranschaulichung zeige ich jedoch einen schlankeren Workflow, der möglicherweise besser geeignet ist.
Beachtet den wichtigen Punkt: Dokumentiert euren Workflow und eure Pipeline! Der Denkprozess der KI scheint hier sehr gut nachvollziehbar zu sein – und ist oft besser als die Realität.
Eine klare Kommunikation zu diesen Themen und Retrospektiven sorgen dafür, dass die Developer Experience (DevEx) hervorragend bleibt.
Prompt Nr. 2
Nachdem wir die erste Antwort erhalten haben und ChatGPT für künftige Prompts den Verlauf unserer Diskussion kennt, möchte ich nun spezifischere Details anfordern. Es empfiehlt sich, die Antwort nach dem ersten Prompt und nach jeder weiteren Antwort zu prüfen und bei Bedarf neue Themen, die sich ergeben, genauer zu beleuchten.
Erst dann solltet ihr mit dem nächsten Prompt fortfahren, um die Chat-Session nicht zu unterbrechen. Das kann bei Large Language Models (LLMs) leicht zu unerwünschten Ergebnissen führen.
Bitte vereinfache den Workflow und entferne Develop- und Release-Branches. Dafür werde ich Git-Tagging verwenden.
GPT-Antwort
Natürlich! Den Git-Workflow durch das Entfernen der Develop- und Release-Branches und die Verwendung von Git-Tagging zu vereinfachen, kann den Prozess schlanker machen – insbesondere für kleinere Teams oder Projekte. Hier ist eine überarbeitete Version des Workflows:
Main-Branch:
Dies ist euer primärer und einziger langlebiger Branch. Der Main-Branch repräsentiert den produktionsreifen Stand eures Codes.
Alle Features, Bugfixes und Hotfixes werden direkt in diesen Branch gemergt.
Feature-Branches:
Erstellt einen Feature-Branch, sobald ihr mit der Arbeit an einem neuen Feature oder einem Bugfix beginnt.
Geht vom Main-Branch aus und mergt die Änderungen nach Abschluss und Tests wieder in den Main-Branch zurück.
Eine Namenskonvention für Feature-Branches könnte etwa
feature/<feature-name>oderbugfix/<bug-name>lauten.
Git-Tagging für Releases:
Wenn ihr bereit seid, eine neue Version zu veröffentlichen, verwendet Git-Tagging auf dem Main-Branch.
Benannt eure Tags nach der semantischen Versionierung (z. B. v1.0.0, v1.0.1), um verschiedene Releases nachzuverfolgen.
Tags können bei Bedarf auch bestimmte CI/CD-Aktionen auslösen.
Continuous Deployment (CD):
Wenn es eure Projektumgebung erlaubt, richtet CD so ein, dass der Main-Branch nach bestandenen CI-Prüfungen automatisch in die Produktion deployt wird.
Für stärker kontrollierte Umgebungen könnt ihr euch dafür entscheiden, getaggte Versionen manuell zu deployen.
Die anderen Teile sind dem vorherigen Workflow sehr ähnlich und müssen hier nicht wiederholt werden.
Fazit zur Vereinfachung des Workflows und zum Entfernen von Develop- und Release-Branches
Okay, das sieht jetzt nach dem aus, was ich angefragt habe. Allerdings habe ich Bedenken, wenn GPT vorschlägt, den main-Branch nach der CI automatisch in die Produktion zu deployen.
Wir alle wissen, dass wir für unsere eigene Vernunft und die Zuverlässigkeit unserer Systeme produktionsnahe Umgebungen wie Staging für eine ordnungsgemäße Qualitätssicherung (QA) unbedingt brauchen.
Automatisierte Regressionstests nach jeder Änderung in produktionsnahen Umgebungen auszuführen, ist entscheidend. Das betrifft nicht nur Codeänderungen am Produkt, sondern auch Änderungen an Infrastruktur (IaC), Pipelines und mehr.
Prompt Nr. 3
Für Continuous Deployment möchte ich main nur automatisch in produktionsnahe Umgebungen deployen, beispielsweise Staging. Ein Deployment in die Produktion soll hingegen über Git-Tags mit dem Präfix „release-“ erfolgen, zum Beispiel release-v1.0.0. Für das Staging-Deployment wäre das Präfix rc- (Release Candidate).
GPT-Antwort
Absolut – dein Ansatz für Continuous Deployment mit spezifischen Git-Tag-Konventionen für Staging- und Produktionsumgebungen ist eine gute Strategie. So kannst du diesen Workflow strukturieren:
Main-Branch als Staging-Umgebung:
Der main-Branch fungiert als Staging-ähnliche Umgebung. Jeder Merge in main löst automatisch ein Deployment in die Staging-Umgebung aus.
So kannst du in einer Umgebung testen, die der Produktion sehr ähnlich ist.
Git-Tagging für Staging und Produktion:
Staging-Tags: Verwende für Staging-Deployments das Präfix rc- (Release Candidate). Beispielsweise kennzeichnet rc-v1.0.0 einen Release Candidate für Version 1.0.0. Wenn du einen Tag mit diesem Präfix pushst, löst er ein Deployment in die Staging-Umgebung aus.
Produktions-Tags: Verwende für Produktions-Deployments das Präfix release-. Tags wie release-v1.0.0 dienen dazu, manuelle Deployments in die Produktionsumgebung auszulösen. So behältst du die Kontrolle darüber, was wann in die Produktion deployt wird.
Schritte im Workflow:
Entwicklung: Entwickler arbeiten an Feature- oder Bugfix-Branches, die von main abzweigen.
Code Review und Merge: Sobald die Arbeit abgeschlossen ist, wird ein Pull Request erstellt, um Änderungen in main zu mergen. Nach dem Code Review und erfolgreichen CI-Checks werden die Änderungen gemergt.
Automatisches Staging-Deployment: Ein Merge in main löst automatisch ein Deployment in die Staging-Umgebung aus. Dort erfolgen die abschließenden Tests und die Validierung.
Tagging für Release Candidates: Wenn das Team mit den Änderungen in Staging zufrieden ist, wird ein rc--Tag erstellt, um einen Release Candidate offiziell zu kennzeichnen.
Produktions-Deployment: Sobald der Release Candidate gründlich getestet und freigegeben ist, wird ein release--Tag erstellt. Dieser Tag dient dann dazu, das Deployment in die Produktionsumgebung manuell auszulösen.
Continuous Integration und Deployment:
Richte CI/CD-Pipelines ein, die anhand der Tagging-Konvention unterschiedliche Umgebungen bedienen.
Stelle sicher, dass die CI-Pipeline alle erforderlichen Tests und Qualitätsprüfungen enthält.
Dokumentation:
Dokumentiere diesen Prozess klar, einschließlich der Frage, wie und wann für Staging- und Produktions-Deployments Tags erstellt werden.
Dieses Setup stellt eine klare Trennung zwischen Staging- und Produktions-Deployments sicher und gibt deinem Team die Kontrolle über den Release-Prozess. Durch unterschiedliche Tags für Staging (rc-) und Produktion (release-) kannst du den Fortschritt verschiedener Releases in deinen Umgebungen einfach verwalten und nachverfolgen.
Fazit zur Automatisierung von Deployments in produktionsähnliche Umgebungen
Jetzt bin ich mit meinem Workflow zufrieden. Ihr könnt auf ähnliche Weise vorgehen, um einen Workflow zu entwickeln, mit dem ihr gerne arbeitet.
Wenn ihr die Chat-Sitzung mit der AI völlig durcheinanderbringt, ist es möglicherweise besser, von Grund auf eine neue zu starten, um irreführende Antworten zu vermeiden.
Dieses Mal habe ich bereits in der ersten Chat-Sitzung Ergebnisse erzielt, aber oft war es nicht so einfach. Als Nächstes erstelle ich die eigentliche Pipeline als Code und nutze dafür Atlassian Bitbucket Pipelines als zugrunde liegende Technologie.
Generative AI für DevOps-Pipelines
In diesem Abschnitt sehen wir, wie Chat GPT-4 eine Bitbucket-Pipeline-Beschreibungsdatei generieren kann, um das oben Beschriebene umzusetzen.
Prompt Nr. 4
Hier setze ich die Prompts in derselben Chat-Sitzung fort, damit das LLM im Hintergrund über den relevanten Kontext verfügt.
Jetzt möchte ich, dass du mir auf Grundlage des neuesten Workflows, den du gerade erstellt hast, die Datei bitbucket-pipelines.yaml bereitstellst. Erstelle die Pipeline für meinen Backend-Service, der mit Python Flask implementiert ist und den ich in Google Kubernetes auf GCP deployen möchte.
Hier erhielt ich eine Implementierung auf hohem Niveau, bei der die meisten Details in separate Shell-Skriptdateien ausgelagert wurden. Das war nicht meine Absicht, daher zeige ich die Antwort hier nicht. Nach weiteren Diskussionsrunden erhielt ich jedoch das, wonach ich gesucht hatte.
Prompts Nr. 5 bis Nr. 8
Bei komplexen Themen sind mehrere Prompts bei der Arbeit mit generativer AI üblich. Die AI kann eure genauen Anforderungen nicht aus einem einzigen Prompt mit begrenzten Details ableiten. Außerdem ist es wichtig, größere Aufgaben in kleinere, überschaubare Teile aufzuteilen. Dieser Prozess erfordert auch ein umfassendes Verständnis von DevOps, um das Gespräch effektiv zu steuern. Ihr solltet nicht erwarten, ohne großen Aufwand gute Ergebnisse zu erzielen.
Nr. 5 – Okay, das ist etwas zu allgemein. Ich möchte, dass du das Erstellen von Docker-Images und das Pushen der Images in die Google Cloud Repository gcr.io einbeziehst. Füge außerdem gcloud-cli- und kubectl-Befehle hinzu. Ergänze zudem Platzhalter für Umgebungsvariablen und Secrets, wo sie benötigt werden.
Nr. 6 – Das ist gut, aber wie funktioniert es, wenn ein release-*-Tag manuell ausgelöst wird?
Nr. 7 – Ich möchte Bitbucket Deployment Environments nutzen. Kannst du mir bitte die aktuellste Datei bitbucket-pipelines.yaml mit den entsprechenden Anpassungen bereitstellen?
Nr. 8 – Ich möchte die Pipeline so ändern, dass das Docker-Image nur einmal erstellt wird und später mit einem anderen Tag versehen werden kann. Es sollte nicht jedes Mal neu erstellt werden müssen.
GPT-4-Antwort
Um deine Pipeline so anzupassen, dass das Docker-Image nur einmal erstellt und anschließend für verschiedene Umgebungen mit neuen Tags versehen wird, musst du einige Änderungen an deiner bitbucket-pipelines.yml vornehmen. Die Idee ist, das Docker-Image einmal zu erstellen, mit einem allgemeinen Tag in die Google Container Registry (GCR) zu pushen und es dann bei Bedarf für Staging- oder Produktions-Deployments neu zu taggen.
Hier ist eine aktualisierte Version deiner Datei bitbucket-pipelines.yml mit diesen Änderungen:
image: atlassian/default-image:2
pipelines:
default:
- step:
name: Build and Test
caches:
- pip
script:
- pip install -r requirements.txt
- python -m unittest discover tests
branches:
main:
- step:
name: Build and Push Docker Image
script:
- echo $GCLOUD_SERVICE_KEY | base64 --decode --ignore-garbage > ${HOME}/gcloud-service-key.json
- docker build -t gcr.io/$GCLOUD_PROJECT/your-app:latest .
- gcloud auth configure-docker --quiet
- docker push gcr.io/$GCLOUD_PROJECT/your-app:latest
- step:
name: Deploy to Staging
deployment: staging
script:
- echo "Deploying to Staging Environment"
- ./deploy-staging.sh # This script should handle the retagging for staging
tags:
'rc-*':
- step:
name: Retag and Deploy to Staging
deployment: staging
script:
- echo "Retagging and Deploying Release Candidate to Staging"
- ./retag-deploy-staging.sh # Script to retag the image for staging
'release-*':
- step:
name: Retag and Deploy to Production
deployment: production
trigger: manual
script:
- echo "Retagging and Deploying to Production Environment"
- ./retag-deploy-production.sh # Script to retag the image for production
definitions:
caches:
pip: ~/.cache/pip
Wesentliche Änderungen
Einmaliger Image-Build: Das Docker-Image wird bei Commits in den Main-Branch nur einmal erstellt und gepusht. Es erhält den Tag latest.
Neues Tagging für Staging und Produktion:
Das Skript ./deploy-staging.sh wird verwendet, um den Tag latest direkt in die Staging-Umgebung zu deployen.
Für die Tags rc-* und release-* werden separate Skripte (./retag-deploy-staging.sh und ./retag-deploy-production.sh) verwendet. Diese Skripte sollten das Docker-Image mit dem passenden Tag versehen – basierend auf dem Commit- oder Release-Tag – und es anschließend in der jeweiligen Umgebung deployen.
Skripte zum Retagging und für Deployments
./deploy-staging.sh sollte das neueste Image ohne Retagging nach Staging deployen.
./retag-deploy-staging.sh und ./retag-deploy-production.sh sollten Folgendes tun: Das neueste Image aus GCR abrufen. Es mit dem spezifischen Commit- oder Release-Tag retaggen. Das retaggte Image zurück in GCR pushen. Das Kubernetes-Deployment aktualisieren, damit es den neuen Tag verwendet.
Das neueste Image aus GCR abrufen.
Es mit dem spezifischen Commit- oder Release-Tag retaggen.
Das retaggte Image zurück in GCR pushen.
Das Kubernetes-Deployment aktualisieren, damit es den neuen Tag verwendet.
Dieser Ansatz stellt sicher, dass das Docker-Image nur einmal gebaut wird, was Zeit und Ressourcen spart. Die Retagging-Skripte bieten Flexibilität bei der Verwaltung verschiedener Umgebungen, ohne dass das Image neu gebaut werden muss. Denkt daran, sicherzustellen, dass euer GCP-Servicekonto über die erforderlichen Berechtigungen verfügt, und die Platzhalter durch eure tatsächlichen Projektdetails zu ersetzen.
Fazit zum finalen Output des LLM
Wiederholt diese Schritte für jede Komponente eures Systems – ob Service, UI oder Anwendung. Aufgrund meiner Erfahrung mit Bitbucket Pipelines kann ich Antworten mit einem gewissen Maß an Sicherheit bewerten und verstehen, was nötig ist, damit dies operativ funktioniert. Wäre ich jedoch mit den Technologien nicht vertraut, würde ich mit einigen unerwarteten Herausforderungen rechnen.
Mit zunehmender Weiterentwicklung von LLMs und der Entwicklung spezialisierter Varianten wird sich die Qualität der Antworten sicherlich verbessern. AI wird die Einführung neuer Technologien und Prozesse im DevOps-Bereich erheblich beschleunigen.
Mit AI in der Praxis eine DevOps-Basis schaffen
Damit ist meine Demonstration abgeschlossen, wie sich mit Unterstützung von AI in der Praxis eine DevOps-Basis schaffen lässt. Um mit dem Prompting zu beginnen, sind keine fortgeschrittenen Kenntnisse erforderlich. Doch wie bei jeder Sportart erzielt ihr mit Übung bessere Ergebnisse.
Ausgehend von dieser Basis gibt es noch einiges zu verbessern, zum Beispiel eine umfassende Continuous Integration, einschließlich DevSecOps und IaC.
Mit AI wird der Einstieg in DevOps-Themen einfacher. Im Internet gibt es so viele gute Materialien, und sie scheinen gut in LLMs integriert zu sein. Wichtig ist jedoch zu verstehen, dass Design-Diskussionen dieser Art mit den fortschrittlichsten LLMs effektiver sind. Dieselbe Diskussion würde beispielsweise mit GPT-3.5 ganz anders verlaufen.
Oft wird angenommen, dass CI/CD für kleinere Projekte eine zu große Investition darstellt. Doch der Nutzen überwiegt leicht die Kosten, die entstehen würden, wenn CI/CD vernachlässigt oder erst später eingeführt wird. Es sollte keinen Grund mehr geben, von Anfang an mit Investitionen in DevOps zu zögern.
Mit der Zeit rechne ich mit immer umfassenderen Entwicklungsplattformen, in denen viele Prozesse automatisiert sind und Softwareentwicklung sowie DevOps stärker abstrahiert werden. Dennoch bleiben Problemlösungskompetenz und ein tiefes Verständnis der zugrunde liegenden Prinzipien wichtig.
Ich hoffe, dieser Blogbeitrag hat euch dazu inspiriert, DevOps von Anfang an umzusetzen und/oder eure aktuelle Situation zu verbessern.
Wenn euch dieser Blogbeitrag gefallen hat, interessiert euch vielleicht auch unsere Podcast-Episode über AI in der DevOps-Toolchain.
- Software development
- DevOps
- CI/CD
Subscribe to our newsletter
Related blogs