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 specificResourceVersion
usually 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 theObject
field (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 theEndpoints
object with that specific name.Watch
Call:endpointsClient.Watch(...)
initiates the watch request.ResultChan()
: We get the channeleventChannel
to receive events.Event Loop: The
for event := range eventChannel
loop blocks until an event arrives or the channel is closed.Type Assertion: We use
event.Object.(*v1.Endpoints)
to safely cast the receivedruntime.Object
to the expected*v1.Endpoints
type. We check if the assertionok
.Event Processing: We print the event type and then extract and display the ready/not ready addresses from the
Endpoints
object, 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
eventChannel
and potentially restart the watch, often using theResourceVersion
from the last known event to avoid missing updates.Error Handling: The example includes basic error checking but doesn't fully handle
watch.Error
events or automatic reconnection.Informers (Preview): For applications that need reliable, cached, and automatically reconnecting watches (like controllers),
client-go
provides 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 directWatch
interface 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?