A Kubernetes operator that automatically triggers jobs when watched Kubernetes resources change.
kube-changejob monitors specified Kubernetes resources and triggers jobs when changes are detected. It provides a declarative way to automate workflows in response to resource modifications, making it ideal for:
- Configuration synchronization workflows
- Automated deployment pipelines
- Resource validation and compliance checks
- Backup and snapshot operations
- Custom event-driven automation
- Flexible Resource Watching: Monitor any Kubernetes resource (ConfigMaps, Secrets, Deployments, etc.)
- Field-Specific Monitoring: Watch entire resources or specific fields using JSONPath
- Trigger Conditions: Configure "Any" or "All" logic for multi-resource triggers
- Cooldown Period: Prevent excessive job creation with configurable cooldown
- Job History Management: Automatically clean up old jobs with history limits
- Webhook Validation: Built-in validation and defaulting webhooks
- High Availability: Supports leader election for HA deployments
- Secure by Default: TLS-enabled webhooks and metrics, restrictive pod security
- Kubernetes cluster (v1.29+)
- kubectl configured to access your cluster
- cert-manager (for webhook certificates)
# Install cert-manager (if not already installed)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.1/cert-manager.yaml
# Install kube-changejob (replace VERSION with desired version)
kubectl apply -f https://github.com/nusnewob/kube-changejob/releases/latest/download/install.yaml
# Verify the installation
kubectl get pods -n kube-changejob-system# Install from OCI registry
helm install kube-changejob oci://ghcr.io/nusnewob/charts/kube-changejob --version 0.1.0
# Or with custom values
helm install kube-changejob oci://ghcr.io/nusnewob/charts/kube-changejob \
--version 0.1.0 \
--set image.tag=v0.1.0kubectl apply -k github.com/nusnewob/kube-changejob/config/defaultCreate a ChangeTriggeredJob that triggers when a ConfigMap changes:
apiVersion: triggers.changejob.dev/v1alpha
kind: ChangeTriggeredJob
metadata:
name: config-watcher
namespace: default
spec:
# Job template - what to run when triggered
jobTemplate:
spec:
template:
spec:
containers:
- name: runner
image: busybox:latest
command: ["sh", "-c", "echo 'ConfigMap changed at:' $(date)"]
restartPolicy: Never
# Resources to watch
resources:
- apiVersion: v1
kind: ConfigMap
name: my-config
namespace: default
# Trigger when any resource changes (default)
condition: Any
# Wait 60 seconds between triggers (default)
cooldown: 60s
# Keep last 5 jobs (default)
history: 5Apply the configuration:
kubectl apply -f changejob.yamlMonitor the status:
kubectl get changetriggeredjobs config-watcher -o yamlComprehensive documentation is available in the docs/ directory:
- Installation Guide - Detailed installation instructions
- User Guide - Complete usage guide with examples
- API Reference - CRD specification and API details
- Configuration - Controller configuration options
- Examples - Real-world usage examples
- Release Process - How to create and manage releases
- Resource Polling: The controller periodically polls watched resources (default: every 60 seconds)
- Change Detection: Computes SHA256 hashes of resource data to detect changes
- Trigger Evaluation: Evaluates trigger conditions (Any/All) and cooldown period
- Job Creation: Creates a new Job from the jobTemplate when triggered
- History Management: Automatically cleans up old jobs based on history limit
The controller can be configured using command-line flags or environment variables:
| Flag | Environment Variable | Default | Description |
|---|---|---|---|
--poll-interval |
POLL_INTERVAL |
60s |
How often to poll resources |
--metrics-bind-address |
- | 0 |
Metrics endpoint address |
--health-probe-bind-address |
- | :8081 |
Health probe address |
--leader-elect |
- | false |
Enable leader election |
--log-level |
- | info |
Log level (debug, info, warn, error) |
--log-format |
- | text |
Log format (json or text) |
--log-timestamp |
- | rfc3339 |
Log timestamp formart (epoch, millis, nano, iso8601, rfc3339 or rfc3339nano) |
--debug |
- | false |
Enable debug info |
Example with custom poll interval:
# Via environment variable
kubectl set env deployment/kube-changejob-controller-manager \
-n kube-changejob-system \
POLL_INTERVAL=30s
# Via command-line flag
kubectl patch deployment kube-changejob-controller-manager \
-n kube-changejob-system \
--type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--poll-interval=30s"}]'Trigger only when all specified resources have changed:
apiVersion: triggers.changejob.dev/v1alpha
kind: ChangeTriggeredJob
metadata:
name: multi-resource-watcher
spec:
jobTemplate:
spec:
template:
spec:
containers:
- name: sync
image: my-sync-tool:latest
command: ["sync-all"]
restartPolicy: Never
resources:
- apiVersion: v1
kind: ConfigMap
name: app-config
namespace: default
- apiVersion: v1
kind: Secret
name: app-secret
namespace: default
- apiVersion: apps/v1
kind: Deployment
name: app
namespace: default
condition: All # Trigger only when all three resources change
cooldown: 300s # 5-minute cooldownMonitor only specific fields using JSONPath:
apiVersion: triggers.changejob.dev/v1alpha
kind: ChangeTriggeredJob
metadata:
name: deployment-image-watcher
spec:
jobTemplate:
spec:
template:
spec:
containers:
- name: notify
image: notification-tool:latest
command: ["notify", "Deployment image updated"]
restartPolicy: Never
resources:
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: default
fields:
- "spec.template.spec.containers[*].image" # Watch only container images
cooldown: 30sMonitor cluster-wide resources:
apiVersion: triggers.changejob.dev/v1alpha
kind: ChangeTriggeredJob
metadata:
name: node-watcher
namespace: kube-changejob-system
spec:
jobTemplate:
spec:
template:
spec:
containers:
- name: alert
image: alert-tool:latest
command: ["alert", "Node changes detected"]
restartPolicy: Never
resources:
- apiVersion: v1
kind: Node
name: worker-1
# No namespace - Node is cluster-scoped
cooldown: 120s- Go 1.24+
- Docker
- kubectl
- kind (for local testing)
- kubebuilder 4.10.1+
# Clone the repository
git clone https://github.com/nusnewob/kube-changejob.git
cd kube-changejob
# Build the controller
make build
# Run tests
make test
# Run end-to-end tests
make test-e2e# Install CRDs
make install
# Run controller locally
make run
# In another terminal, apply test resources
kubectl apply -f config/samples/Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
┌─────────────────────────────────────────────────────────────┐
│ ChangeTriggeredJob │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Spec: │ │
│ │ - jobTemplate: Job template to create │ │
│ │ - resources: List of resources to watch │ │
│ │ - condition: "Any" or "All" │ │
│ │ - cooldown: Minimum time between triggers │ │
│ │ - history: Number of jobs to keep │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ChangeTriggeredJob Controller │
│ │
│ 1. Poll watched resources (every 60s) │
│ 2. Compute SHA256 hash of resource data │
│ 3. Compare with stored hashes │
│ 4. Evaluate trigger condition (Any/All) │
│ 5. Check cooldown period │
│ 6. Create Job from template if triggered │
│ 7. Update status with job info │
│ 8. Clean up old jobs (history limit) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes Jobs │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Job 1 │ │ Job 2 │ │ Job 3 │ │ Job 4 │ │
│ │ (oldest) │ │ │ │ │ │ (latest) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Jobs owned by ChangeTriggeredJob (automatic cleanup) │
└─────────────────────────────────────────────────────────────┘
The controller exposes Prometheus metrics on port 8443 (HTTPS) or 8080 (HTTP):
- Standard controller-runtime metrics
- Custom resource metrics
To enable Prometheus monitoring:
kubectl apply -k config/prometheusHealth and readiness probes are available on port 8081:
/healthz- Health check/readyz- Readiness check
Please see SECURITY.md for information on reporting security vulnerabilities.
- TLS-enabled webhooks and metrics endpoints
- Restrictive pod security context (non-root, read-only filesystem)
- RBAC with minimal required permissions
- Network policies for traffic control
- Webhook validation for resource specifications
- Check controller logs:
kubectl logs -n kube-changejob-system deployment/kube-changejob-controller-manager- Verify ChangeTriggeredJob status:
kubectl describe changetriggeredjob <name>- Check if cooldown period has elapsed
- Ensure watched resources exist and are accessible
- Verify cert-manager is running:
kubectl get pods -n cert-manager- Check webhook certificates:
kubectl get certificate -n kube-changejob-system- Check webhook configuration:
kubectl get validatingwebhookconfiguration
kubectl get mutatingwebhookconfiguration- Verify RBAC permissions:
kubectl get clusterrole kube-changejob-manager-role -o yaml- Check service account:
kubectl get serviceaccount -n kube-changejob-system# Delete all ChangeTriggeredJob resources
kubectl delete changetriggeredjobs --all --all-namespaces
# Uninstall the operator
kubectl delete -k github.com/nusnewob/kube-changejob/config/defaultThis project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Built with:
- Kubebuilder - Kubernetes operator framework
- controller-runtime - Controller runtime library
- cert-manager - Certificate management for webhooks
- Author: Bowen Sun
- Repository: github.com/nusnewob/kube-changejob
- Issues: GitHub Issues