kubectl describe show the controller’s progress messages directly on the parent object.
Design overview
- The WebApp
specis the user’s desired state (e.g.,replicas). - The child Deployment reports actual state through
status(e.g.,dep.Status.ReadyReplicas). - The controller copies the observed number into the WebApp
status. - Events provide an additional layer: they describe the controller’s decision during each reconcile pass.
- Use a timed requeue (
RequeueAfter) to schedule a follow-up check when the Deployment is converging instead of returning an error.
Controller changes
- Add an
EventRecorderfield to the reconciler. - Wire the recorder into the controller in
cmd/main.gousing the manager’sGetEventRecorderFor. - Emit events after observing and updating status, and use a timed requeue while waiting for readiness.
Reconciler skeleton
Add the new imports and aRecorder field to the WebAppReconciler. Note the record and time imports; the reconciler will use a timed requeue.
RBAC rules
Make sure your RBAC markers include status access so the controller can update the WebApp status:Wiring the recorder in main
The controller manager exposes an event recorder viaGetEventRecorderFor. Supply that to the reconciler so it can emit events. The provided source name (for example, webapp-controller) appears in the events table and helps link events to the emitting controller.
Emitting events in Reconcile
Place the event emission after:- You have ensured the child Deployment exists (created/updated if necessary).
- You have copied the observed Deployment state into the WebApp
status.
dep.Status.ReadyReplicas to desiredReplicas. If the Deployment has fewer ready replicas than requested, emit a Warning-type event that informs the user the controller is waiting, and schedule a follow-up check using RequeueAfter rather than returning an error. When the Deployment reaches the requested replicas, emit a Normal-type event to indicate readiness.
Here is the relevant portion of Reconcile. It assumes you have w (the WebApp) and dep (the child Deployment) already loaded and any create/update logic already performed.
- The first argument to
Eventfis a pointer to the WebApp object; events are intentionally attached to the parent CR so users inspecting the CR see the messages first. - Use
corev1.EventTypeWarningto indicate a not-ready state that merits attention. In this context, “Warning” signals that the controller is waiting for readiness — it does not necessarily mean a reconcile failed. - Use a short, stable
reason(e.g.,WaitingForReplicasorWebAppReady) and put formatted details in the message. - Returning
nilerror with a non-zeroRequeueAfterschedules a normal follow-up check, which is preferable to forcing an error retry path.
Attach events to the parent CR so users can inspect progress and decisions without needing to hunt for child resources or controller logs. Use a timed requeue to poll for readiness rather than treating a non-ready deployment as an error.
Choose a requeue delay that balances responsiveness with controller load. Very frequent requeues can increase API server pressure; very slow requeues can delay progress visibility.
Build and run
Build locally before starting the manager to catch missing imports or compile-time errors.status and Events for controller progress messages.
status.readyReplicas updated on the WebApp and kubectl describe will show the WaitingForReplicas events followed by a WebAppReady event attached to the WebApp. For example:
Summary
- Status answers: “What does the controller observe now?” (observed values, e.g.,
status.readyReplicas). - Events answer: “What important decision did the controller just report?” (human-friendly progress and reasoning).
RequeueAfterbridges the gap by scheduling deliberate follow-up checks during normal convergence rather than using errors to retrigger reconciliation.
References
- Kubernetes Events and Troubleshooting: https://kubernetes.io/docs/tasks/debug-application-cluster/events-custom-metrics-pipeline/
- Controller Runtime (sigs.k8s.io/controller-runtime): https://pkg.go.dev/sigs.k8s.io/controller-runtime