https://github.com/wenisch-tech/chronoreaper
A Kubernetes Operator built with Quarkus and the Java Operator SDK (JOSDK) that automatically deletes resources once a timestamp defined as annotation has passed.
https://github.com/wenisch-tech/chronoreaper
auto-delete k8s k8s-operators operator
Last synced: 18 days ago
JSON representation
A Kubernetes Operator built with Quarkus and the Java Operator SDK (JOSDK) that automatically deletes resources once a timestamp defined as annotation has passed.
- Host: GitHub
- URL: https://github.com/wenisch-tech/chronoreaper
- Owner: wenisch-tech
- License: agpl-3.0
- Created: 2026-04-07T14:27:39.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-31T20:05:10.000Z (18 days ago)
- Last Synced: 2026-05-31T20:06:10.535Z (18 days ago)
- Topics: auto-delete, k8s, k8s-operators, operator
- Language: Java
- Homepage:
- Size: 101 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 13
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# ChronoReaper
[](https://github.com/wenisch-tech/Kairos/releases)
[](LICENSE.md)
[](https://github.com/wenisch-tech/chronoreaper/pkgs/container/chronoreaper)
[](https://artifacthub.io/packages/helm/jfwenisch/chronoreaper)
[](https://github.com/wenisch-tech/chronoreaper/actions)
ChronoReaper is a Kubernetes Operator built with [Quarkus](https://quarkus.io) and the
[Java Operator SDK (JOSDK)](https://javaoperatorsdk.io) that automatically deletes resources once a timestamp defined as annotation has passed passed.
Deployable via
[Helm](https://helm.sh) or the
[Operator Lifecycle Manager (OLM)](https://olm.operatorframework.io) /
[OperatorHub.io](https://operatorhub.io).
## How it works
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).
### Annotation format
Two timestamp formats are supported:
#### ISO-8601 UTC
```yaml
metadata:
annotations:
wenisch.tech/ttl: "2025-12-31T23:59:59Z"
```
#### Unix epoch seconds
```yaml
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.
---
## Supported resource types
| 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 |
---
## Quick start
### Option 1 — Helm
```bash
helm install chronoreaper helm/chronoreaper \
--namespace chronoreaper \
--create-namespace
```
Common overrides:
```bash
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
```
### Option 2 — OLM / OperatorHub
1. Install OLM (if not already present):
```bash
operator-sdk olm install
```
2. Apply the bundle manifests:
```bash
kubectl apply -f bundle/manifests/
```
3. Or search for **ChronoReaper** on [OperatorHub.io](https://operatorhub.io)
and follow the one-click install.
---
## Example resources
### Pod — expires at a fixed date
```yaml
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"]
```
### Deployment — expires via Unix epoch
```yaml
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:latest
```
### Namespace — self-destructing sandbox
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: sandbox-abc123
annotations:
wenisch.tech/ttl: "1800000000"
```
---
## Configuration
| 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 |
### `application.properties` keys
| Key | Default | Description |
|-----|---------|-------------|
| `ttl.check.interval` | `60s` | Polling interval |
| `ttl.dry-run` | `false` | Dry-run mode |
---
## Observability
### Health probes
| Probe | Path | Port |
|-------|------|------|
| Liveness | `/q/health/live` | `8081` |
| Readiness | `/q/health/ready` | `8081` |
### Prometheus metrics (port `8081`, path `/q/metrics`)
| Metric | Description |
|--------|-------------|
| `ttl_operator_resources_deleted_total` | Total resources deleted since startup |
| `ttl_operator_errors_total` | Total errors encountered since startup |
---
## Development
### Prerequisites
| Tool | Minimum version |
|------|-----------------|
| Java | 17 |
| Apache Maven | 3.9 |
| Docker / Podman | any recent version |
### Build
```bash
mvn package -DskipTests
```
### Run tests
```bash
mvn test
```
### Run locally (dev mode with live-reload)
```bash
mvn quarkus:dev
```
> Requires a reachable kubeconfig (`~/.kube/config`) or an in-cluster
> `KUBERNETES_SERVICE_HOST`. Outside a cluster, ensure
> `quarkus.kubernetes-client.devservices.enabled=false` is set (already the
> default in `%dev` profile).
### Build the container image
```bash
docker build -t wenisch-tech/chronoreaper:latest .
docker push wenisch-tech/chronoreaper:latest
```
## License
[GNU Affero General Public License v3.0](LICENSE)