Risiko Cloud & Serverless

Die Wolke ist eine der innovativsten Entwicklungen, seit der Jahrtausendwende und ermöglicht uns eine flächendeckende Nutzung neuronaler Netze, die wir im Volksmund als Large Language Models (LLM) bezeichnen. Dieser Technologiesprung ist nur noch durch Quantencomputing zu übertreffen. Aber genug der Buzzwords für die SEO-Optimierung, stattdessen schauen wir einmal hinter die Kulissen. Beginnen wir erst einmal damit, was Cloud überhaupt ist, und legen dafür die ganzen Marketingbegriffe einmal beiseite.

Am besten kann man sich die Wolke als gigantischen Supercomputer vorstellen, der aus vielen kleinen Computern bausteinartig zusammengesetzt wurde. Dadurch hat man theoretisch beliebig viel CPU‑Leistung, Arbeitsspeicher und Festplattenspeicher zusammenschalten. Auf diesem Supercomputer, der in einem Rechenzentrum läuft, können nun wiederum virtuelle Maschinen bereitgestellt werden, die einen echten Computer mit einer freidefinierbaren Hardware simulieren. Auf diese Weise können die physischen Hardwareresourcen optimal auf die bereitgestellten virtuellen Maschinen aufgeteilt werden.

Bei Cloud unterscheiden wir grob drei unterschiedliche Betriebslevel: Infrastructure as a Service (IaaS), Platform as a Service (PaaS) und Software as a Service. Die nachfolgende Abbildung gibt eine Vorstellung davon, wie sich diese Ebenen aufteilen.

Vereinfacht kann man sagen, dass bei IaaS durch den Anbieter lediglich die Hardwarespezifikation bereitgestellt wird. Also CPU, RAM, Festplatte und Internetanschluss. Über die Administrationssoftware z. B. Kubernetes kann man nun eigene virtuelle Maschinen/Container erstellen und die entsprechenden Betriebssysteme und Services selbst installieren. Die gesamte Verantwortung der Sicherheit und des Netzwerkrouting liegt hier beim Kunden selbst. PaaS hingegen stellt bereits eine rudimentär eingerichtete virtuelle Maschine inklusive des ausgewählten Betriebssystems bereit. Was man schlussendlich auf diesem System oberhalb der Betriebssystemebene installiert, ist einem selbst überlassen. Aber auch hier ist das Thema Sicherheit zu großen Teilen in den Händen des Kunden. Bei den meisten Hostinganbietern sind typische PaaS-Produkte sogenannte virtuelle Server. Die geringste Freiheit haben Nutzer bei SaaS. Hier hat man meist nur die Berechtigung, durch ein Benutzerkonto eine Software zu nutzen. Sehr typische SaaS Produkte sind E-Mail Konten, aber auch sogenannte Managed Server. Managed Server findet man größtenteils zum Bereitstellen von eigenen Internetseiten. Hier wird die Version der Programmiersprache und der Datenbank durch den Betreiber des Servers vorgegeben.

Gerade die Managed Server haben eine lange Tradition. Sie kamen zur Jahrtausendwende auf um eine sofort benutzbare Umgebung für dynamische PHP Webseiten mit MySQL Datenbankanbindung bereitzustellen. Ähnlich verhält es sich mit den neu in Mode gekommenen Serverless Produkten. Je nach Erfahrungslevel kann man nun bei den Großen Anbietern AWS, Google und Microsoft Azure entsprechende Produkte kaufen.

Der Gedanke ist also, keine eigenen Server mehr für die Dienste zu betreiben und somit den kompletten Aufwand für Hardware, Betrieb und Sicherheit an die Cloudbetreiber auszulagern. Grundsätzlich ist das auch kein schlechter Gedanke, besonders wenn es sich um kleine Unternehmen oder Startups handelt, die einerseits nicht viele finanzielle Mittel zur Verfügung haben oder ihnen einfach das administrative Know-how für Netzwerk, Linux und Serversicherheit fehlt.

Natürlich kommt man mit vollständig extern verwalteten Serverless Angeboten auch schnell an Grenzen. Gerade wenn man die eigene entwickelte Individualsoftware Serverless mit möglichst wenig Aufwand in der Cloud bereitstellen möchte, kommt man an so manchem Stolperstein vorbei. Ein Problem ist oft die flexible Erweiterbarkeit bei wechselnden Anforderungen. Sicher kann man hier aus dem Portfolio der verschiedenen Anbieter Produkte zukaufen und diese wie ein Bausteinset beliebig kombinieren, aber die anfallenden Kosten können sich dabei schnell überschlagen.

Grundsätzlich ist an einem pay per use Modell (also bezahle, was du verwendest) nichts auszusetzen. Für Personen und Organisationen mit kleinem Geldbeutel ist das auf den ersten Blick keine schlechte Lösung. Aber auch hier sind es die kleinen Details, die schnell zu ernsthaften Problemen anwachsen können.

Wenn man sich für einen beliebigen Cloudanbieter entscheidet, ist man gut beraten, möglichst auf dessen proprietäre Management- und Automatisierungsprodukte zu verzichten und stattdessen nach Möglichkeit auf etablierte allgemeine Produkte auszuweichen. Bindet man sich mit allen Konsequenzen an einen Anbieter, so wird es nur unter sehr großem Aufwand möglich sein zu einem anderen Anbieter z wechseln. Änderungen der AGB oder kontinuierlich steigende Kosten sind mögliche Gründe für einen erzwungenen Wechsel. Daher prüfet, wer sich ewig bindet.

Aber auch unbedachte Ressourcennutzung in Cloudsystemen, z. B. durch falsche Konfigurationen oder ungünstige Deploy-Strategien, kann zu einer Kostenexplosion führen. Hier ist man gut beraten, wenn es die Möglichkeit gibt, Limits einzustellen, diese zu aktivieren. sodass man ab einem bestimmten Betrag darauf hingewiesen wird, dass nur noch ein ‚bestimmtes‘ Kontingent zur Verfügung steht. Gerade bei hochverfügbaren Diensten, die plötzlich sprunghaft enorm viele neue Anwender bekommen, können schnell durch solche Limits vom Netz abgestöpselt werden. Daher ist man immer gut beraten, möglichst zwei Lösungen im Bereich Cloud zu nutzen, eine für Entwicklung und eine separate für das Produktivsystem, um das Offlinerisiko zu minimieren.

Ähnlich wie beim Trading an der Börse, kann man auch bei Cloud Services wie AWS Schranken definieren. Die Stops an der Börse sollen verhindern, dass man eine Aktie nicht zu billig verkauft oder zu teuer einkauft. Durch das Pay per Use Modell ist es in der Cloud nicht viel anders. Hier muss man beim Anbieter geeignete Grenzen setzen, die verhindern, dass die Rechnung den Verfügungsrahmen des Kontos sprengt. Auch in der Cloud sind die Grenzen dynamisch. Das heißt, die Rahmenbedingungen verändern sich stetig, was bedeutet, dass die notwendigen Grenzen regelmäßig den Erfordernissen angepasst werden müssen. Um Engpässe rechtzeitig zu erkennen, sollte ein aussagekräftiges Monitoring etabliert sein. Die Mindestanforderung für ein AWS Node wird durch dessen Requests bestimmt. Die obere Schranke der verfügbaren Ressourcen wird durch das Limit bestimmt. Mit Werkzeugen wie Kubecost von IBM lässt sich die Kostenüberwachung in K8 Clustern weitgehend automatisieren.

Für Cloudentwicklungsumgebungen sollte man den eigenen Entwickler‑ und DevOps-Team auch ein wenig auf die Finger schauen. Wenn für eine einfache JavaScript Angular App ein NPM Docker Container von über 2 GB jedes Mal on the fly erstellt wird, sollte man diese Strategie durchaus hinterfragen. Auch wenn die Cloud scheinbar unendlich viele Ressourcen dynamisch allokieren kann, heißt das nicht, dass dies dann auch kostenfrei passiert.

Natürlich ist auch das Thema Sicherheit ein wichtiger Faktor. Natürlich kann man dem Cloudbetreiber so weit vertrauen, wenn er sagt, dass alles verschlüsselt ist und ein Zugriff auf Kundendaten und Geschäftsgeheimnisse nicht möglich ist. Sicher kann man davon ausgehen, dass die Informationen, die bei den meisten Unternehmungen abzugreifen sind, selten einen spannenden oder gar aufregenden Inhalt haben, der für große Cloudbetreiber von Interesse sein könnte. Wer dennoch auf Nummer sicher gehen möchte, sollte das Thema Serverless vollständig abschreiben und eher mit dem Gedanken spielen, seine eigene Cloud zu betreiben. Das geht dank moderner und freier Software mittlerweile leichter als gedacht.

Aus persönlicher Erfahrung habe ich gelernt, dass bei der Komplexität moderner Webanwendungen ein effizientes Monitoring mit Grafana und Prometheus oder anderen Lösungen wie dem ELK Stack oder Slunk unverzichtbar ist. Doch gerade mit der Datenerhebung und der richtigen Auswertung haben so manche DevOps Teams so ihre Schwierigkeiten. Hier sind vor allem die IT-Entscheider gefragt, sich einen technischen Überblick zu verschaffen, um nicht auf die wohlklingenden Marketingfallen bei Cloud und Serverless hereinzufallen.


Die Zukunft des Build Managements

Nicht nur sogenannte Hochsprachen, die den Quelltext in Maschinencode überführen müssen, damit dieser ausführbar ist, benötigen sogenannte Build Werkzeuge. Auch für moderne Scriptsprachen wie Python, Ruby oder PHP sind diese Werkzeuge mittlerweile verfügbar, da deren Verantwortungsbereich stetig wächst. Blickt man in die Anfänge dieser Werkzeugkategorie, stößt man unweigerlich auf make, der erste offizielle Vertreter von dem, was man heute als Build Werkzeug bezeichnet. Die Hauptaufgabe von make war das Erstellen von Maschinencode und das Paketieren der Dateien zu einer Bibliothek oder ausführbaren Datei. Man kann also sagen, das Buildwerkzeuge unter die Kategorie der Automatisierungswerkzeuge fallen. Da liegt es nahe, viele andere immer wiederkehrende Aufgaben, die im Entwickleralltag anfallen, ebenfalls zu übernehmen. So war eine der wichtigsten Innovationen, die für den Erfolg von Maven verantwortlich war, die Verwaltung von Abhängigkeiten zu anderen Programmbibliotheken.

Eine andere Klasse an Automatisierungswerkzeugen, die fast verschwunden ist, sind die sogenannten Installer. Produkte wie Inno SetUp oder Wise Installer wurden verwendet, um den Installationsprozess auf Desktopanwendungen zu automatisieren. Diese Installationsroutinen sind eine spezielle Form des Deployments. Der Deploymentprozess wiederum hängt von verschiedenen Faktoren ab. Zuallererst ist natürlich das verwendete Betriebssystem ein wichtiges Kriterium. Aber auch die Art der Anwendung hat einen erheblichen Einfluss. Handelt es sich etwa um eine Webanwendung, die eine definierte Laufzeitumgebung (Server) benötigt? Wir können hier bereits sehen, dass viele der gestellten Fragen mittlerweile im Themenbereich DevOps angesiedelt sind.

Als Entwickler genügt es nun nicht mehr, nur zu wissen, wie man Programmcode schreibt und Funktionen implementiert. Wer eine Webanwendung bauen möchte, muss zuerst den entsprechenden Server zum Laufen bekommen, auf dem die Applikation ausgeführt wird. Glücklicherweise gibt es mittlerweile viele Lösungen, die das Bereitstellen einer lauffähigen Runtime erheblich vereinfachen. Aber gerade für Anfänger ist es nicht immer so leicht, das ganze Thema zu überblicken. Ich erinnere mich noch an Fragen in einschlägigen Foren, dass man jetzt Java Enterprise heruntergeladen hat, aber nur der Applikationsserver enthalten ist.

Wo Anfang der 2000er noch Automatisierungslösungen fehlten, ist heute eher die Herausforderung, das richtige Werkzeug zu wählen. Auch hier gibt es eine Analogie aus dem Java Universum. Als das Build-Werkzeug Gradle auf dem Markt erschien, stiegen viele Projekte von Maven auf Gradle um. Das Argument war, eine höhere Flexibilität zu erhalten. Oft benötigte man die Möglichkeit, orchestrierte Builds zu definieren. Also die Reihenfolge, in der Teilprojekte erstellt werden. Anstatt sich einzugestehen, dass es sich bei dieser Anforderung um einen Architekturmangel handelt und anstatt diesen zu beheben, wurden komplizierte und kaum überschaubare Build Logiken in Gradle gebaut. Das führte wiederum dazu, dass Anpassungen nur schwer umzusetzen waren und viele Projekte zurück nach Maven migriert wurden.

Aus den DevOps Automatisierungen haben sich mittlerweile sogenannte Pipelines etabliert. Pipelines können auch als Prozess verstanden werden und diese Prozesse lassen sich wiederum standardisieren. Das beste Beispiel für einen standardisierten Prozess, ist der in Maven definierte Build Lifecycle, der auch als Default-Lifecycle bezeichnet wird. In diesem Prozess werden 23 sequenzielle Schritte definiert, die im Groben zusammengefasst folgende Aufgaben abarbeiten:

  • Auflösen und Bereitstellen von Abhängigkeiten
  • Kompilieren der Quelltexte
  • Kompilieren und Ausführen von Komponententests
  • Paketieren der Dateien zu einer Bibliothek oder Anwendung
  • Lokales Bereitstellen des Artefaktes zur Verwendung in anderen lokalen Entwicklungsprojekten
  • Ausführen von Integrationstests
  • Deployen der Artefakte auf einem Remote Repository Server.

Dieser Prozess hat sich über Jahre in unzähligen Javaprojekten bestens bewährt. Führt man diesen Prozess allerdings auf einem CI Server wie Jenkins als Pipeline aus, bekommt man wenig zu sehen. Die einzelnen Schritte des Build Lifecycles bauen aufeinander auf und können nicht einzeln angesteuert werden. Es ist nur möglich, den Lifecycle vorzeitig zu verlassen. Man kann also nach dem Paketieren die nachfolgenden Schritte des lokalen Deployments und das Ausführen der Integrationstests auslassen.

Eine Schwäche des hier beschriebenen Build Prozesses kommt bei der Erstellung von Webapplikationen zutage. Web Frontends enthalten meist CSS und JavaScript Code, der ebenfalls automatisiert optimiert wird. Um in SCSS definierte Variablen in korrektes CSS zu überführen, muss ein SASS Präprozessor verwendet werden. Zudem ist es sehr nützlich, CSS Dateien und JavaScript Dateien möglichst stark zu komprimieren. Dieser Vorgang der Obfuskation optimiert die Ladezeiten von Webanwendungen. Aber auch für CSS und JavaScript gibt es bereits unzählige Bibliotheken, die mit dem Werkzeug NPM verwaltet werden können. NPM wiederum stellt sogenannte Entwicklungsbibliotheken wie Grunt bereit, mit denen wiederum CSS-Prozessierung und -Optimierung möglich sind.

Wir sehen, wie komplex der Buildprozess von modernen Anwendungen werden kann. Das Kompilieren ist nur ein kleiner Teil davon. Ein wichtiges Feature moderner Build Werkzeuge ist das Optimieren des Build Vorgangs. Eine mittlerweile etablierte Lösung dafür ist das Erstellen von inkrementellen Builds. Dies ist eine Variante des Cachings, bei der nur geänderte Dateien kompiliert beziehungsweise prozessiert werden.

Jenkins Pipelines

Was ist aber bei einem Release zu tun? Ein Prozess, der wiederum nur dann benötigt wird, wenn eine Implementierungsphase beendet ist, um das Artefakt für die Verteilung bereitzustellen. Nun könnte man alle Schritte, die ein Release enthalten, ebenfalls in den Build einbauen, was wiederum zu längeren Buildzeiten führt. Längere lokale Buildzeiten stören wiederum den Arbeitsfluss des Entwicklers, weswegen es sinnvoller ist, hierfür einen eigenen Prozess zu definieren.

Bei einem Release sollte eine wichtige Bedingung sein, dass alle verwendeten Bibliotheken ebenfalls als finale Releaseversion vorliegen. Ist dies nicht der Fall, kann nicht sichergestellt werden, dass erneut erstellte Releases dieser Version identisch sind. Aber auch alle Testfälle müssen korrekt durchlaufen werden und ein Fehlschlagen bricht den Vorgang ab. Zudem sollte ein entsprechendes Tag im Source-Control-Repository auf die Revision gesetzt werden. Die fertigen Artefakte sind zu signieren und auch eine API Dokumentation ist zu erstellen. Natürlich sind die hier beschriebenen Regeln nur eine kleine Auswahl und einige der beschriebenen Aufgaben können sogar parallelisiert werden. Nutzt man zudem noch ein raffiniertes Caching, kann das Erstellen eines Releases auch für umfangreiche Monolithen in kurzer Zeit vonstattengehen.

Für Maven wurde beispielsweise kein kompletter Releaseprozess, ähnlich dem Buildprozess, definiert. Hier wurde durch die Community ein spezielles Plug-in entwickelt, mit dem einfache Aufgaben, die während eines Releases anstehen, semiautomatisiert werden können.

Wenn wir das Thema Dokumentation und Reporting ein wenig genauer betrachten, finden wir auch hier genügend Möglichkeiten, einen vollständigen Prozess zu beschreiben. So wäre das Erstellen der API Dokumentation nur ein untergeordneter Punkt. Wesentlich spannender an einem standardisierten Reporting sind die verschiedenen Codeinspektionen, die teilweise auch parallel durchlaufen werden können.

Natürlich darf auch das Deployment nicht fehlen. Aufgrund der Vielfalt, der möglichen Zielumgebungen ist an dieser Stelle eine andere Strategie angebracht. Ein denkbarer Weg wäre eine breite Unterstützung von Konfigurationswerkzeugen wie Ansible, Chef und Puppet. Aber auch Virtualisierungstechnologien wie Docker und LXC Container gehören in Zeiten der Cloud zum Standard. Hauptaufgabe des Deployments wäre dann vor allem die Provisionierung der Zielumgebung und das Einspielen der Artefakte aus einem Repository Server. Mit einer Fülle verschiedener Deployment Templates würde dies eine erhebliche Vereinfachung darstellen.

Wenn wir die hier getroffenen Annahmen konsequent weiterdenken, kommen wir zu dem Schluss, dass es unterschiedliche Projekttypen geben kann. Das wären klassische Entwicklungsprojekte, aus denen dann Artefakte für Bibliotheken und Anwendungen entstehen, Testprojekte, die wiederum die erstellten Artefakte als Abhängigkeit enthalten, und natürlich Deploymentprojekte zur Bereitstellung der Infrastruktur. Der Bereich des automatisierten Deployments findet sich auch in der Idee Infrastructure as a Code und GitOps wieder,die man an dieser Stelle aufgreifen und weiterentwickeln kann.

Wir sehen, dass bei weitem noch nicht alle Innovationen für sogenannte Build Werkzeuge ausgeschöpft sind. Viele der hier besprochenen Ideen sind bereits existierende Konzepte und erfordern lediglich eine Standardisierung. Durch die formalen Beschreibungen eines Prozesses und die flexible Konfiguration einzelner Komponenten in den Prozessschritten wird eine individuelle Anpassung ermöglicht.


Frühjahrsputz für Docker

Wer sich für diesen, eigentlich etwas spezialisierten Artikel interessiert, dem muss man nicht mehr erklären, was Docker ist und wofür das Virtualisierungswerkzeug eingesetzt wird. Daher richtet sich dieser Artikel vornehmlich an Systemadministratoren, DevOps und Cloud-Entwickler. Für alle, die bisher nicht ganz so fit mit der Technologie sind, empfehle ich unseren Docker Kurs: From Zero to Hero.

In einem Szenario, in dem wir regelmäßig neue Docker Images erstellen und verschiedene Container instanzieren, wird unsere Festplatte ordentlich gefordert. Images können je nach Komplexität durchaus problemlos einige hundert Megabyte bis Gigabyte erreichen. Damit das Erstellen neuer Images auch nicht gefühlt, wie ein Download einer drei Minuten langen MP3 mit einem 56k Modem dauert, nutzt Docker einen Build-Cache. Ist im Dockerfile wiederum ein Fehler, kann dieser Build-Cache recht lästig werden. Daher ist es eine gute Idee, den Build-Cache durchaus regelmäßig zu entleeren. Aber auch alte Containerinstanzen, die nicht mehr in Verwendung sind können zu komischen Fehlern führen. Wie hält man seine Dockerumgebung also stubenrein?

Sicher kommt man mit mit docker rm <container-nane> und docker rmi <image-id> schon recht weit. In Buildumgebungen wie Jenkins oder Serverclustern kann diese Strategie allerdings zu einer zeitintensiven und mühsamen Beschäftigung werden. Doch verschaffen wir uns zuerst einmal einen Überblick über die Gesamtsituation. Hier hilft uns der Befehl docker system df weiter.

root:/home# docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          15        9         5.07GB    2.626GB (51%)
Containers      9         7         11.05MB   5.683MB (51%)
Local Volumes   226       7         6.258GB   6.129GB (97%)
Build Cache     0         0         0B        0B

Bevor ich gleich in die Details eintauche, noch ein wichtiger Hinweis. Die vorgestellten Befehle sind sehr effizient und löschen unwiderruflich die entsprechenden Bereiche. Daher wendet diese Befehle erst auf einer Übungsumgebung an, bevor ihr damit Produktivsysteme außer Gefecht setzt. Zudem hat es sich für mich bewährt, auch die Befehle zur Instanzierung von Containern in deiner Textdatei unter Versionsverwaltung zu stellen.

Der naheliegendste Schritt bei einem Docker System Cleanup ist das Löschen der nichtbenutzten Container. Im Konkreten bedeute das, dass durch den Löschbefehl alle Instanzen der Docker Container, die nicht laufen (also nicht aktiv sind), unwiederbringlich gelöscht werden. Will man auf einem Jenkins Buildnode vor einem Deployment Tabula Rasa durchführen, kann man zuvor alle auf der Maschine laufenden Container mit einem Befehl beenden.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Der Parameter -f unterdrückt die Nachfrage, ob man diese Aktion wirklich durchführen möchte. Also die ideale Option für automatisierte Skripte. Durch das Löschen der Container erhalten wir vergleichsweise wenig Festplattenplatz zurück. Die Hauptlast findet sich bei den heruntergeladenen Images. Diese lassen sich ebenfalls mit nur einem Befehl entfernen. Damit Images allerdings gelöscht werden können, muss vorher sichergestellt sein, dass diese nicht durch Container (auch inaktive) in Verwendung sind. Das Entfernen ungenutzter Container hat noch einen ganz anderen praktischen Vorteil. Denn beispielsweise durch Container blockierte Ports werden so wieder freigegeben. Schließlich lässt sich ein Port einer Hostumgebung nur exakt einmal an einen Container binden. Das kann stellenweise schnell zu Fehlermeldungen führen. Also erweitern wir unser Skript um den Eintrag, alle nicht durch Container benutzten Docker Images ebenfalls zu löschen.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Eine weitere Konsequenz unserer Bemühungen umfasst die Docker Layers. Hier sollte man aus Performancegründen, besonders in CI Umgebungen Abstand nehmen. Docker Volumes hingegen sind hier weniger problematisch. Beim Entfernen der Volumes, werden nur die Referenzen in Docker entfernt. Die in die Container verlinkten Ordner und Dateien bleiben von der Löschung unberührt. Der Parameter -a löscht alle Docker Volumes.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Ein weiterer Bereich, der von unseren Aufräumarbeiten betroffen ist, ist der Build-Cache. Besonders wenn man gerade ein wenig mit dem Erstellen neuer Dockerfiles experimentiert, kann es durchaus sehr nützlich sein, den Cache hin und wieder manuell zu löschen. Diese Maßnahme verhindert, dass sich falsch erstellte Layer in den Builds erhalten und es später im instanziierten Container zu ungewöhnlichen Fehlern kommt. Der entsprechende Befehl lautet:

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Ganz radikal ist die Möglichkeit, alle nicht genutzten Ressourcen wieder freizugeben. Hierfür gibt es ebenfalls ein explizites Kommando für die Shell.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Wir können die gerade vorgestellten Befehle natürlich auch für CI Buildumgebungen wie Jenkins oder GitLab CI nutzen. Allerdings kann es sein, dass dies nicht unbedingt zum gewünschten Ziel führt. Ein bewährter Ansatz für Continuous Integration / Continuous Deployment ist das Aufsetzen einer eigenen Docker-Registry, wohin man selbst erstellte Images deployen kann. Diese Vorgehensweise, ist ein gutes Backup & Chaching System für die genutzten Docker Images. Einmal korrekt erstellte Images lassen sich so bequem über das lokale Netzwerk auf die verschiedenen Serverinstanzen deployen, ohne dass diese ständig lokal neu erstellt werden müssen. Daraus ergibt sich als bewährter Ansatz ein eigens für Docker Images / Container optimierter Buildnode, um die erstellten Images vor der Verwendung optimal zu testen. Auch auf Cloudinstanzen wie Azure und der AWS sollte man auf eine gute Performanz und ressourcenschonendes Arbeiten Wert legen. Schnell können die anfallenden Kosten explodieren und ein stabiles Projekt in massive Schieflage bringen.

In diesem Artikel konnten wir sehen, dass tiefe Kenntnisse der eingesetzten Werkzeuge einige Möglichkeiten zur Kostenersparnis erlauben. Gerade das Motto „Wir machen, weil wir es können“, ist im kommerzeillen Umfeld weniger hilfreich und kann schnell zur teuren Resourcenverschwendung ausarten.


Vibe Coding – eine neue Plage des Internets?

Als ich das erste Mal den Begriff Vibe Coding las, dachte ich erst an Kopfhörer, chillige Musik und den Übertritt in den Flow. Der absolute Zustand der Kreativität dem Programmierer hinterherjagen. Ein Rausch der Produktivität. Aber nein, es wurde mir recht schnell klar, es geht um etwas anderes.

Vibe Coding nennt man das, was man einer KI über den Prompt eingibt, um ein benutzbares Programm zu erhalten. Die Ausgabe des Large Language Models (LLM) ist dann noch nicht gleich das ausführbare Programm, sondern nur der entsprechende Quelltext in der Programmiersprache, die der Vibe Coder vorgibt. Daher braucht der Vibe Coder je nachdem, auf welcher Plattform er unterwegs ist, noch die Fähigkeit, das Ganze zum Laufen zu bringen.

Seitdem ich in der IT aktiv bin, gibt es den Traum der Verkäufer: Man bräuchte keine Programmierer mehr, um Anwendungen für den Kunden zu entwickeln. Bisher waren alle Ansätze dieser Art wenig erfolgreich, denn egal was man auch tat, es gab keine Lösung, die vollständig ohne Programmierer ausgekommen ist. Seit der allgemeinen Verfügbarkeit von KI‑Systemen hat sich einiges geändert und es ist nur eine Frage der Zeit, bis man von den LLM-Systemen wie Copilot etc. auch ausführbare Anwendungen geliefert bekommt.

Die Möglichkeiten, die sich durch Vibe Coding eröffnen, sind durchaus beachtlich, wenn man weiß, was man da tut. Gleich aus Goethes Zauberlehrling, der der Geister, die er rief, nicht mehr Herr geworden ist. Werden Programmierer nun obsolet? Auf absehbare Zeit denke ich nicht, dass der Beruf Programmierer aussterben wird. Es wird sich aber einiges verändern und die Anforderungen werden sehr hoch sein.

Ich kann definitiv sagen, dass ich der KI Unterstützung beim Programmieren offen gegenüberstehe. Allerdings haben mich meine bisherigen Erfahrungen gelehrt, sehr vorsichtig zu sein mit dem, was die LLMs so als Lösung vorschlagen. Möglicherweise liegt es daran, dass meine Fragen sehr konkret und für spezifische Fälle waren. Die Antworten waren durchaus hin und wieder ein Fingerzeig in eine mögliche Richtung, die sich als erfolgreich herausgestellt hat. Aber ohne eigenes Fachwissen und Erfahrung wären alle Antworten der KI nicht nutzbar gewesen. Auch Begründungen oder Erläuterungen sind in diesem Kontext mit Vorsicht zu genießen.

Es gibt mittlerweile diverse Angebote, die den Leuten den Umgang mit künstlicher Intelligenz beibringen wollen. Also in Klartext, wie man einen funktionierenden Prompt formuliert. Ich halte solche Offerten für unseriös, denn die LLM wurden ja dafür entwickelt, natürliche (menschliche) Sprache zu verstehen. Was soll man also lernen, vollständige und verständliche Sätze zu formulieren?

Wer eine ganze Anwendung über Vibe Coding erstellt, muss diese ausgiebig testen. Also sich durch die Funktionen klicken und schauen, ob alles so funktioniert, wie es soll. Das kann durchaus zu einer sehr nervenden Beschäftigung ausarten, die mit jedem Durchlauf lästiger wird.

Auch die Verwendung von Programmen, die durch Vibe Coding erstellt wurden, ist unproblematisch, solange diese lokal auf dem eigenen Computer laufen und nicht als kommerzieller Internetservice frei zugänglich sind. Denn genau hier lauert die Gefahr. Die durch Vibe Coding erstellten Programme sind nicht ausreichend gegen Hackerangriffe gesichert, weswegen man sie nur in geschlossenen Umgebungen betreiben sollte. Ich kann mir auch gut vorstellen, dass künftig in sicherheitskritischen Umgebungen wie Behörden oder Banken die Verwendung von Programmen, die Vibe Coded sind, zu verbieten. Sobald die ersten Cyberattacken auf Unternehmensnetzwerke durch Vibe Coding Programme bekannt werden, sind die Verbote gesetzt.

Neben der Frage zur Sicherheit von Vibe-Coding-Anwendungen werden Anpassungen und Erweiterungen nur mit großem Aufwand umzusetzen sein. Dieses Phänomen ist in der Softwareentwicklung gut bekannt und tritt bei sogenannten Legacy Anwendungen regelmäßig auf. Sobald man hört, dass ist historisch gewachsen ist, man auch schon mitten drin. Fehlende Strukturen und sogenannte technische Schulden lassen ein Projekt über die Zeit so erodieren, dass sich die Auswirkungen von Änderungen nur sehr schwer auf die restlichen Funktionen abschätzen lassen. So ist zu vermuten, dass es in Zukunft sehr viele Migrationsprojekte geben wird, die die KI erstellten Codebasen wieder in saubere Struckturen überführen. Deswegen eignet sich Vibe Coding vor allem für die Erstellung von Prototypen, um Konzepte zu testen.

Mittlerweile gibt es auch Beschwerden in Open Source Projekten, dass es hin und wieder zu Contributions kommt, die nahezu die halbe Codebasis umstellen und fehlerhafte Funktionen hinzufügen. Hier helfen natürlich zum einen der gesunde Menschenverstand und die vielen in der Softwareentwicklung etablierten Standards. Es ist ja nicht so, dass man im Open Source nicht schon früher Erfahrung mit schlechten Code Commits gesammelt hätte. Dadurch kam der Diktaturship-Workflow für Werkzeuge wie Git, das von der Codehosting Plattform GitHub in Pull Request umbenannt wurde.

Wie kann man also schnell schlechten Code erkennen? Mein derzeitiges Rezept ist die Überprüfung der Testabdeckung für hinzugefügten Code. Kein Test, kein Codemerge. Natürlich können auch Testfälle Vibe Coded sein oder es fehlen notwendige Assertions, auch das lässt sich mittlerweile gut automatisiert erkennen. In den vielen Jahren in Softwareentwicklungsprojekten habe ich genügend erlebt, dass mir kein Vibe Coder auch nur annähernd Schweißperlen auf die Stirn treiben kann.

Mein Fazit zum Thema Vibe Coding lautet: Es wird in Zukunft einen Mangel an fähigen Programmierern geben, die Unmengen an schlechtem Produktivcode gerade biegen sollen. Also auf absehbare Zeit noch kein aussterbender Beruf. Dem gegenüber werden durchaus ein paar clevere Leute für das eigene Business sich mit einfachen Informatikkenntnissen ein paar leistungsfähige Insellösungen zusammenscripten, die zu Wettbewerbsvorteilen führen werden. Während wir diese Transformation erleben, wird das Internet weiterhin zugemüllt und die Perlen, von denen Weizenbaum einst gesprochen hat, schwerer zu finden sein.


Stichwortverzeichnis & Abkürzungen

[A]

[B]

[C]

[D]

[E]

[F]

[G]

[H]

[I]

[J]

[K]

[L]

[M]

[N]

[O]

[P]

[Q]

[R]

[S]

[T]

[U]

[V]

[W]

[Y]

[Z]

[X]

Zurück zum Inhaltsverzeichniss: Apache Maven Master Class

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

[A]

[B]

[C]

[D]

[E]

[F]

[G]

[H]

[I]

[J]

[K]

[L]

[M]

[N]

[O]

[P]

[Q]

[R]

[S]

[T]

[U]

[V]

[W]

[Y]

[Z]

[X]

Zurück zum Inhaltsverzeichniss: Apache Maven Master Class