TTL Controller Lifecycle#
The TTL controller (pkg/controllers/ttl/) garbage-collects Kubernetes resources that carry the cleanup.kyverno.io/ttl label . It is a per-GVR controller: one instance is created for each GroupVersionResource that needs TTL-based cleanup.
Reconcile Loop#
The controller is started via Start, which delegates to controllerutils.Run. The reconcileFunc signature receives a cancellable ctx context.Context derived from the controller's root context.
The reconcile method follows this path:
- Key parsing β splits the item key into namespace/name.
- Lister lookup β fetches the object from the cache; returns early on
NotFound. - Deletion guard β returns early if
DeletionTimestampis set (object already terminating) . - TTL label check β returns early if
cleanup.kyverno.io/ttllabel is absent . - Deletion time computation β
parseDeletionTimeresolves the label value as a duration (added to creation time), ISO 8601 datetime, or date-only string. - Branch on expiry:
- Expired: calls
client.Deletewith an optional propagation policy derived from thecleanup.kyverno.io/propagation-policyannotation . On failure, records aRecordTTLFailuremetric. - Not yet expired: records a
RecordDeletedObjectmetric and re-enqueues the item withAddAfterfor the remaining duration .
- Expired: calls
Context Lifecycle Bug (Fixed in PR #17032)#
Prior to PR #17032, both the client.Delete call and both metric recording calls used context.Background() rather than the reconcile-scoped ctx . This was a context leak: if the controller was shut down or the API server became unresponsive, those operations could not be cancelled, potentially causing the controller to hang.
The fix β replacing all three context.Background() calls with ctx β ensures:
- Resource deletion respects controller shutdown signals.
RecordTTLFailureandRecordDeletedObjectmetric calls are tied to the reconcile context .
Note: The source file snapshot in this KB (commit
b3ce4ae) still shows the unfixedcontext.Background()pattern. The corrected behaviour is in the currentmainbranch after PR #17032 merged on 2026-08-10.
Lifecycle Methods#
| Method | Purpose |
|---|---|
Start(ctx, workers) | Launches worker goroutines; context drives cancellation |
Stop() | Deregisters event handlers, shuts down the work queue |
deregisterEventHandlers() | Removes Add/Update handlers from the shared informer |
Event handlers are registered only for Add and Update events β Delete events are intentionally omitted (passing nil) , because a deleted object will simply be absent from the lister on the next reconcile.
Metrics#
The metrics.TTLInfoMetrics interface exposes:
RecordDeletedObject(ctx, gvr, namespace)β emitted when a living (not-yet-expired) resource is re-enqueued for a future check.RecordTTLFailure(ctx, gvr, namespace)β emitted when a Delete API call fails.
Both are OpenTelemetry-backed counters accessed via metrics.GetTTLInfoMetrics() .
Key Source Files#
| File | Role |
|---|---|
pkg/controllers/ttl/controller.go | Controller struct, reconcile loop, lifecycle methods |
pkg/controllers/ttl/utils.go | parseDeletionTime, propagation-policy helpers |
pkg/metrics/ttl_info.go | TTLInfoMetrics interface and implementation |
pkg/utils/controller/run.go | Generic Run loop that drives reconciliation |
api/kyverno/constants.go | LabelCleanupTtl, AnnotationCleanupPropagationPolicy |