Kubernetes编程——client-go基础—— Watch
Watch
https://github.com/kubernetes/apimachinery/blob/release-1.27/pkg/watch/watch.go
我理解意思是说:k8s.io/apimachinery/pkg/watch/watch.go 文件是 Kubernetes 中用于实现 watch API 的关键文件之一。该文件定义了用于监听资源对象变化的 Watcher 接口和相关的数据结构。
package watch import ( "fmt" "sync" "k8s.io/klog/v2" "k8s.io/apimachinery/pkg/runtime" ) // Interface can be implemented by anything that knows how to watch and report changes. type Interface interface { // Stop stops watching. Will close the channel returned by ResultChan(). Releases // any resources used by the watch. Stop() // ResultChan returns a chan which will receive all the events. If an error occurs // or Stop() is called, the implementation will close this channel and // release any resources used by the watch. ResultChan() <-chan Event } // EventType defines the possible types of events. type EventType string const ( Added EventType = "ADDED" Modified EventType = "MODIFIED" Deleted EventType = "DELETED" Bookmark EventType = "BOOKMARK" Error EventType = "ERROR" ) var ( DefaultChanSize int32 = 100 ) // Event represents a single event to a watched resource. // +k8s:deepcopy-gen=true type Event struct { Type EventType // Object is: // * If Type is Added or Modified: the new state of the object. // * If Type is Deleted: the state of the object immediately before deletion. // * If Type is Bookmark: the object (instance of a type being watched) where // only ResourceVersion field is set. On successful restart of watch from a // bookmark resourceVersion, client is guaranteed to not get repeat event // nor miss any events. // * If Type is Error: *api.Status is recommended; other types may make sense // depending on context. Object runtime.Object } type emptyWatch chan Event // NewEmptyWatch returns a watch interface that returns no results and is closed. // May be used in certain error conditions where no information is available but // an error is not warranted. func NewEmptyWatch() Interface { ch := make(chan Event) close(ch) return emptyWatch(ch) } // Stop implements Interface func (w emptyWatch) Stop() { } // ResultChan implements Interface func (w emptyWatch) ResultChan() <-chan Event { return chan Event(w) } // FakeWatcher lets you test anything that consumes a watch.Interface; threadsafe. type FakeWatcher struct { result chan Event stopped bool sync.Mutex } func NewFake() *FakeWatcher { return &FakeWatcher{ result: make(chan Event), } } func NewFakeWithChanSize(size int, blocking bool) *FakeWatcher { return &FakeWatcher{ result: make(chan Event, size), } } // Stop implements Interface.Stop(). func (f *FakeWatcher) Stop() { f.Lock() defer f.Unlock() if !f.stopped { klog.V(4).Infof("Stopping fake watcher.") close(f.result) f.stopped = true } } func (f *FakeWatcher) IsStopped() bool { f.Lock() defer f.Unlock() return f.stopped } // Reset prepares the watcher to be reused. func (f *FakeWatcher) Reset() { f.Lock() defer f.Unlock() f.stopped = false f.result = make(chan Event) } func (f *FakeWatcher) ResultChan() <-chan Event { return f.result } // Add sends an add event. func (f *FakeWatcher) Add(obj runtime.Object) { f.result <- Event{Added, obj} } // Modify sends a modify event. func (f *FakeWatcher) Modify(obj runtime.Object) { f.result <- Event{Modified, obj} } // Delete sends a delete event. func (f *FakeWatcher) Delete(lastValue runtime.Object) { f.result <- Event{Deleted, lastValue} } // Error sends an Error event. func (f *FakeWatcher) Error(errValue runtime.Object) { f.result <- Event{Error, errValue} } // Action sends an event of the requested type, for table-based testing. func (f *FakeWatcher) Action(action EventType, obj runtime.Object) { f.result <- Event{action, obj} } // RaceFreeFakeWatcher lets you test anything that consumes a watch.Interface; threadsafe. type RaceFreeFakeWatcher struct { result chan Event Stopped bool sync.Mutex } func NewRaceFreeFake() *RaceFreeFakeWatcher { return &RaceFreeFakeWatcher{ result: make(chan Event, DefaultChanSize), } } // Stop implements Interface.Stop(). func (f *RaceFreeFakeWatcher) Stop() { f.Lock() defer f.Unlock() if !f.Stopped { klog.V(4).Infof("Stopping fake watcher.") close(f.result) f.Stopped = true } } func (f *RaceFreeFakeWatcher) IsStopped() bool { f.Lock() defer f.Unlock() return f.Stopped } // Reset prepares the watcher to be reused. func (f *RaceFreeFakeWatcher) Reset() { f.Lock() defer f.Unlock() f.Stopped = false f.result = make(chan Event, DefaultChanSize) } func (f *RaceFreeFakeWatcher) ResultChan() <-chan Event { f.Lock() defer f.Unlock() return f.result } // Add sends an add event. func (f *RaceFreeFakeWatcher) Add(obj runtime.Object) { f.Lock() defer f.Unlock() if !f.Stopped { select { case f.result <- Event{Added, obj}: return default: panic(fmt.Errorf("channel full")) } } } // Modify sends a modify event. func (f *RaceFreeFakeWatcher) Modify(obj runtime.Object) { f.Lock() defer f.Unlock() if !f.Stopped { select { case f.result <- Event{Modified, obj}: return default: panic(fmt.Errorf("channel full")) } } } // Delete sends a delete event. func (f *RaceFreeFakeWatcher) Delete(lastValue runtime.Object) { f.Lock() defer f.Unlock() if !f.Stopped { select { case f.result <- Event{Deleted, lastValue}: return default: panic(fmt.Errorf("channel full")) } } } // Error sends an Error event. func (f *RaceFreeFakeWatcher) Error(errValue runtime.Object) { f.Lock() defer f.Unlock() if !f.Stopped { select { case f.result <- Event{Error, errValue}: return default: panic(fmt.Errorf("channel full")) } } } // Action sends an event of the requested type, for table-based testing. func (f *RaceFreeFakeWatcher) Action(action EventType, obj runtime.Object) { f.Lock() defer f.Unlock() if !f.Stopped { select { case f.result <- Event{action, obj}: return default: panic(fmt.Errorf("channel full")) } } } // ProxyWatcher lets you wrap your channel in watch Interface. threadsafe. type ProxyWatcher struct { result chan Event stopCh chan struct{} mutex sync.Mutex stopped bool } var _ Interface = &ProxyWatcher{} // NewProxyWatcher creates new ProxyWatcher by wrapping a channel func NewProxyWatcher(ch chan Event) *ProxyWatcher { return &ProxyWatcher{ result: ch, stopCh: make(chan struct{}), stopped: false, } } // Stop implements Interface func (pw *ProxyWatcher) Stop() { pw.mutex.Lock() defer pw.mutex.Unlock() if !pw.stopped { pw.stopped = true close(pw.stopCh) } } // Stopping returns true if Stop() has been called func (pw *ProxyWatcher) Stopping() bool { pw.mutex.Lock() defer pw.mutex.Unlock() return pw.stopped } // ResultChan implements Interface func (pw *ProxyWatcher) ResultChan() <-chan Event { return pw.result } // StopChan returns stop channel func (pw *ProxyWatcher) StopChan() <-chan struct{} { return pw.stopCh }
我理解意思是说:这段代码是 Kubernetes 中 watch 相关的实现。数据结构主要包含以下内容:
1、Type 类型:
1.1、EventType:定义了事件的类型,包括 Added、Modified、Deleted、Bookmark 和 Error。
1.2、Event:表示一个资源对象的事件,包含事件类型(EventType)和发生变化的对象(runtime.Object)。
1.3、Interface 接口:定义了 watch 的方法,包括 Stop() 和 ResultChan()。
-
- Stop() 停止watch,关闭结果通道。
- ResultChan() 返回结果通道,接收模拟的事件。
1.4、emptyWatch:是一个别名类型,实际上是 chan Event 的类型。它是用于创建一个没有任何结果和事件的 watch 接口的实现,适用于某些错误情况,其中没有可用的信息,但不需要返回错误。
1.5、RaceFreeFakeWatcher:线程安全的假 watch,用于测试。与 FakeWatcher 类似,可以模拟资源对象的事件,并且具有更好的并发支持。
1.6、ProxyWatcher:通过包装一个通道,代理实现了 Interface 接口,用于包装现有的通道并提供 watch 功能。
我理解意思是说:在实际情况中,可以直接使用 watch.Interface 接口。这个接口是 Kubernetes 提供的用于监听资源变化的通用接口。
1、watch.Interface 接口定义了 Stop() 和 ResultChan() 两个方法,用于停止 watch 和获取结果通道。
2、使用 watch.Interface 接口的好处是,它可以适应不同类型的 watch 实现。你可以使用 Kubernetes 提供的默认 watch 实现,也可以根据自己的需求实现自定义的 watch 。
3、当你需要监听并处理资源对象的变化时,可以创建一个 watch 实例,并通过 ResultChan() 方法接收事件。 watch 会始终返回事件通道,你可以选择在需要时停止 watch。
例如,可以使用以下方式创建一个 watch 实例并监听事件:
watcher := // 创建 watch 实例 eventChan := watcher.ResultChan() // 在协程中处理事件 go func() { for event := range eventChan { // 处理事件 } }() // 等待某些条件满足后停止 watch
4、需要注意的是,watch.Interface 接口没有提供对具体资源对象的类型信息。在处理事件时,你需要自行对事件中的对象进行类型断言或其他类型处理操作。
综上所述,当需要监听和处理资源对象的变化时,可以直接使用 watch.Interface 接口。根据自己的需要选择合适的 watch 实现,并通过接口方法获取事件通道进行处理。
但是!在实际情况中,通常会使用 Informer 而不是直接使用 watch.Interface!Informer 是 Kubernetes 提供的更高级别的资源监听和同步机制,它基于 watch.Interface 实现,并提供了更多的功能和便利性。