List() & Watch()
概述
源码版本信息
- Project: kubernetes
- Branch: master
- Last commit id: d25d741c
- Date: 2021-09-26
ListWatcher 是 Reflector 的一个主要能力提供者,今天我们具体看下 ListWatcher 是如何实现 List()
和 Watch()
过程的。这里我们只跟到 RESTClient 到调用层,不深入 RESTClient 本身的实现;后面有机会再单独结合 apiserver、etcd 等整体串在一起讲 k8s 里的 list-watch 机制底层原理。
ListWatch 对象的创建
ListWatcher 对应的新建实例函数如下:
- client-go/tools/cache/listwatch.go:70
1
2func NewListWatchFromClient(c Getter, resource string, namespace string, fieldSelector fields.Selector) *ListWatch {
3 optionsModifier := func(options *metav1.ListOptions) {
4 options.FieldSelector = fieldSelector.String()
5 }
6
7 return NewFilteredListWatchFromClient(c, resource, namespace, optionsModifier)
8}
主要逻辑在下面,list 和 watch 能力都是通过 RESTClient 提供:
1func NewFilteredListWatchFromClient(c Getter, resource string, namespace string, optionsModifier func(options *metav1.ListOptions)) *ListWatch {
2
3 listFunc := func(options metav1.ListOptions) (runtime.Object, error) {
4 optionsModifier(&options)
5 return c.Get().
6 Namespace(namespace).
7 Resource(resource).
8 VersionedParams(&options, metav1.ParameterCodec).
9 Do(context.TODO()).
10 Get()
11 }
12
13 watchFunc := func(options metav1.ListOptions) (watch.Interface, error) {
14 options.Watch = true
15 optionsModifier(&options)
16 return c.Get().
17 Namespace(namespace).
18 Resource(resource).
19 VersionedParams(&options, metav1.ParameterCodec).
20 Watch(context.TODO())
21 }
22 return &ListWatch{ListFunc: listFunc, WatchFunc: watchFunc}
23}
Getter
上面有一个 Getter 接口,看下定义:
- client-go/tools/cache/listwatch.go:65
1type Getter interface {
2 Get() *restclient.Request
3}
这里需要一个能够获得 *restclient.Request
的方式
我们实际使用的时候,会用 rest.Interface
接口类型的实例,这是一个相对底层的工具,封装的是 Kubernetes REST apis 相应动作:
- client-go/rest/client.go:41
1type Interface interface {
2 GetRateLimiter() flowcontrol.RateLimiter
3 Verb(verb string) *Request
4 Post() *Request
5 Put() *Request
6 Patch(pt types.PatchType) *Request
7 Get() *Request
8 Delete() *Request
9 APIVersion() schema.GroupVersion
10}
对应实现是:
- client-go/rest/client.go:81
1type RESTClient struct {
2 base *url.URL
3 versionedAPIPath string
4 content ClientContentConfig
5 createBackoffMgr func() BackoffManager
6 rateLimiter flowcontrol.RateLimiter
7 warningHandler WarningHandler
8 Client *http.Client
9}
10
Getter 接口的 Get()
方法返回的是一个 *restclient.Request
类型,Request 的用法我们直接看 ListWatch 的 New 函数里已经看到是怎么玩的了。
至于这里的 RESTClient 和我们代码里常用的 Clientset 的关系,这里先简单举个例子介绍一下:我们在用 clientset 去 Get 一个指定名字的 DaemonSet 的时候,调用过程类似这样:
1r.AppsV1().DaemonSets("default").Get(ctx, "test-ds", getOpt)
这里的 Get 其实就是利用了 RESTClient 提供的能力,方法实现对应如下:
1func (c *daemonSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.DaemonSet, err error) {
2 result = &v1beta1.DaemonSet{}
3 err = c.client.Get().
4 Namespace(c.ns).
5 Resource("daemonsets").
6 Name(name).
7 VersionedParams(&options, scheme.ParameterCodec).
8 Do(ctx).
9 Into(result)
10 return
11}
ListWatch
上面 NewFilteredListWatchFromClient()
函数里实现了 ListFunc 和 WatchFunc 属性的初始化,我们接着看下 ListWatch 结构体定义:
- client-go/tools/cache/listwatch.go:57
1type ListWatch struct {
2 ListFunc ListFunc
3 WatchFunc WatchFunc
4
5 DisableChunking bool
6}
实现的接口叫做 ListWatcher
1type ListerWatcher interface {
2 Lister
3 Watcher
4}
这里的 Lister 是
1type Lister interface {
2
3 List(options metav1.ListOptions) (runtime.Object, error)
4}
这里的 Watcher 是
1type Watcher interface {
2
3 Watch(options metav1.ListOptions) (watch.Interface, error)
4}
List() & Watch()
最后 ListWatch 对象的 List() 和 Watch() 的实现就没有太多新内容了:
- client-go/tools/cache/listwatch.go:103
1func (lw *ListWatch) List(options metav1.ListOptions) (runtime.Object, error) {
(转载请保留本文原始链接 https://www.danielhu.cn)
请发表评论