Inhaltsverzeichnis
Automatisches Paperless-ngx Backup in Kubernetes: CronJobs mit dynamischer Pod-Ermittlung
Manchmal ist es notwendig, in einem Kubernetes-Cluster regelmäßig Aufgaben auszuführen, die sich auf laufende Anwendungspods beziehen. Denken Sie an die Erstellung von Backups, das Generieren von Berichten oder das Ausführen von Wartungsskripten. Kubernetes bietet hierfür CronJobs an. Doch was, wenn der Ziel-Pod für Ihre Aufgabe nicht immer denselben Namen hat, weil er zum Beispiel bei jedem Deployment neu erstellt wird oder dynamisch skaliert wird?
Genau hier kommt die dynamische Pod-Ermittlung in Kubernetes CronJobs
ins Spiel! In diesem Blogbeitrag zeigen wir Ihnen, wie Sie einen Kubernetes CronJob konfigurieren, der den zu interagierenden Pod dynamisch zur Laufzeit identifiziert. Dies macht Ihre Automatisierung robuster und wartungsfreundlicher, da Sie den CronJob nicht bei jeder Pod-Änderung anpassen müssen.
Warum dynamische Pod-Ermittlung?
Stellen Sie sich vor, Sie haben eine Anwendung wie Paperless-ngx, die in einem Kubernetes-Deployment läuft. Jedes Mal, wenn Sie ein Update bereitstellen oder die Anwendung neu startet, könnte der Pod, in dem die Hauptanwendung läuft, einen neuen Namen erhalten (z.B. paperless-ngx-789abcde-xyz12
). Wenn Ihr CronJob fest an einen spezifischen Pod-Namen gebunden wäre, würde er fehlschlagen, sobald der Pod-Name sich ändert.
Durch die dynamische Ermittlung des Pod-Namens zur Laufzeit des CronJobs umgehen wir dieses Problem vollständig. Der CronJob sucht einfach nach einem Pod, der bestimmte Kriterien erfüllt (z.B. ein spezifisches Label), und führt den Befehl dann im aktuell
gefundenen Pod aus.
Das Kernstück: Der Kubernetes CronJob
Das Herzstück unserer Lösung ist der Kubernetes CronJob. Er definiert den Zeitplan und die auszuführende Aufgabe. Werfen wir einen Blick auf die entscheidenden Teile des Manifests:
# ================================================================= # ServiceAccount, Role, RoleBinding # ================================================================= apiVersion: v1 kind: ServiceAccount metadata: name: kubectl-exec-sa namespace: paperless-production # <-- Anpassen --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-exec-role namespace: paperless-production # <-- Anpassen rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"] - apiGroups: [""] resources: ["pods/exec"] verbs: ["create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: pod-exec-binding namespace: paperless-production # <-- Anpassen subjects: - kind: ServiceAccount name: kubectl-exec-sa namespace: paperless-production # <-- Anpassen roleRef: kind: Role name: pod-exec-role apiGroup: rbac.authorization.k8s.io --- # ================================================================= # CronJob (mit dynamischer Pod-Ermittlung) # ================================================================= apiVersion: batch/v1 kind: CronJob metadata: name: run-document-exporter-dynamic namespace: paperless-production # <-- Anpassen spec: timeZone: Europe/Berlin # Zeitzone für den Zeitplan schedule: "12 5 * * *" # Jeden Tag um 05:12 Uhr concurrencyPolicy: Forbid # Verhindert parallele Ausführungen successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 jobTemplate: spec: template: spec: serviceAccountName: kubectl-exec-sa # Verwendet das ServiceAccount für die Berechtigungen restartPolicy: OnFailure containers: - name: kubectl-executor image: bitnami/kubectl:1.29 # Ein Container mit kubectl command: - "sh" - "-c" - | set -e # Bricht bei Fehlern ab echo "Suche nach einem laufenden Pod mit dem Label-Selector '$TARGET_POD_LABEL_SELECTOR' im Namespace '$KUBERNETES_NAMESPACE'..." # Finde den Namen des ERSTEN laufenden Pods, der dem Label-Selector entspricht. TARGET_POD_NAME=$(kubectl get pods --namespace "$KUBERNETES_NAMESPACE" -l "$TARGET_POD_LABEL_SELECTOR" --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}') # Überprüfe, ob ein Pod-Name gefunden wurde. if [ -z "$TARGET_POD_NAME" ]; then echo "FEHLER: Kein laufender Pod mit dem Label-Selector '$TARGET_POD_LABEL_SELECTOR' gefunden." exit 1 fi echo "Pod '$TARGET_POD_NAME' gefunden. Führe Befehl im Container '$TARGET_CONTAINER_NAME' aus..." # Führe den eigentlichen Befehl aus, jetzt mit dem dynamisch ermittelten Pod-Namen kubectl exec --namespace "$KUBERNETES_NAMESPACE" "$TARGET_POD_NAME" -c "$TARGET_CONTAINER_NAME" -- /bin/sh -c "document_exporter ../export -z --delete" echo "Befehlsausführung erfolgreich abgeschlossen." env: - name: TARGET_POD_LABEL_SELECTOR value: "app.kubernetes.io/name=paperless-ngx" # <-- Anpassen: Label des Ziel-Pods # - name: TARGET_CONTAINER_NAME # value: "<NAME_DES_ZIEL-CONTAINERS_HIER_EINFUEGEN>" # <-- Anpassen (optional): Name des Ziel-Containers - name: KUBERNETES_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace # Der Namespace wird automatisch bereitgestellt
Erläuterung der Schlüsselkomponenten
ServiceAccount, Role, RoleBinding
:ServiceAccount (kubectl-exec-sa)
: Dieses Dienstkonto wird dem CronJob zugewiesen, um ihm die notwendigen Berechtigungen innerhalb des Clusters zu geben.Role (pod-exec-role)
: Diese Rolle definiert die Berechtigungen. Hier erlauben wir dem ServiceAccount, Pods zuget
(abzurufen) und zulist
(aufzulisten) sowiepods/exec
(create
) zu nutzen, um Befehle in einem Pod auszuführen.RoleBinding (pod-exec-binding)
: Dieses Binding verknüpft dasServiceAccount
mit derRole
im angegebenennamespace
.
CronJob (run-document-exporter-dynamic)
:namespace: paperless-production
: Stellen Sie sicher, dass dieser Namespace zu Ihrem tatsächlichen Anwendungs-Namespace passt.timeZone: Europe/Berlin
: Wichtig für die korrekte Planung der Ausführung, insbesondere bei Sommer- und Winterzeitumstellungen.schedule: „12 5 * * *“
: Dies ist der Cron-String. In diesem Beispiel bedeutet er „jeden Tag um 5:12 Uhr“. Passen Sie ihn an Ihre Bedürfnisse an.concurrencyPolicy: Forbid
: Verhindert, dass neue Job-Instanzen gestartet werden, wenn eine vorherige Instanz noch läuft. Dies ist oft ratsam für Wartungsaufgaben.successfulJobsHistoryLimit
undfailedJobsHistoryLimit
: Legt fest, wie viele vergangene Job-Ausführungen im Kubernetes-API gespeichert werden. Nützlich für die Fehlerbehebung.serviceAccountName: kubectl-exec-sa
: Verbindet den Job mit dem zuvor definierten ServiceAccount.image: bitnami/kubectl:1.29
: Dieser Container enthält daskubectl
-Tool, das wir für die Pod-Ermittlung und Befehlsausführung benötigen. Stellen Sie sicher, dass Sie eine passende Version für Ihre Kubernetes-Cluster-Version verwenden.
Dynamische Logik im command Sektion
:set -e
: Stellt sicher, dass das Skript sofort beendet wird, wenn ein Befehl fehlschlägt. Das ist eine gute Praxis für Shell-Skripte.TARGET_POD_NAME=$(kubectl get pods … -o jsonpath='{.items[0].metadata.name}')
: Dies ist der Kern der dynamischen Ermittlung.kubectl get pods
: Listet die Pods auf.–namespace „$KUBERNETES_NAMESPACE“
: Sucht im aktuellen Namespace.-l „$TARGET_POD_LABEL_SELECTOR“
: Filtert die Pods nach einem bestimmten Label.Sie müssen den Wert für TARGET_POD_LABEL_SELECTOR anpassen
, um Ihre Ziel-Anwendung zu identifizieren (z.B.app.kubernetes.io/name=paperless-ngx
).–field-selector=status.phase=Running
: Stellt sicher, dass nurlaufende
Pods berücksichtigt werden.-o jsonpath='{.items[0].metadata.name}
: Extrahiert den Namen desersten
gefundenen Pods aus der JSON-Ausgabe.
Fehlerbehandlung
: Das Skript prüft, ob ein Pod-Name gefunden wurde. Wenn nicht, wird eine Fehlermeldung ausgegeben und das Skript mitexit 1
beendet.kubectl exec –namespace „$KUBERNETES_NAMESPACE“ „$TARGET_POD_NAME“ -c „$TARGET_CONTAINER_NAME“ – /bin/sh -c „document_exporter ../export -z –delete“
: Sobald der Pod-Name ermittelt wurde, wird der eigentliche Befehl (document_exporter ../export -z –delete
) im Ziel-Pod ausgeführt.TARGET_CONTAINER_NAME
: Optional können Sie auch den Namen des spezifischen Containers im Pod angeben, falls der Pod mehrere Container hat und der Befehl in einem bestimmten Container ausgeführt werden muss. Wenn nicht angegeben, versuchtkubectl exec
den Befehl im ersten Container des Pods auszuführenTARGET_POD_LABEL_SELECTOR
: Diesen Wertmüssen Sie anpassen
, um das spezifische Label Ihrer Anwendung zu verwenden. Zum Beispiel:value: „app=my-web-app“
odervalue: „app.kubernetes.io/name=my-application“
.KUBERNETES_NAMESPACE
: Dieser Wert wird automatisch über dieDownward API
aus den Metadaten des Jobs bezogen, was die Konfiguration flexibler macht.
Anpassung und Bereitstellung
Bevor Sie dieses Manifest anwenden, stellen Sie sicher, dass Sie die folgenden Platzhalter in den Kommentaren (# ←- Anpassen
) und den env
-Variablen aktualisieren:
namespace
: Ersetzen Siepaperless-production
durch den tatsächlichen Namespace Ihrer Anwendung.TARGET_POD_LABEL_SELECTOR
: Dies ist das wichtigste Element. Ersetzen Sieapp.kubernetes.io/name=paperless-ngx
durch den Label-Selector, der Ihren Ziel-Pod eindeutig identifiziert. Sie können kubectl get pods -n <your-namespace> –show-labels verwenden, um die Labels Ihrer Pods zu überprüfen.TARGET_CONTAINER_NAME
(optional): Wenn Ihr Ziel-Pod mehrere Container hat und Sie den Befehl in einem bestimmten Container ausführen müssen, uncommenten Sie diese Zeile und geben Sie den Containernamen an.
Sobald Sie die Anpassungen vorgenommen haben, können Sie das Manifest mit kubectl apply -f your-cronjob-manifest.yaml in Ihrem Kubernetes-Cluster bereitstellen.
Fazit
Die Verwendung der dynamischen Pod-Ermittlung in Kubernetes CronJobs ist eine elegante Lösung, um Ihre geplanten Aufgaben widerstandsfähiger gegen Änderungen in Ihrer Pod-Infrastruktur zu machen. Es reduziert den Wartungsaufwand und sorgt dafür, dass Ihre Automatisierung auch in dynamischen Umgebungen zuverlässig funktioniert.