In einer Zeit, in der sich die AI-gestützte Programmierung rasant weiterentwickelt, kann die Bedeutung robuster DevOps-Praktiken nicht hoch genug eingeschätzt werden. In diesem Blogbeitrag zeige ich, wie sich AI effizient nutzen lässt, um CI/CD-Pipelines aufzubauen und weiterzuentwickeln. Dabei wird deutlich: AI bringt zwar 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 zu schaffen, 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 über funktionierende DevOps-Praktiken verfügen. Konzentrieren wir uns jetzt auf die Grundlagen von CI/CD und beginnen wir 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-Umfeld. Hier zeige ich, wie sich ein solcher Workflow mit ChatGPT 4 von Grund auf erstellen lässt. Ihr könnt die Ergebnisse testen, indem ihr dieselben Prompts verwendet, die ich hier genutzt habe (ChatGPT-4-Version erforderlich).
Prompt Nr. 1
Der erste Prompt dient in der Regel als Einführung in das Thema. Mit diesem Ansatz könnt ihr die erste Antwort beobachten und verstehen, in welche Richtung sich die Diskussion entwickelt. Einzelne Prompts reichen selten aus. Lest weiter, um zu sehen, wie ich die Diskussion weiter steuere. Mein erster Prompt lautet:
Bitte gib mir eine Git-Workflow-Grundlage, auf der ich später Continuous-Integration- und Continuous-Deployment-Pipelines aufbauen kann.
GPT-Antwort
Eine solide Grundlage für einen Git-Workflow ist entscheidend, um Continuous-Integration- (CI) und Continuous-Deployment-Pipelines (CD) effektiv umzusetzen. Hier ist ein vorgeschlagener Basis-Workflow, den du als Ausgangspunkt verwenden kannst: ...
Branching-Strategie:
Main-Branch: Dies ist der primäre Branch, dessen Quellcode am HEAD stets einen produktionsreifen Zustand widerspiegelt.
Develop-Branch: Dieser Branch dient als Integrations-Branch für Features. Er enthält stets die neuesten ausgelieferten Entwicklungsänderungen für das nächste Release.
Feature-Branches: Erstellt diese Branches, wenn ihr mit der Arbeit an einem neuen Feature beginnt. Sie werden von „develop“ abgezweigt und nach Abschluss des Features wieder in „develop“ zusammengeführt.
Release-Branches: Zweigt sie von „develop“ ab, wenn ihr ein neues Produktions-Release vorbereiten möchtet. So kann ein Team das aktuelle Release fertigstellen, während ein anderes Team weiterhin 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 bei jedem neuen Commit in jeden Branch automatisierte Tests und weitere Prüfungen wie Linting ausführt – insbesondere für „develop“- und Feature-Branches.
Continuous Deployment (CD):
Sobald die CI-Pipeline erfolgreich durchgelaufen ist und Änderungen in den Main-Branch gemergt wurden, erfolgt automatisch das Deployment in die Produktion, sofern eure Umgebung dies zulässt.
In Umgebungen mit stärkerer Kontrolle könnt ihr Deployments auch manuell über den Main-Branch auslösen.
Versionierung mit Tags:
Nach jedem Release verseht ihr den Code im Main-Branch mit einem Tag, der die Versionsnummer enthält.
Dokumentation:
Haltet eure Projektdokumentation aktuell. Dazu gehören nicht nur eure Code-Dokumentation, sondern auch eure Workflow- und Pipeline-Prozesse.
Zusätzlich gibt es Abschnitte zu Commit-Richtlinien, Code-Reviews und Merging. Obwohl sie wichtig sind, werden wir uns in diesem Blogbeitrag nicht darauf konzentrieren.
Fazit zur Verwendung einer Git-Workflow-Grundlage
Selbst die KI scheint die Bedeutung von Git-Workflows zu betonen. Sie empfiehlt separate Entwicklungs- und Release-Branches – 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 Gedankengang der KI ist hier offenbar sehr gut nachvollziehbar und entspricht häufiger der Realität als erwartet.
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 den Verlauf unserer Diskussion für zukünftige Prompts gespeichert hat, möchte ich nun konkretere Details anfordern. Es empfiehlt sich, die Antwort nach dem ersten Prompt und nach jeder weiteren Antwort zu bewerten und bei Bedarf neue Themen, die sich ergeben, genauer zu betrachten.
Erst danach solltet ihr mit dem nächsten Prompt fortfahren, um die Chat-Sitzung nicht zu unterbrechen. Bei Large Language Models (LLMs) kann das leicht zu unerwünschten Ergebnissen führen.
Bitte vereinfache den Workflow und entferne die Develop- und Release-Branches. Dafür werde ich Git-Tagging verwenden.
GPT-Antwort
Natürlich! Wenn ihr den Git-Workflow vereinfacht, indem ihr die Develop- und Release-Branches entfernt und stattdessen Git-Tagging verwendet, kann der Prozess schlanker werden – 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 bildet den produktionsreifen Zustand eures Codes ab.
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.
Erstellt ihn auf Basis von Main und merged ihn nach Abschluss und Tests der Arbeit wieder zurück in Main.
Eine Namenskonvention für Feature-Branches könnte beispielsweise
feature/<feature-name>oderbugfix/<bug-name>sein.
Git-Tagging für Releases:
Wenn ihr bereit seid, eine neue Version zu veröffentlichen, verwendet Git-Tagging im Main-Branch.
Benennen 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 eure Projektumgebung dies zulässt, richtet CD so ein, dass der Main-Branch nach bestandenen CI-Prüfungen automatisch in die Produktion deployt wird.
Für Umgebungen mit stärkerer Kontrolle könnt ihr getaggte Versionen auch manuell deployen.
Die anderen Teile sind weitgehend ähnlich wie zuvor und müssen hier nicht wiederholt werden.
Fazit zur Vereinfachung des Workflows und zum Entfernen von Develop- und Release-Branches
Okay, das sieht jetzt so aus, wie ich es angefordert habe. Allerdings gibt es Bedenken, wenn GPT vorschlägt, den Main-Branch nach der CI automatisch in die Produktion zu deployen.
Wir alle wissen: Für unsere Nerven und die Zuverlässigkeit der Systeme brauchen wir unbedingt produktionsnahe Umgebungen wie Staging für eine ordnungsgemäße Qualitätssicherung (QA).
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 den Main-Branch nur automatisch in produktionsnahe Umgebungen deployen, etwa nach 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 Staging-Deployments 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 dient 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). Zum Beispiel 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 dies ein Deployment in die Staging-Umgebung aus.
Produktions-Tags: Verwende für Produktions-Deployments das Präfix release-. Tags wie release-v1.0.0 lösen manuelle Deployments in die Produktionsumgebung aus. So behältst du die Kontrolle darüber, was wann in die Produktion deployt wird.
Workflow-Schritte:
Entwicklung: Entwickler arbeiten an Feature- oder Bugfix-Branches, die von main abgezweigt werden.
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. Dies dient abschließenden Tests und der 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 wurde, wird ein release--Tag erstellt. Dieser Tag wird dann verwendet, um das Deployment in die Produktionsumgebung manuell auszulösen.
Continuous Integration und Deployment:
Richte CI/CD-Pipelines ein, die anhand der Tagging-Konvention verschiedene Umgebungen bedienen.
Stelle sicher, dass die CI-Pipeline alle erforderlichen Tests und Qualitätsprüfungen umfasst.
Dokumentation:
Dokumentiere diesen Prozess klar, einschließlich der Frage, wie und wann Tags für Staging- und Produktions-Deployments erstellt werden.
Dieses Setup sorgt für eine klare Trennung zwischen Staging- und Produktions-Deployments und gibt deinem Team Kontrolle über den Release-Prozess. Durch verschiedene Tags für Staging (rc-) und Produktion (release-) kannst du den Fortschritt unterschiedlicher 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 zufrieden seid.
Wenn ihr die Chat-Sitzung mit der AI völlig durcheinanderbringt, solltet ihr möglicherweise eine neue Sitzung von Grund auf 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 zeigen wir, wie Chat GPT-4 eine Bitbucket-Pipeline-Beschreibungsdatei generieren kann, um das oben Beschriebene umzusetzen.
Prompt Nr. 4
Hier führe ich die Prompts in derselben Chat-Sitzung fort, damit der LLM im Hintergrund über relevanten Kontext verfügt.
Jetzt möchte ich, dass du mir aus dem neuesten Workflow, auf den du kürzlich geantwortet hast, die bitbucket-pipelines.yaml bereitstellst. Erstelle die Pipeline für meinen Backend-Service, der mit Python Flask implementiert ist und den ich auf Google Kubernetes in GCP deployen möchte.
Hier erhielt ich eine Implementierung auf hohem Abstraktionsniveau, 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 Gesprächsrunden 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, detailbegrenzten Prompt ableiten. Außerdem ist es entscheidend, größere Aufgaben in kleinere, handhabbare Abschnitte zu unterteilen. Dieser Prozess erfordert auch ein umfassendes Verständnis von DevOps, um das Gespräch effektiv zu steuern. Ihr solltet nicht erwarten, einfach gute Ergebnisse zu erhalten.
Nr. 5 – Okay, das ist etwas zu abstrakt. Ich möchte, dass du das Erstellen von Docker-Images und das Pushen von Images in die Google Cloud Repository gcr.io einschließt. Füge außerdem gcloud-cli- und kubectl-Befehle hinzu. Verwende zudem Platzhalter für Umgebungsvariablen und Secrets, wo erforderlich.
Nr. 6 – Das ist gut, aber wie funktioniert es, wenn ein release-*-Tag manuell ausgelöst wird?
Nr. 7 – Ich möchte Bitbucket-Deployment-Umgebungen verwenden. Kannst du mir bitte die aktuellste bitbucket-pipelines.yaml-Datei mit den Änderungen bereitstellen, die diese Informationen enthalten?
Nr. 8 – Ich möchte die Pipeline so ändern, dass das Docker-Image nur einmal erstellt wird und später mit einem neuen Tag versehen werden kann. Es sollte nicht jedes Mal erneut erstellt werden müssen.
Antwort von GPT-4
Um deine Pipeline so zu ändern, dass das Docker-Image nur einmal erstellt und anschließend für verschiedene Umgebungen mit neuen Tags versehen wird, musst du einige Anpassungen 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 mit neuen Tags zu versehen.
Hier ist eine aktualisierte Version deiner bitbucket-pipelines.yml-Datei 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
Wichtige Änderungen
Einmaliges Erstellen des Images: Das Docker-Image wird bei Commits in den Main-Branch nur einmal erstellt und gepusht. Es wird mit dem Tag latest versehen.
Neue Tags für Staging und Produktion:
Das Skript ./deploy-staging.sh wird verwendet, um den neuesten Tag direkt in der 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 Deployment
./deploy-staging.sh sollte das neueste Image ohne Retagging in Staging deployen.
./retag-deploy-staging.sh und ./retag-deploy-production.sh sollten: 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, und spart so Zeit und Ressourcen. Die Retagging-Skripte bieten Flexibilität bei der Verwaltung verschiedener Umgebungen, ohne das Image neu bauen zu müssen. Stellt sicher, dass euer GCP-Servicekonto über die erforderlichen Berechtigungen verfügt, und ersetzt die Platzhalter durch eure tatsächlichen Projektdetails.
Fazit zum finalen Output des LLM
Wiederholt diese Schritte für jede Komponente eures Systems, sei es ein Service, eine UI oder eine Anwendung. Aufgrund meiner Erfahrung mit Bitbucket Pipelines kann ich Antworten mit einem gewissen Maß an Sicherheit bewerten und verstehen, was nötig ist, um dies operativ umzusetzen. Wäre ich mit den Technologien jedoch nicht vertraut, würde ich mit einigen unerwarteten Herausforderungen rechnen.
Mit zunehmender Reife der LLMs und der Entwicklung spezialisierterer Versionen wird sich die Qualität der Antworten sicherlich verbessern. AI wird den Einsatz neuer Technologien und Prozesse im DevOps-Bereich deutlich beschleunigen.
Mit AI eine DevOps-Basis in der Praxis schaffen
Damit endet meine Demonstration, wie sich mit Unterstützung von AI eine DevOps-Basis in der Praxis schaffen lässt. Um mit dem Prompting zu beginnen, sind keine fortgeschrittenen Kenntnisse erforderlich. Doch wie in 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 leichter. Im Internet gibt es sehr viel gutes Material, das offenbar gut in LLMs integriert ist. 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. Die Vorteile überwiegen jedoch leicht die Kosten, die entstehen würden, wenn CI/CD vernachlässigt oder erst zu einem späteren Zeitpunkt eingeführt wird. Es sollte keinen Grund mehr geben, zögerlich in DevOps von Anfang an zu investieren.
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ösungsfähigkeiten 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.
- Softwareentwicklung
- DevOps
- CI/CD
Subscribe to our newsletter
Related blogs