Kubernetes: CronJobs überwachen

Wie lange ist es her, seit ein Kubernetes CronJob zuletzt erfolgreich gelaufen ist?
Heute ein kurzer Blogbeitrag zum Monitoring von Kubernetes CronJobs.
Der heutige Blog ist für Sie interessant, wenn Sie Ihre Kubernetes CronJobs mit dem verbreiteten Monitoring-Stack des Prometheus Operators (Prometheus Agent, Service Discovery, Grafana) überwachen möchten.
opensight.ch – roman hüsler

Kubernetes CronJobs

Ein CronJob legt in Kubernetes einen Zeitplan fest (ganz ähnlich wie Cron Jobs unter Linux), nach dem ein Job periodisch ausgeführt werden soll. Ist der Ausführungszeitpunkt erreicht, erstellt Kubernetes automatisch ein Job-Objekt, das wiederum einen oder mehrere Pods für die Ausführung erzeugt. Uns interessiert also, wann der Job zuletzt gestartet wurde und ob der Lauf (Pod) erfolgreich abgeschlossen wurde. Auf Kubernetes-Seite haben wir es mit Objekten vom Typ «CronJob», «Job» und «Pod» zu tun.
Die Herausforderung: Die gewünschte Information lässt sich nicht einfach aus einer einzigen Metrik abfragen, sondern mehrere Metriken müssen kombiniert werden. Wir verwenden die folgenden 4 Metriken, um ans Ziel zu kommen:
- kube_job_status_start_time
- kube_job_labels
- kube_pod_labels
- kube_pod_status_phase
Voraussetzungen für das CronJob-Monitoring
Zuerst sollten wir das Kubernetes-Manifest unseres CronJobs mit einigen Labels versehen, damit wir genau diesen Job später in den Metriken wiederfinden:

Metriken kombinieren

kube_job_status_start_time{job_name=~"stockscores-updater.*"}
Die Metrik «kube_job_status_start_time» liefert den Unix-Timestamp der letzten Job-Ausführungen, die der CronJob erzeugt hat. Aber welche davon wurden mit dem Status «Succeeded» abgeschlossen? Um das herauszufinden, muss man die Jobs den erzeugten Pods zuordnen und deren Status abfragen.
Zuerst suchen wir in der Metrik «kube_job_labels» alle vom CronJob erzeugten Jobs mit dem Label «cronjob=stockscores-updater» (siehe Voraussetzungen) und kombinieren sie mit der Metrik von oben (kube_job_status_start_time). Wegen des GROUP_RIGHT-Statements hat die Metrik «kube_job_labels» die höhere Kardinalität: Wir arbeiten mit ihren Labels weiter, aber mit dem Metrikwert (Unix-Timestamp) von kube_job_status_start_time.
kube_job_status_start_time
* ON(job_name) GROUP_RIGHT()
kube_job_labels{label_cronjob="stockscores-updater"}
Jetzt suchen wir in der Metrik der Pod-Labels alle Pods mit dem Label «cronjob=stockscores-updater» (siehe Voraussetzungen):
kube_pod_labels{label_cronjob=~"stockscores-updater"}

Hier sehen wir, dass das Label leider «label_job_name» heisst. Eigentlich müsste es «job_name» heissen, damit wir es zuordnen und unsere Query von oben weiterführen können. Wir brauchen also «label_replace»…
kube_job_status_start_time
* ON(job_name) GROUP_RIGHT()
kube_job_labels{label_cronjob="stockscores-updater"}
* ON(job_name) GROUP_RIGHT()
label_replace(kube_pod_labels, "job_name", "$1", "label_job_name", "(.*)")
Nun ist die Query so weit, dass wir den Pod-Namen der letzten Startzeit des Jobs zuordnen können. Jetzt filtern wir nur noch die Einträge heraus, bei denen auch die Ausführung des Pods erfolgreich abgeschlossen wurde:
kube_job_status_start_time
* ON(job_name) GROUP_RIGHT()
kube_job_labels{label_cronjob="stockscores-updater"}
* ON(job_name) GROUP_RIGHT()
label_replace(kube_pod_labels, "job_name", "$1", "label_job_name", "(.*)")
* ON(pod) GROUP_RIGHT()
kube_pod_status_phase{job="kube-state-metrics",phase=~"Succeeded"}
Kubernetes CronJob Monitoring - Fazit
An diesem Punkt haben wir eine Metrik mit dem Unix-Timestamp (Startzeit) aller erfolgreich ausgeführten Pods des CronJobs. Daraus können wir nun die Zeit seit der letzten erfolgreichen Ausführung berechnen, und unser Kubernetes CronJob Monitoring ist fertig.
# k8s cronjob - time since last successful execution
time() - max(
kube_job_status_start_time
* ON(job_name) GROUP_RIGHT()
kube_job_labels{label_cronjob="stockscores-updater"}
* ON(job_name) GROUP_RIGHT()
label_replace(kube_pod_labels, "job_name", "$1", "label_job_name", "(.*)")
* ON(pod) GROUP_RIGHT()
kube_pod_status_phase{job="kube-state-metrics",phase=~"Succeeded"}
)
BY (job_name, label_cronjob)
Das ergibt in der Regel das klassische Sägezahnmuster, das die Zeit seit der letzten erfolgreichen Ausführung zeigt.

Wir hoffen, Sie haben einige Einblicke ins Monitoring von Kubernetes CronJobs gewonnen. Für das grosse Ganze, von der Hardware bis zu den Workloads, lesen Sie unseren Kubernetes-Monitoring-Leitfaden. Weitere DevOps-Blogs finden Sie unter opensight.ch/blog/category/devops