Kubernetes integration
Monitor Kubernetes CronJob and Job resources with Drumbeats. Sidecar pattern, init container, and lifecycle hooks for ping wiring.
This guide shows how to wire Drumbeats into Kubernetes CronJob and Job resources. By the end your CronJobs send start / success / failure pings without modifying the application container.
The two patterns that work cleanly are command wrapping (the simplest) and init + sidecar containers (when you cannot edit the workload command). Pick command wrapping unless your workload runs in a vendor image you do not control.
Pattern 1: Command wrapping
Wrap the container command with a small shell snippet. Works for any image that includes curl.
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: ghcr.io/myorg/backup:latest
env:
- name: DRUMBEATS_MONITOR
value: "11111111-2222-3333-4444-555555555555"
command: ["/bin/sh", "-c"]
args:
- |
set -euo pipefail
RUN_ID="k8s-$(date +%s)-$RANDOM"
API="https://api.drumbeats.io/v1/ping/${DRUMBEATS_MONITOR}"
curl -sf --max-time 3 "${API}/start?run_id=${RUN_ID}"
if /usr/local/bin/backup.sh; then
curl -sf --max-time 3 "${API}/success?run_id=${RUN_ID}"
else
curl -sf --max-time 3 "${API}/failure?run_id=${RUN_ID}"
exit 1
fiapiVersion: batch/v1
kind: CronJob
metadata:
name: daily-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: ghcr.io/myorg/backup:latest
env:
- name: DRUMBEATS_MONITOR
value: "11111111-2222-3333-4444-555555555555"
command: ["/bin/sh", "-c"]
args:
- |
set -euo pipefail
RUN_ID="k8s-$(date +%s)-$RANDOM"
API="https://api.drumbeats.io/v1/ping/${DRUMBEATS_MONITOR}"
curl -sf --max-time 3 "${API}/start?run_id=${RUN_ID}"
if /usr/local/bin/backup.sh; then
curl -sf --max-time 3 "${API}/success?run_id=${RUN_ID}"
else
curl -sf --max-time 3 "${API}/failure?run_id=${RUN_ID}"
exit 1
fiThe exit 1 after the failure ping preserves the Job's failure state, so Kubernetes' own retry / backoff logic still fires.
Pattern 2: Init container + sidecar (for unmodifiable workloads)
If you cannot change the workload's command, use an initContainer to send start and a lifecycle.postStop hook on a sidecar to send the result. The pattern is more YAML but works for vendor images:
apiVersion: batch/v1
kind: CronJob
metadata:
name: vendor-export
spec:
schedule: "0 3 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
shareProcessNamespace: true
initContainers:
- name: drumbeats-start
image: curlimages/curl:8.10.1
env:
- name: DRUMBEATS_MONITOR
value: "66666666-7777-8888-9999-aaaaaaaaaaaa"
- name: RUN_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- sh
- -c
- |
curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${DRUMBEATS_MONITOR}/start?run_id=${RUN_ID}"
containers:
- name: workload
image: vendor/export:1.4.0
# ... vendor-provided spec, command unchanged ...
- name: drumbeats-finisher
image: curlimages/curl:8.10.1
env:
- name: DRUMBEATS_MONITOR
value: "66666666-7777-8888-9999-aaaaaaaaaaaa"
command: ["sh", "-c", "trap 'curl -sf --max-time 3 \"https://api.drumbeats.io/v1/ping/${DRUMBEATS_MONITOR}/success?run_id=${HOSTNAME}\"' EXIT; tail -f /dev/null & wait"]apiVersion: batch/v1
kind: CronJob
metadata:
name: vendor-export
spec:
schedule: "0 3 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
shareProcessNamespace: true
initContainers:
- name: drumbeats-start
image: curlimages/curl:8.10.1
env:
- name: DRUMBEATS_MONITOR
value: "66666666-7777-8888-9999-aaaaaaaaaaaa"
- name: RUN_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
command:
- sh
- -c
- |
curl -sf --max-time 3 "https://api.drumbeats.io/v1/ping/${DRUMBEATS_MONITOR}/start?run_id=${RUN_ID}"
containers:
- name: workload
image: vendor/export:1.4.0
# ... vendor-provided spec, command unchanged ...
- name: drumbeats-finisher
image: curlimages/curl:8.10.1
env:
- name: DRUMBEATS_MONITOR
value: "66666666-7777-8888-9999-aaaaaaaaaaaa"
command: ["sh", "-c", "trap 'curl -sf --max-time 3 \"https://api.drumbeats.io/v1/ping/${DRUMBEATS_MONITOR}/success?run_id=${HOSTNAME}\"' EXIT; tail -f /dev/null & wait"]The sidecar approach is fragile — it cannot tell success from failure without inspecting the workload container's exit code. For non-trivial cases prefer Pattern 1 or build a wrapper image around the vendor image.
Job vs CronJob
Job— one-off work. Use Pattern 1 and callkubectl createfrom your scheduler. The Drumbeats monitor type should be Event-driven (JOB_BASIC), not Cron — there is no schedule to enforce.CronJob— scheduled work. Use Pattern 1 and pair with a Cron Drumbeats monitor matching the same schedule + timezone.
Error handling
activeDeadlineSeconds. When Kubernetes terminates a Job past its deadline, the failure ping never fires. Setmax_duration_secondson the Drumbeats monitor to the same value so the hang surfaces server-side.backoffLimitretries. Each retry sends its ownstartping. To deduplicate, include the attempt number inrun_id:RUN_ID="k8s-${POD_NAME}-${RETRY:-0}". Drumbeats stores each attempt as a separate run on the same monitor.- Pod evictions. A pod evicted before the success ping fires registers as a hung run. Pair
max_duration_secondswith thestartping.
Production patterns
- Time-bound pings.
curl --max-time 3keeps a slow Drumbeats request from blocking the Job's completion. - Bundle
curlinto the image. Workloads built onscratchordistrolesswill not havecurl. Either bakecurlinto the image or use the sidecar pattern. - Stable run IDs. Use
metadata.name(the Job name, which embeds the CronJob's timestamp) as therun_id. This lets the Drumbeats dashboard cross-reference the Kubernetes Job from the run history. - Multi-environment via slug. A single manifest can route to different monitors per cluster — see Ping API: scheduled pings for the slug endpoint.
Related guides
- Monitor types — Cron for
CronJob, Event-driven forJob. - Ping API — endpoint and parameter reference.
- Production hardening — retries, timeouts, observability patterns.
- Alternatives — how Drumbeats handles Kubernetes monitoring vs Cronitor and Healthchecks.io.