Dynamisches Konfigurationsmanagement: Verwendung von ConfigMaps für Echtzeit-Anwendungsupdates

Verwenden Sie Kubernetes ConfigMaps als gemountete Dateien für Laufzeit-Konfigurationsupdates, mit Einschränkungen hinsichtlich Propagation, subPath und App-Neuladeverhalten.

Dynamisches Konfigurationsmanagement: Verwendung von ConfigMaps für Echtzeit-Anwendungsupdates

Kubernetes bietet robuste Mechanismen zur Verwaltung des Anwendungszustands, aber das Ändern von Anwendungseinstellungen erfordert oft das Neuerstellen von Images oder das Neustarten von Deployment-Pods. Für viele Microservices ist diese Ausfallzeit oder Störung inakzeptabel. Hier kommen ConfigMaps ins Spiel. ConfigMaps sind Kubernetes-Objekte, die dazu dienen, nicht-vertrauliche Konfigurationsdaten in Schlüssel-Wert-Paaren zu speichern und so die Konfiguration vom Anwendungscode zu entkoppeln.

ConfigMaps helfen beim dynamischen Konfigurationsmanagement, wenn Ihre App Einstellungen aus Dateien liest und diese neu laden kann. Der Kubernetes-Teil ist nur die Hälfte des Setups: Gemountete ConfigMap-Dateien können sich ändern, während der Pod weiterläuft, Umgebungsvariablen jedoch nicht, und Ihre Anwendung muss die neuen Werte dennoch erkennen und anwenden.

Grundlegendes zu ConfigMaps: Die Basis

Ein ConfigMap ermöglicht es Ihnen, Konfigurationsdaten als eine Reihe von Schlüsseln und Werten zu speichern. Im Gegensatz zu Secrets sind ConfigMaps für nicht sensible Konfigurationsdaten wie Logging-Level, externe Service-Endpunkte oder Feature-Flags gedacht.

Erstellen eines Beispiel-ConfigMaps

Konfigurationsdaten können direkt im YAML-Manifest definiert oder aus vorhandenen Dateien oder Verzeichnissen erstellt werden. Erstellen wir ein ConfigMap namens app-settings, das anwendungsspezifische Parameter enthält.

Beispiel: ConfigMap in YAML definieren

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-settings
data:
  # Schlüssel-Wert-Paare
  LOG_LEVEL: "INFO"
  API_ENDPOINT: "https://api.default.svc.cluster.local"
  # Mehrzeiliger Konfigurationsdatei-Inhalt
  application.properties: |
    server.port=8080
    feature.toggle.new_ui=false

Dieses ConfigMap stellt drei Datenpunkte bereit: zwei einfache Schlüssel-Wert-Paare und einen komplexen Eintrag (application.properties), der eine Konfigurationsdatei simuliert.

Injizieren von Konfigurationen in Pods

Während ConfigMaps Umgebungsvariablen befüllen können, liegt der Schlüssel zu dynamischen Updates darin, sie als Volumes im Dateisystem eines Pods zu mounten. Wenn sie als Volume gemountet werden, behandelt Kubernetes jeden Schlüssel im ConfigMap als eine Datei im angegebenen Verzeichnis.

Methode 1: Verwendung von Volume-Mounts (Der dynamische Ansatz)

Um dynamische Updates zu erreichen, mounten wir das ConfigMap in die Pod-Spezifikation.

Beispiel: Pod-Spezifikation mit ConfigMap-Volume-Mount

apiVersion: v1
kind: Pod
metadata:
  name: dynamic-app-pod
spec:
  containers:
  - name: my-app
    image: my-registry/my-app:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config 
  volumes:
  - name: config-volume
    configMap:
      name: app-settings

In diesem Setup:

  1. Das ConfigMap app-settings wird mit dem Volume namens config-volume verknüpft.
  2. Das Volume wird unter /etc/config im Container gemountet.
  3. Kubernetes erstellt automatisch Dateien in /etc/config, die den Schlüsseln im ConfigMap entsprechen:
    • /etc/config/LOG_LEVEL enthält den Wert INFO.
    • /etc/config/application.properties enthält die mehrzeilige Konfiguration.

Methode 2: Verwendung von Umgebungsvariablen (Statischer Ansatz)

Für einfachere, statische Werte können Sie diese als Umgebungsvariablen injizieren. Hinweis: Auf diese Weise befüllte Umgebungsvariablen werden nicht automatisch aktualisiert, wenn sich das ConfigMap ändert; der Pod muss neu gestartet werden.

# Ausschnitt aus einer Deployment-Spezifikation
containers:
- name: my-app
  image: my-registry/my-app:latest
  env:
  - name: LOG_LEVEL
    valueFrom:
      configMapKeyRef:
        name: app-settings
        key: LOG_LEVEL

Best Practice: Verwenden Sie für dynamische Updates immer Volume-Mounts für Konfigurationsdateien.

Erzielen von Echtzeit-Updates: Überwachung auf Änderungen

Wenn ein ConfigMap aktualisiert wird, propagiert Kubernetes die Änderung schließlich an Pods, die es als Volume mounten. Der genaue Zeitpunkt hängt vom Synchronisationsverhalten des Kubelets, dem Cache-Verhalten und der Knotenlast ab. Behandeln Sie es daher als eventuelle Propagation und nicht als sofortigen Push der Steuerungsebene.

Wie das Kubelet Updates propagiert

Wenn ein als Volume verwendetes ConfigMap geändert wird:

  1. Das Kubelet prüft während seines Synchronisationszyklus regelmäßig auf Updates und kann Daten aus seinem lokalen Cache bereitstellen.
  2. Wenn ein Update erkannt wird, aktualisiert das Kubelet die gemounteten Dateien im Host-Dateisystem.
  3. Für den laufenden Container werden die Dateien im ConfigMap-Volume über den projizierten Volume-Mechanismus von Kubernetes aktualisiert.

Es gibt eine häufige Ausnahme: Wenn Sie einen einzelnen ConfigMap-Schlüssel mit subPath mounten, aktualisiert Kubernetes diese gemountete Datei nicht, wenn sich das ConfigMap ändert. Verwenden Sie einen normalen ConfigMap-Volume-Mount, wenn Sie Laufzeit-Updates erwarten.

Erkennung auf Anwendungsseite

Der entscheidende Schritt ist, dass Ihr Anwendungscode, der im Container läuft, so konzipiert ist, dass er diese Dateiänderungen erkennt und darauf reagiert.

Beispiel: Anwendungslogik für Dateiüberwachung (Konzeptionelles Python)

Die meisten modernen Anwendungen verwenden interne Mechanismen oder Bibliotheken, um Dateisystemereignisse zu überwachen (z.B. inotify unter Linux).

import time
import os

CONFIG_PATH = "/etc/config/application.properties"

def load_config(path):
    # Funktion zum Lesen und Parsen des Dateiinhalts
    with open(path, 'r') as f:
        print(f"\n--- Konfiguration neu geladen ---\n{f.read()}")
        # Logik zum erneuten Initialisieren von Diensten mit neuen Einstellungen

# Erstes Laden
load_config(CONFIG_PATH)

# Kontinuierliche Überwachungsschleife
last_modified = os.path.getmtime(CONFIG_PATH)

while True:
    current_modified = os.path.getmtime(CONFIG_PATH)
    if current_modified != last_modified:
        print("Dateiänderung erkannt. Konfiguration wird neu geladen...")
        load_config(CONFIG_PATH)
        last_modified = current_modified
    time.sleep(5) # Alle 5 Sekunden prüfen

Dieses Beispiel demonstriert das Abfragen der Dateiänderungszeit (mtime). Wenn das Kubelet die Datei aktualisiert, erkennt die Anwendung die Änderung und kann die Konfiguration dynamisch neu laden.

Achtung bei Dateiüberwachung: ConfigMap-Volume-Updates können Symlink-Ziele unter dem gemounteten Verzeichnis ersetzen. Wenn Ihr Überwacher nur einem geöffneten Datei-Handle folgt, kann er Updates verpassen. Überwachen Sie das Verzeichnis oder fragen Sie den Dateiinhalt ab, wenn Zuverlässigkeit wichtiger ist als sofortiges Neuladen.

Dynamischer Update-Workflow: Ein Schritt-für-Schritt-Beispiel

Lassen Sie uns das Aktualisieren von LOG_LEVEL von INFO auf DEBUG durchgehen, ohne den laufenden Pod zu berühren.

Schritt 1: Ausgangszustand

Stellen Sie sicher, dass Ihr Pod läuft und das ConfigMap über Volume-Mounts konsumiert.

Schritt 2: Aktualisieren des ConfigMaps

Ändern Sie das vorhandene ConfigMap mit kubectl edit oder kubectl apply.

# Verwenden von kubectl edit, um den Wert direkt zu ändern
kubectl edit configmap app-settings

# Finden und ändern Sie die Zeile:
# LOG_LEVEL: "INFO"
# ZU:
LOG_LEVEL: "DEBUG"

Schritt 3: Überwachung der Propagation

Warten Sie, bis das Kubelet die Änderung propagiert. Dies kann in manchen Clustern länger als ein paar Sekunden dauern.

Wenn Ihre Anwendung /etc/config/LOG_LEVEL überwacht:

  1. Das Kubelet aktualisiert die zugrunde liegende Datei.
  2. Die Anwendung erkennt die Änderung (basierend auf ihrem Überwachungsmechanismus).
  3. Die Anwendung lädt ihre interne Logging-Konfiguration auf DEBUG neu.

Entscheidend ist, dass der Pod selbst unberührt bleibt, was eine vollständige Serviceunterbrechung verhindert.

Zusammenfassung und Überlegungen zum Konfigurationsmanagement

Die Verwendung von ConfigMaps mit Volume-Mounts ist die kanonische Methode, um dynamische Konfigurationsupdates in Kubernetes zu erreichen. Beachten Sie jedoch folgende Punkte:

  • Sicherheit: ConfigMaps speichern Daten im Klartext. Verwenden Sie Secrets für sensible Informationen.
  • Unveränderlichkeit: Erwägen Sie für kritische Konfigurationen, das ConfigMap nach der Erstellung unveränderlich zu machen (immutable: true in der Spezifikation), um versehentliche Laufzeitänderungen zu verhindern.
  • Anwendungsbewusstsein: Die Dynamik ist nur möglich, wenn der laufende Container weiß, wie er die Konfigurationsdateien überwachen und neu laden kann.
  • Rollback: Das Zurücksetzen einer Konfigurationsänderung erfordert das Aktualisieren des ConfigMaps auf den vorherigen Zustand und das Warten auf die Erkennung durch die Anwendung.

Durch die Entkopplung der Konfiguration von Bereitstellungsartefakten und die Nutzung von Volume-Mounts ermöglichen Sie robuste Updates mit null Ausfallzeiten für Konfigurationsparameter in Ihren Kubernetes-Workloads.