Description
A simple Kubernetes Operator (built with Kubebuilder) that reconciles a
CronJob custom resource (batch.martishin.com/v1, Kind=CronJob).
For each CronJob, the controller ensures Kubernetes Jobs are created
and executed on schedule, similar to the built-in CronJob controller.
The project is built with Bazel and packaged/deployed with Timoni.
Kubebuilderβs kustomize manifests remain for development/CI, but Timoni is
authoritative for installs and upgrades.
Source code is available on GitHub.
Table of contents
Open Table of contents
Description
Goal of the controller
The controller watches CronJob resources and reconciles the desired state:
- Uses
.spec.schedule(cron string) and.spec.jobTemplateto create Jobs. - Maintains
.statusfields (successful/failed job history). - Ensures Jobs run at the expected times.
This demonstrates a production-like operator pattern.
Prerequisites
- Go
- Docker (for building images)
- kubectl (any recent version)
- Timoni CLI (install from https://timoni.sh/)
- Bazel (for builds)
- Access to a Kubernetes cluster (Kind is easiest).
Optional:
- Kind CLI (for local cluster)
- make
Build & Release (Bazel + Timoni)
The Timoni bundle lives at:
timoni/bundles/operator-stack.cue
It includes three instances:
- crds β the CronJob CRD
- operator β controller (RBAC, SA, Deployment, metrics)
- sample β a sample CronJob resource
Quick start on Kind (local)
# 1) (Optional) Create a Kind cluster
kind create cluster --name mycluster
# 2) Build controller image with Bazel
bazel build //:controller_image
# 3) Load the image into Kind
bazel run //:controller_image_load
docker tag kubebuilder/cronjob-controller:dev controller:dev
kind load docker-image controller:dev --name mycluster
# 4) Point Timoni bundle to that image
make bundle-set-image IMG=controller:dev
# 5) Apply with Timoni
make bundle-apply
Preview, apply, status
# Preview manifests
make bundle-build | less
# Diff vs live cluster
make bundle-diff
# Apply & wait
make bundle-apply
# Status
make bundle-status
kubectl -n cronjob-operator-system get deploy,pods
Test reconciliation
# Inspect the sample CronJob
kubectl -n default get cronjob.batch.martishin.com cronjob-sample -o yaml
# Watch Jobs being created
kubectl -n default get jobs -w
# Inspect sample pod logs
kubectl -n default get pods
Uninstall
make bundle-delete
Local development
Run the controller locally
make run
Unit/Envtest & e2e
make test
make test-e2e
Project structure
bazel-kubebuilder-timoni-k8s-cronjob-operator/
βββ api/v1/ # CRD Go types
βββ cmd/main.go # Controller entrypoint
βββ internal/controller/ # Reconciler logic
βββ timoni/
β βββ bundles/operator-stack.cue
β βββ modules/
β βββ cronjob-operator-crds/ # CRD instance
β βββ cronjob-operator/ # Operator instance
β βββ cronjob-sample/ # Sample CronJob
βββ BUILD.bazel, MODULE.bazel # Bazel build files
βββ config/ # Kubebuilder kustomize (dev only)