ChronoReaper is a Kubernetes Operator built with Quarkus and the Java Operator SDK (JOSDK) that automatically deletes resources once a timestamp defined as annotation has passed passed.
Deployable via Helm or the Operator Lifecycle Manager (OLM) / OperatorHub.io.
Add the wenisch.tech/ttl annotation to any Kubernetes resource. When the
specified timestamp is reached, the operator automatically deletes the resource.
The operator polls all resource types every 60 seconds (configurable).
Two timestamp formats are supported:
metadata:
annotations:
wenisch.tech/ttl: "2025-12-31T23:59:59Z"metadata:
annotations:
wenisch.tech/ttl: "1775666164"If the value cannot be parsed in either format, an error is logged and the resource is left untouched.
| Category | Resources |
|---|---|
| Workloads | Pod, Deployment, ReplicaSet, StatefulSet, DaemonSet, Job, CronJob |
| Networking | Service, Ingress |
| Configuration | ConfigMap, Secret, ServiceAccount |
| Cluster-scoped | Namespace, CustomResourceDefinition, ClusterRole, ClusterRoleBinding |
| Custom resources | All installed CRDs are discovered and checked dynamically |
helm install chronoreaper helm/chronoreaper \
--namespace chronoreaper \
--create-namespaceCommon overrides:
helm install chronoreaper helm/chronoreaper \
--namespace chronoreaper \
--create-namespace \
--set operator.checkInterval=30s \ # poll every 30 s
--set operator.dryRun=true # log only, no actual deletion-
Install OLM (if not already present):
operator-sdk olm install
-
Apply the bundle manifests:
kubectl apply -f bundle/manifests/
-
Or search for ChronoReaper on OperatorHub.io and follow the one-click install.
apiVersion: v1
kind: Pod
metadata:
name: temp-pod
namespace: default
annotations:
wenisch.tech/ttl: "2025-06-30T00:00:00Z"
spec:
containers:
- name: app
image: alpine:latest
command: ["sleep", "infinity"]apiVersion: apps/v1
kind: Deployment
metadata:
name: temp-deploy
namespace: default
annotations:
wenisch.tech/ttl: "1775666164" # 2026-03-06T06:36:04Z
spec:
replicas: 1
selector:
matchLabels:
app: temp
template:
metadata:
labels:
app: temp
spec:
containers:
- name: app
image: nginx:latestapiVersion: v1
kind: Namespace
metadata:
name: sandbox-abc123
annotations:
wenisch.tech/ttl: "1800000000"| Helm value | Env variable | Default | Description |
|---|---|---|---|
operator.checkInterval |
TTL_CHECK_INTERVAL |
60s |
How often to scan all resources (ISO-8601 duration) |
operator.dryRun |
TTL_DRY_RUN |
false |
Log deletions without executing them |
| Key | Default | Description |
|---|---|---|
ttl.check.interval |
60s |
Polling interval |
ttl.dry-run |
false |
Dry-run mode |
| Probe | Path | Port |
|---|---|---|
| Liveness | /q/health/live |
8081 |
| Readiness | /q/health/ready |
8081 |
| Metric | Description |
|---|---|
ttl_operator_resources_deleted_total |
Total resources deleted since startup |
ttl_operator_errors_total |
Total errors encountered since startup |
| Tool | Minimum version |
|---|---|
| Java | 17 |
| Apache Maven | 3.9 |
| Docker / Podman | any recent version |
mvn package -DskipTestsmvn testmvn quarkus:devRequires a reachable kubeconfig (
~/.kube/config) or an in-clusterKUBERNETES_SERVICE_HOST. Outside a cluster, ensurequarkus.kubernetes-client.devservices.enabled=falseis set (already the default in%devprofile).
docker build -t wenisch-tech/chronoreaper:latest .
docker push wenisch-tech/chronoreaper:latest