Spring Boot Anwendungen mit Helm

Mittwoch, 17.5.2023

Spring Boot Applications with Helm

Spring Boot ist ein Framework für die Entwicklung von Java-Anwendungen, und Kubernetes ist einer der De-facto-Standards für die Bereitstellung von Anwendungen in Cloud-Umgebungen. Die Bereitstellung von Apps in einem Kubernetes-Cluster kann jedoch mühsam werden, da sich die Konfigurationen in verschiedenen Kubernetes-Deskriptoren wiederholen. Das Verwalten der Konfiguration wird noch aufwändiger, wenn mehrere Umgebungen wie Entwicklungs-, Test- und Produktionsumgebungen verwendet werden.

Helm löst diese Probleme durch Templates, Paketierung, Versionierung und einer Infrastruktur für die gemeinsame Nutzung und Wiederverwendung von Templates. In diesem Artikel wird Helm kurz vorgestellt und erläutert, wie es für Spring Boot Anwendungen genutzt werden kann.

Wofür braucht man Helm?

Das Deployment von Spring Boot Anwendungen auf Kubernetes erfordert die Erstellung einer Reihe von Manifestdateien. Eine Kubernetes Manifestdatei ist meist im YAML-Format geschrieben und enthält alle Informationen, die zum Betreiben einer Anwendnung benötigt werden. Diese Manifestdateien enthalten unter anderem das verwendete Container-Image, die Anzahl der auszuführenden Replikate und die einem Container zuzuweisenden Hardware-Ressourcen. Manifestdateien dazu schnell zu wachsen und unübersichtlich zu werden, wenn weitere Ressourcen und Konfigurationen hinzugefügt werden. Angenommen, Sie haben eine Manifestdatei, die eine Deployment-Ressource für eine Anwendung definiert und eine andere Manifestdatei, die eine Service-Ressource für dieselbe Anwendung definiert. Beide Manifestdateien enthalten höchstwahrscheinlich ähnliche Konfigurationen, wie z.B. Labels und Annotationen, und verwenden ein ähnliches Namensschema. Die Pflege solcher Dateien ist mühsam und fehleranfällig, vor allem, wenn die Anwendnung in mehrere Umgebungen laufen soll. In diesem Fall müssen für jede Umgebung separate Manifestdateien erstellt und gepflegt werden, was zusäzlich Raum für Fehler schafft. Helm löst diese Probleme, indem es ermöglicht, Templates für Manifestdateien zu erstellen. Darüber hinaus ermöglicht Helm, diese Vorlagen zu verpacken, zu versionieren und hochzuladen, damit sie von anderen einfach wiederverwendet werden können.

Wie verwendet man Helm?

Was ist ein Helm Chart und wie ist es strukturiert?

Ein Helm Chart ist ein Paket, welches alle Ressourcendefinitionen enthält, die für die Ausführung einer Anwendung in einem Kubernetes-Cluster erforderlich sind. Es ist eine Sammlung von Templates, Kubernetes-Manifestdateien und anderen Ressourcen, die den gewünschten Zustand einer Anwendung beschreiben. Ein Chart ist als Verzeichnis organisiert, welches mehrere Dateien und Unterverzeichnisse enthält. Die wichtigsten Dateien und Ordner sind:

  • Chart.yaml: Diese Datei enthält Metadaten über das Chart, wie z.B. den Namen, die Version und die Beschreibung des Charts.
  • values.yaml: Diese Datei enthält Standardwerte für die Konfigurationsoptionen des Charts.
  • templates: Dieser Ordner enthält die Vorlagen, die die Kubernetes-Ressourcen definieren, aus denen die Anwendung besteht. Die Vorlagen verwenden die Go template language, sodass Variablen und Kontrollstrukturen verwendet werden können, um die Erzeugung der  Manifestdateien zu beeinflussen.

Ein Chart hat häufig die folgende Dateistruktur:

 

Wie funktioniert der Templating-Mechanismus in Helm?

Der Templating-Mechanismus in Helm verwendet die text/template-Bibliothek von Go, um Template-Dateien zu verarbeiten und Kubernetes-Manifeste zu erzeugen. Die Templates definieren die Ressourcen der Anwendung, wie z. B. Deployments, Services und Ingresses, und verwenden Platzhalter, um zur Laufzeit festgelegte Variablen darzustellen. Helm ermöglicht es Variablen zu definieren und diese mit folgender Syntax in den Templates zu verwenden: ` .Values.Variablenname`. Das `.` bezieht sich auf die Wurzel des Helm Charts, über `Values` kann auf die benutzerdefinierten Variablen zugegriffen werden, und `Variablenname` ist der Name der selbstdefinierten Variable. Beim Rendern des Charts ersetzt Helm die Variable `Variablenname` durch ihren Wert. Die Variablenwerte können aus verschiedenen Quellen stammen, z. B. aus der Standarddatei values.yaml, aus vom Benutzer bereitgestellten Werten, die als zusätzliche values.yaml an Helm CLI übergeben werden, oder aus CLI-Parametern.

Nachfolgend ist eine Template Datei für ein Deployment zu sehen:

In diesem Beispiel werden die Platzhalter `.Values.replicaCount`, `.Values.appName` und `.Values.image.repository : .Values.image.tag ` zur Laufzeit durch die tatsächliche Werte ersetzt. Im einfachsten Fall werden diese Werte direkt über eine values.yaml bereitgestellt, die wie folgt aussehen kann:

Zum Rendern des Charts können die Befehle `helm install` oder `helm template`  verwendet werden. Der Befehl `helm install` sendet die gerenderten Manifest Dateien direkt an den Kubernetes-API-Server. `helm template` zeigt das gerenderte Manifest nur in der Konsole an. Das generierte Manifest aus dem Beispeil oben sähe folgendermaßen aus:

 

Wie werden in Helm Werte transformiert?

Vordefinierte Funktionen

Die vordefinierten Funktionen von Helm verarbeiten und manipulieren Variablen im Template, bevor sie in Kubernetes-Manifeste gerendert werden. Funktionen sind einfache, zweckgebundene Operationen, die eine bestimmte Aufgabe erfüllen, z. B. die Formatierung einer Zeichenfolge, die Konvertierung eines Werts in einen anderen Datentyp oder die Durchführung einer mathematischen Operation. Die Funktion `quote` zum Beispiel schließt eine Zeichenkette in Anführungszeichen ein. Sie können wie folgt verwendet werden:

 

Pipelines

Die Pipeline-Syntax erlaubt es mehrere Funktionen und Ausdrücke miteinander zu verketten, wodurch eine Reihe von Transformationen für eine Variable definiert werden kann. Eine Pipeline nimmt die Ausgabe eines vorangehenden Funktion oder eines Ausdruckes und leitet sie an die folgende Funktion weiter. Das nächste Beispiel zeigt, wie man Pipelines dazu verwenden kann den Wert einer Variable appName durch mehrere Funktionen zu leiten und so zu transformieren. Die Funktion `split` trennt den Inhalt des Strings appName in ein Array von Teilstrings, wobei das Zeichen `-` als Trennzeichen verwendet wird, und die Funktion `index` wählt das zweite Element dieses Arrays aus:

 

Benutzerdefinierte Funktionen

Zusätzlich zu den vordefinierten Funktionen können benutzerdefinierte Funktionen für Templates erstellt werden. Im Chart können diese Funktionen innerhalb eines Templates oder einer separaten .tpl-Datei definiert werden. Es ist üblich, benutzerdefinierte Funktionen in der `_helper.tpl` Datei im templates Ordner des Charts zu definieren, da so alle benutzerdefinierten Funktionen an einem einzigen Ort organisiert werden können und im gesamten Chart wiederverwendet werden können. Hier ein Beispiel für eine benutzerdefinierte Funktion, die einen gegebenen String großschreibt und ihn in Anführungszeichen einschließt:

Wenn das obige Beispiel in  der`templates/helper.tpl` Datei definiert ist, kann es wie folgt verwendet werden:

Wie funktionieren Bedingungen in Helm?

Sie können if-Anweisungen in Helm verwenden, um bestimmte Teile eines Templates basierend auf dem Wert einer Variablen auszuführen. Sie ermöglichen die Aktivierung oder Deaktivierung einer Funktion oder die bedingte Erstellung von Ressourcen. Sie ermöglichen es Ihnen, flexiblere Templates zu entwerfen, die sich an verschiedene Umgebungen anpassen. Die grundlegende Syntax einer if-Anweisung in Helm lautet wie folgt:

Die Minuszeichen ´-´ entfernen führende und nachfolgende Leerzeichen in der Ausgabe.

Aufbau eines Helm Charts für eine Spring Boot Anwendung

Um eine Anwendung in ein Helm Chart zu packen, müssen mehrere Voraussetzungen erfüllt sein. Die Anwendung, die Sie in das Chart packen möchten, muss containerisiert sein. Für das folgende Beispiel kann das öffentlich verfügbare Image public.ecr.aws/viadee/k8s-demo-app verwendet werden. Außerdem wir der Zugriff auf einen Kubernetes-Cluster benötigt, in dem das Chart bereitgestellt werden kann, und die Helm CLI muss auf dem lokalen Rechner installiert sein. Sobald die notwendigen Voraussetzungen erfüllt sind, kann ein benutzerdefiniertes Helm Chart erstellt werden. Der Prozess umfasst die folgenden Schritte:

  1. Erstellen des Chart-Gerüsts
  2. Bearbeitung der Metadaten des Charts
  3. Bearbeitung der Standardwerte für das Chart
  4. Bearbeitung der Templates
  5. Das Chart verpacken und in ein Chart Repository hochladen

1. Erstellen des Chart-Gerüsts

Das Erstellen eines neuen Helm Charts kann auf verschiedene Weise erfolgen, aber eine der effizientesten Methoden ist die Verwendung des Befehls `helm create`. Dieser Befehl generiert die grundlegende Dateistruktur und Beispieldateien für ein neues Chart, sodass es nicht mehr manuell eingerichtet werden muss. Der Befehl bietet unter anderem die Vorteile, dass bei der Generierung bereits die Best Practices für die Entwicklung von Helm Charts eingehalten werden, sie erleichtert Konsistenz über mehrere Charts hinweg zu erreichen und sie verringert die Möglichkeit manuelle Fehler einzubauen, da man kleinteiliger arbeiten kann. Außerdem bietet der Befehl einen guten Ansatzpunkt, um zu verstehen, wie jeder Teil des Charts funktioniert. Der Befehl `Helm create` erwartet den Namen des Charts als Argument:

Die erstellte Dateistruktur sieht wie folgt aus:

2. Bearbeitung der Metadaten des Charts

Obwohl es nicht notwendig ist, kann es hilfreich sein, die generierte Chart.yaml zu überarbeiten. Sie enthält die Metadaten des Charts, einschließlich seines Namens, seiner Version und seiner Beschreibung. Der Befehl `Helm create` setzt das name Feld, sodass es unwahrscheinlich ist, dass es in der Chart.yaml geändert werden muss, aber es ist möglich. Der Name identifiziert das Chart, wenn es in ein Chart Repository hochladen wird. In einem generierten Chart wird er auch in den Templates verwendet, um die Ressourcen zu benennen. Das Feld description enthält eine kurze Beschreibung des Charts. Das version Feld sollte dem semantischen Versionsstandard folgen, zum Beispiel "1.10.3". Das Feld version ermöglicht die Angabe der Chart-Version für den Upload in ein Chart Repository. Schließlich definiert das Feld appVersion die Version der Anwendung, die das Chart einsetzt. Dieses Feld wird in den standardmäßig generierten Templates referenziert, um die Image-Version der Deployment-Kubernetes-Ressource festzulegen.

Hier ist ein Beispiel für eine Chart.yaml Datei:

3. Bearbeitung der Standardwerte für das Chart

Der erste Wert, der geändert werden muss, ist image.repository in der Datei values.yaml. Er gibt das für die Bereitstellung verwendete Container-Image an und muss auf das gewünschte Image aktualisiert werden. Um diesem Beispiel zu folgen, sollte der Wert image.repository auf public.ecr.aws/viadee/k8s-demo-app gesetzt werden.

Da die angegebene appVersion auch ein gültiges Image-Tag ist, muss der Wert image.tag nicht gesetzt werden. Die generierte Datei template/deployment.yaml verwendet die Ausdrücke `.Values.image.repository : .Values.image.tag | default .Chart.AppVersion´, um das Container-Image für das Deployment anzugeben. Die Zeile besteht aus zwei Ausdrücken, die durch einen Doppelpunkt `:` getrennt sind. Der Ausdruck `.Values.image.repository` ruft den Wert des Repository-Feldes aus dem Image-Abschnitt in der Datei values.yaml ab. Der Ausdruck `.Values.image.tag | default .Chart.AppVersion` gibt den appVersion-Wert zurück, wenn der Wert image.tag nicht definiert oder leer ist.

Zusätzlich zum Wert image.repository muss auch der Wert service.port in der Datei values.yaml geändert werden. In einem generierten Chart definiert dieser Wert den Port, den der Service für das Deployment bereitstellt. Er steuert auch, wo Kubernetes Liveness- und Readiness-Probes erwartet. Standardmäßig ist der service.port 80 in einem genertierten Chart, während der Standardport einer Spring Boot Anwendung 8080 ist.  Wenn die Ports nicht übereinstimmen, bleibt der Pod in einer CrashLoopBackOff stecken.

Dies sind alles notwendige Änderungen, um Ihr eigenes Spring Boot-Container-Image auszuführen. Darüber hinaus unterstützt das Chart Funktionen wie die Anpassung der Ressourcenlimits, das Hinzufügen von Image-Pull-Secrets, die Referenzierung eines bestehenden Service-Accounts und die Aktivierung eines Ingress. Sie können den Befehl `helm template` verwenden, um Änderungen an Ihrem Helm Chart schnell zu testen, bevor Sie es installieren. Der Befehl zeigt an, ob Ihr Chart Syntaxfehler aufweist. Wenn die Syntax korrekt ist, können Sie prüfen, ob das erstellte Kubernetes-Manifest yaml Ihren Erwartungen entspricht.

Der Befehl template benötigt zwei Parameter: den Namen der Veröffentlichung und den Pfad zum Chart-Verzeichnis. In unserem Beispiel ist `my-release` der Name des generierten Release, und `.` legt das aktuelle Verzeichnis als Chart-Verzeichnis fest. Ein Helm Release ist ein Helm Chart, das durch die Installation oder Aktualisierung des Charts mit `helm install` oder `helm upgrade` in einem Kubernetes-Cluster  erstellt wurde. Ein Release hat einen eindeutigen Namen, der mit einem bestimmten Satz an Konfigurationswerten verknüpft ist. In diesem Beispiel erzeugt der Befehl `helm template` das yaml-Manifest für ein Release namens`my-release`. Dabei werden die in der Datei values.yaml angegebenen Konfigurationswerte verwendet.

Hier ist ein Auszug aus dem generierten yaml-Manifest:

Sie können den Befehl `Helm install` mit denselben beiden Parametern verwenden wie den template Befehl, um das Chart in ein Kubernetes-Cluster zu bringen. Der Befehl erstellt die Ressourcen im Cluster und eine neue Version des Helm Release. Helm speichert in einer Historie alle Versionen eines Releases und ermöglicht ein Rollback zu einer älteren Version.

4. Bearbeitung der Templates

An diesem Punkt enthält das generierte yaml-Manifest des Deployments eine Liveness- und Readiness-Probe, die auf den Basispfad der Spring Boot Anwendung zeigt. Ein besserer Ansatz wäre es, die dedizierten Actuator-Endpunkte zu verwenden. Ab Spring Boot Version 2.3 wurden die Klassen LivenessStateHealthIndicator und ReadinessStateHealthIndicator hinzugefügt, um den aktuellen Liveness- und Readiness-Status der Anwendung anzuzeigen. Spring Boot registriert diese Aktuatoren automatisch beim Deployment in Kubernetes. Die Endpunkte /actuator/health/liveness und /actuator/health/readiness dienen als Liveness- und Readiness-Probes.

Da das Chart nun den Start der Anwendung in Kubernetes ermöglicht, besteht der nächste Schritt darin, die Möglichkeit zur Konfiguration der Anwendung hinzuzufügen. Spring Boot Anwendungen verwalten die Konfiguration in application.properties- oder application.yaml Dateien. Diese Dateien enthalten Schlüssel-Wert-Paare, die verschiedene Konfigurationen wie z. B. die URL der Datenbankverbindung, den Server-Port und andere Einstellungen definieren. In der Regel muss die Konfiguration je nach Umgebung, in der die Anwendung ausgeführt wird, geändert werden. So wird sich beispielsweise die URL der Datenbankverbindung für Entwicklungs-, Staging- und Produktionsumgebungen unterscheiden. Beim Deployment einer Anwendung in mehreren Umgebungen ist es wünschenswert, denselben Build zu verwenden und dennoch die Möglichkeit zu haben, zwischen verschiedenen Konfigurationssätzen zu wechseln. Ohne diesen Ansatz müsste der Anwendungscode jedes Mal neu erstellt werden, wenn eine Konfigurationsänderung erforderlich ist. Glücklicherweise verfügt Spring Boot über eine Funktion namens "externalized configuration", die das Festlegen von Konfigurationen über Umgebungsvariablen unterstützt. Durch die Externalisierung der Konfiguration ist es möglich, dasselbe Artefakt für verschiedene Umgebungen zu verwenden und dennoch zwischen verschiedenen Sätzen von Konfigurationswerten zu wechseln.

Durch die Möglichkeit eine Spring Boot Anwendung extern zu konfigurieren kann es über native Kubernetes-Mechanismen angesteuert werden. In Kubernetes können ConfigMaps oder Secrets verwendet werden, um Konfigurationen zu speichern. ConfigMaps speichern Datenpaare, die nicht sensibel sind, wie z. B. Anwendungskonfigurationen, Feature-Flags und Datenbankverbindungsstrings. Secrets werden zum Speichern sensibler Daten wie Kennwörter und Tokens verwendet. Pods können auf die gespeicherte Konfiguration in ConfigMaps oder Secrets zugreifen, indem sie diese als Umgebungsvariablen laden oder diese als Datei mounten. Um diese Funktionalität in das eigene Chart zu integrieren muss ein neues Template für die ConfigMap angelegt werden und das bestehende Temaplte für das Deployment erweitert werden.

Zunächst wird eine neue Datei für das ConfigMap Template im Verzeichnis ./templates erstellt:

Als Nächstes wird der Name der ConfigMap durch denselben Ausdruck ersetzt, den die anderen Ressourcen zum Festlegen ihres Namens verwendet haben:

Nun muss die ConfigMap als Umgebungsvariablen in das Deployment geladen werden. Dazu wird `envFrom` verwendet:

Um die Konfiguration über das Chart steuern zu können, muss ein neuer Wert in der values.yaml hinzugefügt werden und dieser im ConfigMap Template referenziert werden. In diesem Beispiel werden die Properties welcome.text und nav.bgcolor hinzugefügt, die das sichtbare Verhalten der public.ecr.aws/viadee/k8s-demo-app ändern. Es gibt jedoch ein Problem: Betriebssysteme erzwingen strenge Namenskonventionen für Umgebungsvariablen. Linux-Shell-Variablen können beispielsweise nur Buchstaben (Groß- oder Kleinbuchstaben), Zahlen (0-9) oder Unterstriche enthalten. Leider widersprechen diese Regeln dem Benennungssystem von Spring. Glücklicherweise berücksichtigt die flexible Property-Bindung von Spring Boot die Einschränkungen so weit wie möglich. Aber um sicherzustellen, dass die Properties erkannt werden, sollten Sie die diese nach den folgenden Regeln umbenennen:

  1. Punkte durch Unterstriche ersetzen
  2. Bindestriche entfernen.
  3. Alle Buchstaben zu Großbuchstaben umwandeln.

Der Ausdruck `- toYaml .Values.properties | nindent 4` kann dazu verwendet werden um yaml Blöcke zu übernehmen. Die Funktion `toYaml` wird direkt von Helm bereitgestellt und wandelt eine Variable zu einer yaml Zeichenkette um. Die Funktion `nindent`rückt die Ausgabe um eine bestimmte Anzahl von Leerzeichen ein. Das Bindestrich-Symbol `-` vor der Funktion toYaml steht für "no whitespace", d.h. es werden alle führenden Leerzeichen in der Ausgabe eliminiert. Es reicht nicht aus, den Ausdruck `.Values.properties` zu verwenden, um auf den Wert zuzugreifen, da er einen komplexen Datentyp zurückgibt, den Helm in der generierten yaml als `map[NAV_BGCOLOR:lightblue WELCOME_TEXT:Hello world.]` ausgibt.

Zu diesem Zeitpunkt würde die Spring Boot Anwendung nicht bemerken, wenn Sie den Inhalt des `properties` Feldes ändern, da die ConfigMap als Umgebungsvariable injiziert wird und nur neu geladen wird, wenn der Pod neu gestartet wird. Um einen Pod-Neustart zu erzwingen, muss die Deployment-Spezifikation selbst geändert werden. Sie können dies erreichen, indem Sie der Spezifikation des Pod-Templates eine Annotation hinzufügen, die sich ändert, wenn sich die Konfiguration ändert. Dann wird Kubernetes die Änderungen melden und einen Neustart erzwingen.

Der Ausdruck `.Values.properties | quote | sha256sum` nimmt den Wert des `property` Feldes, setzt ihn in Anführungszeichen und errechnet seinen SHA-256-Hash. Das Ergebnis des Ausdrucks ist der eindeutige Bezeichner für das Property-Feld, der zur Erkennung von Änderungen an der Konfiguration verwendet wird.

5. Das Chart verpacken und in ein Chart Repository hochladen

Das von der Community gepflegte Chart Repository heißt Artifact Hub, es kann aber auch ein eigenes Repository betreiben werden. Einige andere beliebte Chart-Repositories sind:

  • Chart Museum: Ein einfaches open-source Chart Repository, welches on-premise oder in der Cloud betrieben werden kann.
  • Harbor: Ein open-source Chart Repository mit fortgescrhittenen Features wie Rollen-basierter Zugriff und Image Signierung
  • GitHub Pages: Bei dieser Methode wird ein git Repository mit einem gh-page Branch erstellt und die Charts in diesem Branch gespeichert.

Um das Chart zu einem Repository hinzuzufügen, muss es zunächst gepackt werden. Mit dem Befehl `helm package` wird eine .tgz-Datei erstellt, die alle erforderlichen Dateien und Metadaten für das Chart enthält. Sobald das Chart gepackt ist, kann Sie es mit verschiedenen Methoden in ein Chart Repository übertragen werden. Bei einigen beliebten Chart-Repositories, wie z. B. Harbor, können Sie Charts über eine Weboberfläche hochladen, während Sie bei anderen, wie z. B. Chart Museum, ein CLI-Tool verwenden müssen. Ein Beispiel für die Verwendung von GitHub-Pages zum Hosten eines Repositorys findet sich hier: https://github.com/viadee/spring-boot-helm-chart/blob/main/.github/workflows/publish.yml. Um ein Helm Chart aus einem Chart Repository zu installieren, können Sie den Befehl `helm install` verwenden, aber anstatt auf das lokale Chart zu verweisen, verweisen Sie auf das Repository.

Fazit

Helm ist ein mächtiges Tool für die Verwaltung von Anwendungen in einem Kubernetes-Cluster. Wenn Sie in einer Umgebung arbeiten, in der Sie eine Vielzahl an Anwendungen bereitstellen und verwalten müssen, kann Helm dazu beitragen, diesen Prozess zu optimieren und den erforderlichen Zeit- und Arbeitsaufwand zu reduzieren. Obwohl Helm den Deployment-Prozess vereinfachen kann, kann es dabei dennoch die Komplexität Ihrer Umgebung erhöhen, da es eine weitere Abstraktionsebene einführt. Wenn Ihre Anwendung leicht auszurollen ist und wenig Konfiguration bedarf, ist der Einsatz von Helm möglicherweise nicht notwendig. Letztendlich müssen Sie bei der Entscheidung bedenken, welche Use-cases Sie abdecken wollen. Selbst für kleine Anwendungen kann Helm Ihren Deployment-Prozess leichter nachvollziehbar machen. Wenn Sie hingegen bereits viel automatisiert haben, ist es vielleicht besser, Ihre Anwendungen direkt auf Ihrem Cluster zu deployen, ohne Helm einzusetzen, oder eine schlankere Lösung wie kustomize zu verwenden.

Referenzen

Helm Chart Git Repository: https://github.com/viadee/springboot-helm-chart

Helm cli: https://helm.sh/docs/intro/install/


zurück zur Blogübersicht

Diese Beiträge könnten Sie ebenfalls interessieren

Keinen Beitrag verpassen – viadee Blog abonnieren

Jetzt Blog abonnieren!

Kommentare

Jan Weyrich

Jan Weyrich

Jan Weyrich arbeitet als Architekt und Entwickler bei der viadee, wo er Kunden in allen Fragen der Planung und der Entwicklung von maßgeschneiderten Software-Lösungen berät. Er nutzt sein tiefes Verständnis von Entwicklungsprozessen zur Lösung der Herausforderungen, denen Unternehmen in diesem Bereich begegnen. Sein aktueller Schwerpunkt liegt auf der Konzeption von sicheren und skalierbaren Lösungen im Cloud-Umfeld.