Konfiguration: ConfigMaps und Secrets
Halte Einstellungen und Zugangsdaten aus deinen Images heraus, injiziere sie in Pods und vermeide die häufigen Fallen.
Ist eine Datenbank-URL oder ein Log-Level in dein Container-Image eingebacken, bedeutet eine Änderung, das Image neu zu bauen, zu pushen und neu zu deployen. Kubernetes trennt Konfiguration von Images mit zwei Objekten: ConfigMaps für gewöhnliche Einstellungen und Secrets für sensible Werte. Diese Anleitung zeigt, wie du beide erstellst, wie du sie in einen Pod bekommst und was Secrets schützen und was nicht.
Eine ConfigMap erstellen
Eine ConfigMap ist eine Menge von Schlüssel-Wert-Paaren. Werte können kurze Strings oder ganze Dateien sein:
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
data:
LOG_LEVEL: info
API_URL: http://api.internal:8080
motd.txt: |
Welcome to the demo environment
Du kannst eine auch von der Kommandozeile erstellen, was für Dateien praktisch ist:
kubectl create configmap web-config \
--from-literal=LOG_LEVEL=info \
--from-file=motd.txt
kubectl describe configmap web-config
ConfigMaps sind für kleine, nicht sensible Daten gedacht (das Limit liegt bei 1 MiB) und gehören zu einem Namespace. Ein Pod kann nur ConfigMaps aus seinem eigenen Namespace nutzen.
Als Umgebungsvariable oder als Datei nutzen
Derselbe Pod kann eine ConfigMap auf beide Arten konsumieren:
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: web
image: nginx:1.25
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: web-config
key: LOG_LEVEL
volumeMounts:
- name: config
mountPath: /usr/share/nginx/html/motd.txt
subPath: motd.txt
volumes:
- name: config
configMap:
name: web-config
Hier passieren zwei Dinge. Der env-Eintrag kopiert einen Schlüssel in eine Umgebungsvariable. (envFrom kann jeden Schlüssel auf einmal importieren, wobei Schlüssel, die keine gültigen Variablennamen sind, übersprungen werden.) Die Einträge volumes und volumeMounts mounten die ConfigMap als Dateien, eine Datei pro Schlüssel.
Mountest du die gesamte ConfigMap wie folgt in ein Verzeichnis, wird das Verzeichnis durch die gemounteten Dateien ersetzt:
volumeMounts:
- name: config
mountPath: /etc/web
Das ist für ein Verzeichnis, das dir gehört, in Ordnung, verdeckt aber alles, was bereits unter diesem Pfad liegt. Ein Mount über ein bestehendes Konfigurationsverzeichnis wie /etc/nginx kann die Anwendung kaputt machen, und der Container kann mit einem Fehler „Datei nicht gefunden“ in eine Absturzschleife geraten. Dafür ist subPath da, wie im ersten Beispiel: Es mountet einen einzelnen Schlüssel als einzelne Datei und lässt den Rest des Verzeichnisses in Ruhe. Der Kompromiss: Mit subPath gemountete Dateien erhalten spätere Aktualisierungen der ConfigMap nicht.
Prüfe, was im Container gelandet ist:
kubectl exec web -- ls /usr/share/nginx/html
kubectl exec web -- env | grep LOG_LEVEL
Zugangsdaten in einem Secret speichern
Ein Secret sieht aus wie eine ConfigMap, ist aber für Passwörter, Tokens und Schlüssel gedacht:
kubectl create secret generic db-credentials \
--from-literal=username=app \
--from-literal=password='S3cr3t-value'
In YAML nutze stringData, um Klartext zu schreiben und Kubernetes kodieren zu lassen:
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
username: app
password: S3cr3t-value
Wenn du das kodierte Feld data selbst schreibst, kodiere mit echo -n 'value' | base64. Ohne -n wird der abschließende Zeilenumbruch Teil des Passworts, und die Authentifizierung schlägt auf verwirrende Weise fehl. Ein Secret konsumierst du auf dieselbe Weise wie eine ConfigMap:
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
Committe keine Secret-Manifeste mit echten Werten in Git. Werkzeuge wie Sealed Secrets, External Secrets Operator und SOPS gibt es, damit du verschlüsselte oder referenzierte Secrets in einem Repository halten kannst.
Wissen, was Secrets schützen und was nicht
Base64 ist eine Kodierung, keine Verschlüsselung. Jeder, der das Secret über die API lesen kann, kann es dekodieren:
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d
Standardmäßig werden Secrets außerdem unverschlüsselt in etcd gespeichert. Um sie tatsächlich zu schützen:
- Beschränke mit RBAC, wer Secrets lesen kann, und denke daran, dass jeder, der in einem Namespace Pods erstellen kann, dessen Secrets mounten kann.
- Aktiviere die Verschlüsselung ruhender Daten für etcd oder nutze die Schlüsselverwaltung eines Cloud-Anbieters.
- Ziehe einen externen Secret Manager in Betracht, wenn deine Anforderungen streng sind.
Umgebungsvariablen sind praktisch, aber leicht zu leaken, da sie in kubectl exec ... env, in Crash-Dumps und manchmal in Logs auftauchen. Ein Secret als Datei zu mounten ist für sensible Werte oft die bessere Wahl.
Konfiguration bewusst aktualisieren
Umgebungsvariablen werden einmal gelesen, wenn der Container startet, sodass eine geänderte ConfigMap oder ein geändertes Secret laufende Pods nicht erreicht. Starte sie neu, um die Änderung aufzugreifen:
kubectl rollout restart deployment/web
Dateien aus einem Mount des ganzen Verzeichnisses werden irgendwann aktualisiert, aber viele Anwendungen lesen ihre Konfiguration ohnehin nur beim Start. Für automatisierte Setups sorge dafür, dass sich das Pod-Template ändert, wann immer sich die Konfiguration ändert. Dafür sind die Config-Hash-Techniken in der Argo-CD-Anleitung zu Helm und Kustomize da.
Beliebte Anleitungen
-
Was Kubernetes ist und welche Probleme es löst Warum Container allein nicht mehr skalieren und wie Kubernetes eine Gruppe von Maschinen zu einer Plattform macht. -
Wie ein Kubernetes-Cluster funktioniert: Control Plane und Knoten Die Komponenten, die einen Cluster am Laufen halten, und was zwischen kubectl apply und einem laufenden Container passiert. -
Deployments: Skalieren, Selbstheilung und Rolling Updates Betreibe Replikas eines Pods, aktualisiere sie ohne Ausfallzeit und rolle zurück, wenn ein Release schiefgeht. -
Services: Stabiles Networking für kurzlebige Pods Gib Pods eine stabile Adresse, stelle sie innerhalb und außerhalb des Clusters bereit und beschränke, wer mit wem sprechen darf. -
Einen fehlschlagenden Pod debuggen: describe, logs, exec und port-forward Eine wiederholbare Checkliste, um herauszufinden, warum ein Pod Pending ist, abstürzt oder nicht antwortet.