Skip to main content
Events are a lightweight, standard Kubernetes mechanism to explain controller decisions (for example, why a child Deployment was created or updated). In this lesson we reuse the Kubernetes event system to report readiness progress from the controller so users inspecting the parent custom resource can see the controller’s reasoning and progress without hunting through child resources or controller logs. We already copy the observed ready replica count from the child Deployment into the WebApp status. Now we will emit short events describing whether the child Deployment is still converging or has reached the requested replica count. These events are attached to the WebApp custom resource so tools like kubectl describe show the controller’s progress messages directly on the parent object.

Design overview

  • The WebApp spec is 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

  1. Add an EventRecorder field to the reconciler.
  2. Wire the recorder into the controller in cmd/main.go using the manager’s GetEventRecorderFor.
  3. Emit events after observing and updating status, and use a timed requeue while waiting for readiness.

Reconciler skeleton

Add the new imports and a Recorder 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 via GetEventRecorderFor. 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.
This guarantees you use fresh observed data for the decision and attach the event to the correct parent object. Create a local variable for the desired replica count to make the comparison explicit:
Compare 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.
Key notes about the event call:
  • The first argument to Eventf is 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.EventTypeWarning to 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., WaitingForReplicas or WebAppReady) and put formatted details in the message.
  • Returning nil error with a non-zero RequeueAfter schedules 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.
Start the manager in the foreground. In a second terminal, apply the sample WebApp and watch progress. The sample requests two replicas. Use the Deployment wait to confirm the child workload becomes available, and inspect the parent WebApp status and Events for controller progress messages.
You should see 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).
  • RequeueAfter bridges the gap by scheduling deliberate follow-up checks during normal convergence rather than using errors to retrigger reconciliation.
Together, status + events + timed requeues make custom resources easier to understand and debug when auditing controller behavior or troubleshooting application rollout progress.

References

Watch Video