Skip to content

martishin/bazel-kubebuilder-timoni-k8s-cronjob-operator

Repository files navigation

Kubebuilder + Timoni + Bazel Kubernetes Operator

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.


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.jobTemplate to create Jobs.
  • Maintains .status fields (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:

  1. crds – the CronJob CRD
  2. operator – controller (RBAC, SA, Deployment, metrics)
  3. 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)

Contributing

PRs welcome!

make lint
make test

License

Copyright 2025.

Licensed under the Apache License, Version 2.0. See LICENSE for details.

About

Kubebuilder k8s operator built with Bazel, packaged & deployed using Timoni

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages