Keycloak in Kubernetes installieren
Praxisleitfaden zur Installation von Keycloak in einem K3s-Cluster
Keycloak in Kubernetes installieren
Keycloak ist ein bewährter Begleiter, wenn es um Authentifizierung und Autorisierung von Nutzern geht. Ganz gleich, welche Plattform wir aufbauen – ein durchdachtes User- und Rechtemanagement ist von Anfang an essenziell. Eine einfache und zugleich effiziente Lösung besteht darin, Keycloak als zentralen Authentifizierungsanbieter zu nutzen. Bei Bedarf können wir es auch mit bestehenden internen Verzeichnissen wie LDAP kombinieren.
Eine sauber aufgesetzte User Federation ist für jede Plattform unverzichtbar. Ohne zentrale Benutzerverwaltung verlieren wir schnell den Überblick – was schnell zu Sicherheitslücken führt, etwa durch zu weitreichende Berechtigungen, fehlende Kontrolle oder mangelnde Nachvollziehbarkeit.
Ein gutes System-Logging sollte im besten Fall immer erfassen, welcher Nutzer welche Aktion ausgelöst hat. So können wir im Nachhinein genau nachvollziehen, was passiert ist – ein wesentlicher Bestandteil für Governance und Compliance.
⚠️ In diesem Artikel gehen wir von einem laufenden Kubernetes-Cluster aus – konkret einem Multi-Node-K3s-Setup mit installiertem Rancher.
💡 Technischer Kontext: In diesem Setup dient Keycloak als zentrales Identity-Management-System. Benutzer können sich über Keycloak authentifizieren, während Rechte im Cluster (z. B. via Rancher) rollenbasiert zugewiesen werden. Externe Verzeichnisse wie LDAP lassen sich anbinden, sind hier aber optional.
Wie wir diesen Cluster aufgesetzt haben, beschreiben wir hier: Setup K3s Cluster
Keycloak Einführung
Keycloak ist eine Quarkus-Anwendung (bis Version 17 basierte sie noch auf WildFly) und kann auf verschiedene Arten installiert werden. Für Testzwecke reicht ein einfacher Docker-Container aus. Für produktive Plattformen mit hohen Sicherheitsanforderungen empfiehlt sich hingegen eine dedizierte Installation – idealerweise in einem eigenen, isolierten Cluster und mit einer extern verwalteten PostgreSQL-Datenbank. Auch eine durchdachte Backup-Strategie und ein Plan für Disaster Recovery sollten in solchen Szenarien von Anfang an mitgedacht werden.
Zwischen diesen beiden Extremen gibt es zahlreiche Varianten. In unserem Fall nutzen wir einen bestehenden Cluster und setzen Keycloak mithilfe des Codecentric-Helm-Charts auf. Als Storage-Lösung verwenden wir Longhorn, und für das Backup setzen wir auf MinIO – eingebunden in unsere Cluster-Backup-Strategie.
🔧 Wie wir Longhorn zusammen mit MinIO für automatisierte Backups konfigurieren, beschreiben wir in einem separaten Artikel: [Coming Soon].
Codecentric Keycloak Helm Chart
Wir haben uns für das Helm-Chart von Codecentric entschieden. Es handelt sich um ein Set sorgfältig gepflegter Charts, die bereits produktionsnah vorkonfiguriert sind.
Es wird ausdrücklich empfohlen, Keycloak mit einer dedizierten Datenbank zu betreiben – wir sprechen hier durchgehend von möglichst produktionsnahen Szenarien.
⚠️ Hinweis zur Produktionsreife
Dieses Setup ist produktionsnah, aber nicht zwangsläufig produktionsreif. Wir setzen bewusst auf pragmatische Lösungen mit geringem Betriebsaufwand – z. B. eine dedizierte Datenbank oder aktivierte Verschlüsselung per Konfigurationsschalter.Für komplexere Anforderungen – etwa Multi-Tenancy, automatisches Horizontal-Scaling oder ein integriertes Backup- und Restore-Konzept – müssen zusätzliche Maßnahmen ergriffen werden. Diese Aspekte hängen stark von der Zielumgebung und den konkreten Sicherheits- und Verfügbarkeitsanforderungen ab.
In diesem Artikel konzentrieren wir uns bewusst auf ein konkretes, funktionierendes Setup – eine vollständige Betrachtung aller möglichen Produktionsszenarien würde den Rahmen sprengen.
Aus der Dokumentation des Helm-Charts entnehmen wir folgende wichtige Aussage:
Note that the default configuration is not suitable for production since it uses a h2 file database by default. It is strongly recommended to use a dedicated database with Keycloak.
Die Standardkonfiguration von Keycloak ist also nicht für den produktiven Betrieb geeignet, da hier eine eingebettete H2-Datenbank verwendet wird. Das bedeutet für uns: Wir müssen vor der Installation von Keycloak eine dedizierte Datenbank bereitstellen, auf die Keycloak zugreifen kann.
Wir setzen dabei standardmäßig auf PostgreSQL und wählen die Bitnami-Variante. Bei der Bereitstellung von Datenbanken für kritische Komponenten gibt es einige grundlegende Punkte zu beachten: Sobald wir stateful Komponenten im Kubernetes-Cluster betreiben, benötigen wir eine passende Storage-Lösung – Kubernetes stellt dies nicht automatisch bereit.
Eine beliebte Lösung, die ebenfalls auf Kubernetes basiert, ist Longhorn. In Rancher lässt sich
Longhorn einfach über die UI oder den Marketplace installieren. Longhorn stellt eine eigene StorageClass
bereit, die
von Helm-Charts genutzt werden kann, um automatisch persistente Volumes im Cluster zu erzeugen. Diese Volumes werden
über mehrere Nodes hinweg repliziert, um Hochverfügbarkeit zu ermöglichen.
Wenn wir einen Schritt weitergehen, können wir ein Backup-Ziel wie MinIO, AWS S3 oder GCP Storage einrichten – und so mit minimalem Aufwand für Ausfallsicherheit sorgen.
In unserem Fall ist Longhorn bereits installiert und als Standard-StorageClass
aktiviert. Das bedeutet: Die
PostgreSQL-Datenbank wird automatisch ihre Volumes über Longhorn erstellen. Da Keycloak auf diese PostgreSQL zugreift,
verfügen wir von Anfang an über eine robuste Lösung für Datensicherheit und Backups.
Unser Plan zusammengefasst:
- PostgreSQL installieren (Bitnami Chart)
- KeycloakX installieren (Codecentric Chart)
PostgreSQL installieren
PostgreSQL wird als Helm-Chart von Bitnami bereitgestellt und bietet eine Vielzahl an Konfigurationsoptionen, die in der offiziellen Dokumentation ausführlich beschrieben sind. Wir fassen hier die für unseren Anwendungsfall wichtigsten Aspekte zusammen.
Resource Requests und Limits
Die Chart-Dokumentation empfiehlt, resources.requests
und resources.limits
individuell an die eigene Infrastruktur
anzupassen. Bitnami stellt dafür mehrere Presets bereit, die als Ausgangspunkt dienen können – von nano
bis 2xlarge
.
Preset | CPU (requests/limits) | Memory (requests/limits) |
---|---|---|
nano | 100m / 150m | 128Mi / 192Mi |
small | 500m / 750m | 512Mi / 768Mi |
medium | 500m / 750m | 1024Mi / 1536Mi |
large | 1.0 / 1.5 | 2048Mi / 3072Mi |
2xlarge | 1.0 / 6.0 | 3072Mi / 12288Mi |
Für unseren Anwendungsfall entscheiden wir uns für das Preset small
, da es eine gute Balance zwischen
Ressourcenverbrauch und Leistungsfähigkeit bietet – insbesondere für Entwicklungs- oder Testumgebungen mit moderatem
Datenbankbedarf.
Keycloak-User und PostgreSQL
Keycloak benötigt selbstverständlich einen eigenen Benutzer, um auf die Datenbank zugreifen zu können. Dabei sollten wir mindestens ein sicheres Passwort setzen – idealerweise würden wir das Passwort regelmäßig rotieren, was jedoch in diesem Beispiel nicht abgedeckt wird.
Statt das Passwort im Klartext in der values.yaml
zu hinterlegen, nutzen wir ein Kubernetes-Secret. Da sich Keycloak
im selben Namespace befindet, kann es dieses Secret problemlos referenzieren. In der Keycloak-Konfiguration verwenden
wir dazu die Einstellung existingSecret
.
Damit die Datenbank und der zugehörige Benutzer beim Deployment direkt angelegt werden, müssen wir zudem die
entsprechenden Werte unter dem auth
-Block definieren.
StorageClass
Unsere Standard-StorageClass ist bereits auf Longhorn gesetzt. Wir definieren sie dennoch explizit im Chart, um die Konfiguration nachvollziehbar und stabil zu halten:
1
primary.persistence.storageClass: "longhorn"
Replikation
Das Bitnami-Chart unterstützt zwei Betriebsmodi: standalone
und replication
.
Im Modus standalone
wird genau ein Pod für PostgreSQL gestartet. Dieser läuft als StatefulSet, was bedeutet, dass
Kubernetes bei einem Ausfall automatisch einen Ersatz-Pod startet – das darunterliegende Volume bleibt erhalten. Da
Longhorn die Volumes zusätzlich über mehrere Nodes repliziert, erreichen wir auch im Standalone-Modus bereits eine
gewisse Ausfallsicherheit.
Der Replikationsmodus des Bitnami-Charts erlaubt den Betrieb mehrerer PostgreSQL-Instanzen mit einer Primary und mehreren Read Replicas. Dabei übernimmt die Primary alle Schreibzugriffe, während die Replicas ausschließlich lesend genutzt werden können. Für unser Setup ist das jedoch nicht erforderlich: Keycloak erzeugt keine signifikante Lese-Last auf der Datenbank, und das Helm-Chart von Codecentric bietet keine native Unterstützung zur expliziten Nutzung von Read Replicas. Daher bleiben wir bei der einfacheren und stabilen standalone-Variante.
Dank Longhorn ist unsere Datenhaltung bereits redundant. Sollte der PostgreSQL-Pod fehlschlagen, wird automatisch ein neuer Pod mit Zugriff auf das bestehende Volume gestartet – der Betrieb von Keycloak bleibt dadurch stabil.
Volume-Größe
Die gewünschte Größe des Volumes definieren wir direkt im Chart. Ein Vorteil von Longhorn ist, dass sich Volumes im Nachhinein problemlos erweitern lassen. Daher starten wir zunächst mit einer moderaten Größe von 2 GiB, was für unsere Umgebung ausreichend ist:
1
primary.persistence.size: "2Gi"
Finale Konfiguration
Fassen wir noch einmal zusammen:
- Wir setzen das Ressourcen-Preset auf
small
(in einer echten Produktionsumgebung würden wir die Werte exakt auf unsere Infrastruktur abstimmen). - Wir legen eine initiale Datenbank samt Benutzer für Keycloak an.
- Wir definieren ein separates Admin-Passwort für PostgreSQL.
- Wir hinterlegen ein Benutzerpasswort für Keycloak.
- Wir referenzieren das Secret über
existingSecret
.
Die finale Konfiguration sieht wie folgt aus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# postgres-values.yaml
architecture: standalone
global:
defaultStorageClass: longhorn
auth:
username: keycloakx
database: keycloakx
existingSecret: postgres-auth-secret
secretKeys:
adminPasswordKey: postgres-password
userPasswordKey: password
replicationPasswordKey: replication-password
primary:
resourcesPreset: small
persistence:
size: 2Gi
metrics:
enabled: true
serviceMonitor:
enabled: true
labels:
release: rancher-monitoring
Und das dazugehörige Secret, das wir vor dem Deployment anlegen:
1
2
3
4
5
6
7
8
9
10
# postgres-auth-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: postgres-auth-secret
type: Opaque
stringData:
postgres-password: "<REPLACE_WITH_SECURE_ADMIN_PASSWORD>"
password: "<REPLACE_WITH_SECURE_KEYCLOAK_PASSWORD>"
replication-password: "<REPLACE_WITH_SECURE_REPLICATION_PASSWORD>"
🔐 Hinweis: Die Platzhalter sollten durch sichere, zufällig generierte Passwörter ersetzt werden. Für die lokale Entwicklung kann das manuell erfolgen, in produktiven Setups empfiehlt sich die Integration mit einem Secrets-Manager oder ein automatisierter Passwortgenerator.
Helm-Chart installieren
💡 Es gibt auch eine HA-Variante von PostgreSQL für produktive Umgebungen mit höheren Anforderungen: bitnami/postgresql-ha
Nachdem wir das Secret und die finale Konfiguration vorbereitet haben, können wir das PostgreSQL-Helm-Chart wie folgt installieren:
- Namespace anlegen (falls noch nicht vorhanden):
1
kubectl create namespace keycloakx-system
Secret deployen:
1
kubectl apply -f postgres-auth-secret.yaml -n keycloakx-system
Bitnami-Repo hinzufügen (falls noch nicht vorhanden):
1
2
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
PostgreSQL-Chart mit vorbereiteter Konfiguration installieren:
1
2
3
helm install keycloakx-postgresql bitnami/postgresql \
--namespace keycloakx-system \
-f postgres-values.yaml
KeycloakX installieren
Auch für die Installation von KeycloakX erstellen wir eine eigene config.yaml
und passen sie an unser Szenario an.
Die Konfiguration von KeycloakX kann herausfordernd sein, da es mehrere Ebenen gibt: Die internen Konfigurationsparameter von Keycloak selbst und die Konfigurationsmöglichkeiten über das Helm-Chart. Letzteres verwaltet sowohl Keycloak-spezifische Optionen als auch Kubernetes-Ressourcen wie Ingress, Secrets oder Ressourcenzuweisungen.
Gerade beim Troubleshooting ist es entscheidend zu verstehen:
- Welche Konfiguration erwartet Keycloak?
- Wie wird diese korrekt über das Helm-Chart übergeben?
Hinzu kommt: Für manche Funktionen existieren mehrere Konfigurationswege, die dasselbe Ziel erreichen. Wir zeigen im Folgenden unseren pragmatischen Weg.
Beim Troubleshooting ist es daher wichtig, zu verstehen:
- Welche Einstellung benötigt Keycloak selbst?
- Wie bringen wir diese Einstellung über das Helm-Chart in den Container?
Hinzu kommt, dass es häufig mehrere Möglichkeiten gibt, zum gleichen Ziel zu gelangen. In unserem Beispiel gehen wir Schritt für Schritt vor und erklären unsere Entscheidungen.
Command
Damit Keycloak korrekt startet, müssen wir den Startbefehl explizit über den command
-Block angeben. Dieser sieht wie
folgt aus:
1
2
3
command:
- "/opt/keycloak/bin/kc.sh"
- "start"
Zusätzlich ergänzen wir folgende Flags:
1
2
- "--http-enabled=true"
- "--hostname-strict=false"
--http-enabled=true
: Ermöglicht die Erreichbarkeit von Keycloak über HTTP. In unserem Setup ist das korrekt, da wir einen Ingress mit TLS-Termination (Reverse Proxy) verwenden – der interne Traffic bleibt unverschlüsselt.--hostname-strict=false
: Diese Option ist hilfreich, wenn Keycloak unter verschiedenen Hostnamen erreichbar sein soll. Standardmäßig akzeptiert Keycloak nur exakt definierte Hostnamen. Durch das Deaktivieren dieser Striktheit vermeiden wir mögliche Fehlerquellen, sofern keine expliziten Sicherheitsanforderungen dagegen sprechen.
Ressourcen
Die Ressourcenanforderungen für den KeycloakX-Pod setzen wir wie folgt:
1
2
3
4
5
6
7
resources:
requests:
cpu: "500m"
memory: "1024Mi"
limits:
cpu: "1000m"
memory: "2048Mi"
Wie immer hängt die genaue Konfiguration stark von der Zielumgebung ab – also davon, wie viele Ressourcen im Cluster zur Verfügung stehen und welche Last zu erwarten ist. In unserem Fall stellt diese Konfiguration einen sinnvollen Ausgangspunkt dar.
Datenbank
Als Nächstes konfigurieren wir die Datenbank – das ist obligatorisch, da Keycloak sonst eine eingebettete Datenbank verwendet, die nicht für produktive Szenarien geeignet ist und keine Backup-Möglichkeiten bietet. Wir verweisen hier einfach auf die zuvor eingerichtete PostgreSQL-Datenbank.
1
2
3
4
5
6
7
8
database:
vendor: postgres
hostname: keycloakx-postgresql
port: 5432
database: keycloakx
username: keycloakx
existingSecret: postgres-auth-secret
existingSecretKey: password
Die Werte setzen sich wie folgt zusammen: Unser PostgreSQL-Helm-Release trägt den Namen keycloakx-postgresql
,
entsprechend lautet der Hostname keycloakx-postgresql
. Der Port ist der Standardport von PostgreSQL (5432),
Datenbankname und Benutzername müssen mit der Konfiguration aus unserer postgres-values.yaml
übereinstimmen.
Abschließend referenzieren wir das Secret und verweisen auf den Key password
. Damit weiß Keycloak, dass es sich mit
der Datenbank unter der URI
keycloakx-postgresql.keycloakx-system.svc.cluster.local:5432/keycloakx
verbinden soll und das dazugehörige Passwort im
Secret unter dem Key password
zu finden ist.
Damit ist die Verbindung zur Datenbank vollständig hergestellt.
Keycloak-Umgebungsvariablen
Einige Einstellungen lassen sich nur direkt über die Umgebungsvariablen von Keycloak selbst konfigurieren. Das ist
jedoch kein Mehraufwand, da das Helm-Chart dafür das Feld extraEnv
bereitstellt.
In unserem Fall setzen wir folgende Umgebungsvariablen:
1
2
3
4
5
6
7
8
9
10
extraEnv: |
- name: KEYCLOAK_ADMIN
value: admin
- name: KEYCLOAK_ADMIN_PASSWORD
value: MY_SECRET_PASSWORD
- name: KC_PROXY_HEADERS
value: xforwarded
- name: JAVA_OPTS_APPEND
value: >-
-Djgroups.dns.query=keycloakx-headless
Initialer Admin
KEYCLOAK_ADMIN
und KEYCLOAK_ADMIN_PASSWORD
definieren einen initialen Admin-Benutzer, der beim ersten Start
automatisch angelegt wird. Da Keycloak diese Parameter ausschließlich über Umgebungsvariablen entgegennimmt und das
Helm-Chart sie über extraEnv
als einfachen String-Block weiterreicht, ist es nicht möglich, hier ein Kubernetes-Secret
direkt zu referenzieren. Deshalb muss das Passwort in diesem Fall leider im Klartext gesetzt werden.
Da dieser Benutzer ohnehin nur zur Ersteinrichtung gedacht ist, sollte er nach dem Setup durch einen dauerhaft gesicherten Admin ersetzt und anschließend gelöscht werden.
Proxy-Header und Weiterleitungen
Ein häufiger Stolperstein bei Keycloak in Kombination mit Ingress ist das Verhalten bei Weiterleitungen. Extern wird Keycloak meist über HTTPS angesprochen, intern kommuniziert der Ingress-Controller jedoch per HTTP mit dem Service. Ohne passende Konfiguration interpretiert Keycloak diese Situation falsch – was z. B. zu Redirect-Loops oder Mixed-Content-Fehlern führen kann.
Deshalb setzen wir KC_PROXY_HEADERS
auf xforwarded
, damit Keycloak die vom Ingress gesetzten Header korrekt
auswertet.
Zur Einordnung hier eine Übersicht der häufigsten Proxy-Optionen:
Variable | Gültig ab Version | Zweck |
---|---|---|
KC_PROXY_HEADERS |
17.x+ | Aktiviert Auswertung von Forwarded-Headers |
KC_PROXY |
16–18 | Definiert Proxy-Modus (edge , reencrypt ) |
PROXY_ADDRESS_FORWARDING |
bis 16.x | Legacy-Variante – nicht mehr empfohlen |
In unserem Fall war nur
KC_PROXY_HEADERS=xforwarded
nötig, da wir Traefik mit TLS-Termination einsetzen.
Clustering (JGroups)
Keycloak nutzt JGroups für verteiltes Caching, z. B. für Sessions oder verteilte Locks. Damit sich Instanzen im Cluster finden, müssen wir den DNS-Namen des Headless-Services angeben. Das geschieht über den Java-Parameter:
1
-Djgroups.dns.query=keycloakx-headless
Alternativ ließe sich das verteilte Caching auch vollständig deaktivieren – das hängt vom Setup ab (z. B. bei Singleton-Instanz ohne Replikas).
Ingress
Zum Schluss benötigen wir noch einen Ingress, damit Keycloak auch von außerhalb des Clusters erreichbar ist.
1
2
3
4
5
6
7
8
9
10
11
12
ingress:
enabled: true
ingressClassName: traefik
rules:
- host: keycloakx.osaia.cloud
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- keycloakx.osaia.cloud
secretName: keycloakx-tls-secret
Wir verwenden Traefik als Ingress-Controller, der standardmäßig mit K3s ausgeliefert wird. Wichtig ist, dass die
ingressClassName
mit der installierten Traefik-Instanz übereinstimmt. TLS wird bereits am Ingress terminiert, daher
muss Keycloak nur für HTTP erreichbar sein.
Für den Zugriff über HTTPS benötigen wir ein TLS-Zertifikat, das wir als Kubernetes-Secret einbinden. In unserem Fall
stammen die Dateien fullchain.pem
und privatekey.pem
aus einer internen Zertifizierungsstelle. Alternativ lassen
sich Zertifikate auch mit Let’s Encrypt oder dem cert-manager generieren.
Beide Dateien müssen im selben Verzeichnis liegen und wie folgt ins Cluster eingebunden werden:
1
2
3
4
kubectl create secret tls keycloakx-tls-secret \
--cert=fullchain.pem \
--key=privatekey.pem \
--namespace=keycloakx-system
Finale Konfiguration
Unsere finale Helm-Konfiguration für KeycloakX sieht wie folgt aus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Anzahl der Keycloak-Pods
replicas: 2
# Startkommando für Keycloak
command:
- "/opt/keycloak/bin/kc.sh"
- "start"
- "--http-enabled=true" # Da TLS am Ingress terminiert wird
- "--hostname-strict=false" # Erlaubt verschiedene Hostnamen ohne Fehlermeldung
# Ressourcenanforderungen und -limits
resources:
requests:
cpu: "500m"
memory: "1024Mi"
limits:
cpu: "1000m"
memory: "2048Mi"
# Datenbank-Konfiguration (verweist auf externes PostgreSQL)
database:
vendor: postgres
hostname: keycloakx-postgresql
port: 5432
database: keycloakx
username: keycloakx
existingSecret: postgres-auth-secret
existingSecretKey: password
# Umgebungsvariablen für Keycloak (z. B. Initial-Admin und Proxy-Verhalten)
extraEnv: |
- name: KEYCLOAK_ADMIN
value: admin
- name: KEYCLOAK_ADMIN_PASSWORD
value: MY_SECRET_PASSWORD
- name: KC_PROXY_HEADERS
value: xforwarded
- name: JAVA_OPTS_APPEND
value: >-
-Djgroups.dns.query=keycloakx-headless
# Ingress-Konfiguration für externe Erreichbarkeit
ingress:
enabled: true
ingressClassName: traefik
rules:
- host: keycloakx.osaia.cloud
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- keycloakx.osaia.cloud
secretName: keycloakx-tls-secret
Und schließlich installieren wir Keycloak:
1
2
3
helm upgrade --install keycloakx codecentric/keycloakx \
-f keycloak-values.yaml \
--namespace keycloakx-system
Sobald die Installation abgeschlossen ist, können wir uns mit dem Benutzernamen und Passwort aus den Umgebungsvariablen
KEYCLOAK_ADMIN
und KEYCLOAK_ADMIN_PASSWORD
am Admin-Interface anmelden.
🎉 Herzlichen Glückwunsch – unser Keycloak läuft nun erfolgreich im Cluster und ist extern erreichbar!
Im nächsten Artikel zeigen wir, wie wir Keycloak als OIDC-Provider einsetzen, um zentrale Benutzerverwaltung über mehrere Anwendungen hinweg zu realisieren – inklusive Integration in moderne Frontends, sicheren Login-Flows und rollenbasiertem Zugriff.
Bildnachweis
Image by Pete Linforth from Pixabay
Dieser Beitrag wurde erstellt von OSAIA Consulting – Experten für Platform Engineering, Automatisierung und Softwarearchitektur.
💬 Fragen oder Feedback?
Wir freuen uns über den Austausch – schreibt uns jederzeit über unsere Website.