1. 程式人生 > 其它 >Kubernetes client-go 原始碼分析 - ListWatcher

Kubernetes client-go 原始碼分析 - ListWatcher

概述ListWatch 物件的建立GetterListWatchList() & Watch()

概述

原始碼版本資訊

  • Project: kubernetes
  • Branch: master
  • Last commit id: d25d741c
  • Date: 2021-09-26

ListWatcherReflector 的一個主要能力提供者,今天我們具體看下 ListWatcher 是如何實現 List()Watch() 過程的。這裡我們只跟到 RESTClient 到呼叫層,不深入 RESTClient 本身的實現;後面有機會再單獨結合 apiserver、etcd 等整體串在一起講 k8s 裡的 list-watch 機制底層原理。

ListWatch 物件的建立

ListWatcher 對應的新建例項函式如下:

  • client-go/tools/cache/listwatch.go:70
1//這裡Getter型別的c對應一個RESTClient
2funcNewListWatchFromClient(cGetter,resourcestring,namespacestring,fieldSelectorfields.Selector)*ListWatch{
3optionsModifier:=func(options*metav1.ListOptions){
4options.FieldSelector=fieldSelector.String()//序列化成字串

5}
6//呼叫下面這個NewFilteredListWatchFromClient()函式
7returnNewFilteredListWatchFromClient(c,resource,namespace,optionsModifier)
8}

主要邏輯在下面,list 和 watch 能力都是通過 RESTClient 提供:

 1funcNewFilteredListWatchFromClient(cGetter,resourcestring,namespacestring,optionsModifierfunc(options*metav1.ListOptions))*ListWatch{
2
//list某個namespace下的某個resource
3listFunc:=func(optionsmetav1.ListOptions)(runtime.Object,error){
4optionsModifier(&options)
5returnc.Get().//RESTClient.Get()->*request.Request
6Namespace(namespace).
7Resource(resource).
8VersionedParams(&options,metav1.ParameterCodec).
9Do(context.TODO()).
10Get()
11}
12//watch某個namespace下的某個resource
13watchFunc:=func(optionsmetav1.ListOptions)(watch.Interface,error){
14options.Watch=true
15optionsModifier(&options)
16returnc.Get().
17Namespace(namespace).
18Resource(resource).
19VersionedParams(&options,metav1.ParameterCodec).
20Watch(context.TODO())
21}
22return&ListWatch{ListFunc:listFunc,WatchFunc:watchFunc}
23}

Getter

上面有一個 Getter 介面,看下定義:

  • client-go/tools/cache/listwatch.go:65
1typeGetterinterface{
2Get()*restclient.Request
3}

這裡需要一個能夠獲得 *restclient.Request 的方式

我們實際使用的時候,會用 rest.Interface 介面型別的例項,這是一個相對底層的工具,封裝的是 Kubernetes REST apis 相應動作:

  • client-go/rest/client.go:41
 1typeInterfaceinterface{
2GetRateLimiter()flowcontrol.RateLimiter
3Verb(verbstring)*Request
4Post()*Request
5Put()*Request
6Patch(pttypes.PatchType)*Request
7Get()*Request
8Delete()*Request
9APIVersion()schema.GroupVersion
10}

對應實現是:

  • client-go/rest/client.go:81
 1typeRESTClientstruct{
2base*url.URL
3versionedAPIPathstring
4contentClientContentConfig
5createBackoffMgrfunc()BackoffManager
6rateLimiterflowcontrol.RateLimiter
7warningHandlerWarningHandler
8Client*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(ctxcontext.Context,namestring,optionsv1.GetOptions)(result*v1beta1.DaemonSet,errerror){
2result=&v1beta1.DaemonSet{}
3err=c.client.Get().//其實就是RESTClient.Get(),返回的是*rest.Request物件
4Namespace(c.ns).
5Resource("daemonsets").
6Name(name).
7VersionedParams(&options,scheme.ParameterCodec).
8Do(ctx).
9Into(result)
10return
11}

ListWatch

上面 NewFilteredListWatchFromClient() 函式裡實現了 ListFuncWatchFunc 屬性的初始化,我們接著看下 ListWatch 結構體定義:

  • client-go/tools/cache/listwatch.go:57
1typeListWatchstruct{
2ListFuncListFunc
3WatchFuncWatchFunc
4//DisableChunkingrequestsnochunkingforthislistwatcher.
5DisableChunkingbool
6}

實現的介面叫做 ListWatcher

1typeListerWatcherinterface{
2Lister
3Watcher
4}

這裡的 Lister 是

1typeListerinterface{
2//List的返回值應該是一個list型別物件,也就是裡面有Items欄位,裡面的ResourceVersion可以用來watch
3List(optionsmetav1.ListOptions)(runtime.Object,error)
4}

這裡的 Watcher 是

1typeWatcherinterface{
2//從指定的資源版本開始watch
3Watch(optionsmetav1.ListOptions)(watch.Interface,error)
4}

List() & Watch()

最後 ListWatch 物件的 List() 和 Watch() 的實現就沒有太多新內容了:

  • client-go/tools/cache/listwatch.go:103
1func(lw*ListWatch)List(optionsmetav1.ListOptions)(runtime.Object,error){//ListWatch在Reflector中使用,在Reflector中已經有了分頁邏輯,所以這裡不能再新增分頁相關程式碼returnlw.ListFunc(options)}func(lw*ListWatch)Watch(optionsmetav1.ListOptions)(watch.Interface,error){returnlw.WatchFunc(options)}

(轉載請保留本文原始連結 https://www.danielhu.cn)