Watching Endpoints Changes in Real-time using Go watch Interface
We've seen how the Endpoints object reflects the current set of ready Pods backing a Service. This list is highly dynamic – Pods scale up and down, become ready, fail readiness probes, or get rescheduled. Simply using Get or List periodically to check the Endpoints state is inefficient and doesn't provide real-time updates.
For scenarios where you need to react immediately to changes in the backend IPs of a Service (e.g., custom load balancers, dynamic configuration tools, monitoring systems), Kubernetes provides a powerful watch mechanism.
The Kubernetes watch API:
The Kubernetes API allows clients to establish a long-lived HTTP request (or WebSocket connection) to "watch" a specific resource or collection of resources. When changes occur to those resources (creation, update, deletion), the API server streams event notifications back to the client over this persistent connection.
Using client-go's Watch Method:
client-go makes it easy to use this underlying watch capability. Resource interfaces (like the one obtained from clientset.CoreV1().Endpoints(namespace)) provide a Watch method.
The Watch method takes:
context.Context: Allows cancelling the watch request.metav1.ListOptions: Crucially, this can be used to filter the watch. You can specify:FieldSelector: To watch a specific object by name (e.g.,fields.OneTermEqualSelector("metadata.name", "my-service-endpoints")).LabelSelector: To watch resources matching certain labels.ResourceVersion: To start the watch from a specific point in the resource history (important for handling reconnections, though we won't delve deep here). For simple watches, starting without a specificResourceVersionusually gets current state + future changes.
It returns a watch.Interface and an error.
The watch.Interface:
This interface represents the active watch connection. Its most important method is:
ResultChan() <-chan watch.Event: Returns a read-only channel. Event notifications from the API server are sent over this channel.
The watch.Event Struct:
Each item received on the result channel is a watch.Event struct, containing:
Type(watch.EventType): Indicates the type of event:watch.Added: A new matching resource was created.watch.Modified: An existing matching resource was updated.watch.Deleted: A matching resource was deleted.watch.Bookmark: Represents a specific resource version (less common for simple use).watch.Error: An error occurred (e.g., watch expired, internal error). The actual error is often in theObjectfield (as*metav1.Status).
Object(runtime.Object): The actual Kubernetes resource object (e.g.,*v1.Endpoints) associated with the event. You'll need to perform a type assertion to access its fields.
Example: Watching Endpoints for a Specific Service
Let's write a Go program that watches the Endpoints object associated with a specific Service name and prints updates as they occur.
How it Works:
Field Selector: We use
fields.OneTermEqualSelector("metadata.name", *serviceName)to tell the API server we only want events related to theEndpointsobject with that specific name.WatchCall:endpointsClient.Watch(...)initiates the watch request.ResultChan(): We get the channeleventChannelto receive events.Event Loop: The
for event := range eventChannelloop blocks until an event arrives or the channel is closed.Type Assertion: We use
event.Object.(*v1.Endpoints)to safely cast the receivedruntime.Objectto the expected*v1.Endpointstype. We check if the assertionok.Event Processing: We print the event type and then extract and display the ready/not ready addresses from the
Endpointsobject, similar to how we did it withGet.Loop Continuation: The loop continues, waiting for the next event.
Important Considerations:
Watch Lifetime: Watches are not guaranteed to last forever. The API server might close the connection due to timeouts, resource constraints, or other reasons. Robust applications need to handle the closure of the
eventChanneland potentially restart the watch, often using theResourceVersionfrom the last known event to avoid missing updates.Error Handling: The example includes basic error checking but doesn't fully handle
watch.Errorevents or automatic reconnection.Informers (Preview): For applications that need reliable, cached, and automatically reconnecting watches (like controllers),
client-goprovides a higher-level abstraction called Informers. We will cover Informers in detail in Chapter 6 as they are the standard way to build robust watchers. The directWatchinterface is useful for simpler tools or understanding the underlying mechanism.
Watching Endpoints directly provides powerful real-time insight into the dynamic mapping between Services and their backend Pods, enabling sophisticated networking tools and automation.
Last updated
Was this helpful?