• client-go系列之1---client-go代码结构讲解


    1. 写在前面

    个人主页: https://gzh.readthedocs.io

    关注容器技术、关注Kubernetes。问题或建议,请公众号留言。

    本系列内容都是基于这个版本的client-go进行讲解,不同版本的略有差异。

    [root@77DDE94FF07FCC1-wsl /ACode/client-go] git rev-parse HEAD
    becbabb360023e1825a48b4db85f454e452ae249
    

    下面简单罗列一下本文中可能会用提到的一些常用缩写,详细的介绍请参考后面的文章(TODO)谈起k8s中的GVR我们实际在讲什么

    说明

    看一下k8s的资源模型:

    apiVersion: extensions/v1beta1

    kind: ReplicaSet

    对于Resource我们可以将之类比于编程语言中的“包”的概念,主要用于区分不同的API,这样可以有效避免Kinds重名的问题。通常会使用公司的域名等具有独特明显区分的字符串作为Resource的值,如:alibaba-inc.com

    Version用于区分不同API的稳定程度及兼容性,如:v1beta1, v1

    Kind即为API所对应的名字,如:Deployment, Service

    2. 代码结构

    从这个包的名字可以很明显的知道,client-go其实主要是提供了用户与k8s交互时使用客户端,方便大家编程。

    个别目录已过滤掉。

    [root@77DDE94FF07FCC1-wsl /ACode/client-go] tree -d -L 1 -I "testing|examples|*_test*|Godeps|third_party|metadata|deprecated|restmapper"
    .
    ├── discovery                   # 定义DsicoveryClient客户端。作用是用于发现k8s所支持GVR(Group, Version, Resources)。
    ├── dynamic                     # 定义DynamicClient客户端。可以用于访问k8s Resources(如: Pod, Deploy...),也可以访问用户自定义资源(即: CRD)。
    ├── informers                   # k8s中各种Resources的Informer机制的实现。
    ├── kubernetes                  # 定义ClientSet客户端。它只能用于访问k8s Resources。每一种资源(如: Pod等)都可以看成是一个客端,而ClientSet是多个客户端的集合,它对RestClient进行了封装,引入了对Resources和Version的管理。通常来说ClientSet是client-gen来自动生成的。
    ├── listers                     # 提供对Resources的获取功能。对于Get()和List()而言,listers提供给二者的数据都是从缓存中读取的。
    ├── pkg                         
    ├── plugin                      # 提供第三方插件。如:GCP, OpenStack等。
    ├── rest                        # 定义RestClient,实现了Restful的API。同时会支持Protobuf和Json格式数据。
    ├── scale                       # 定义ScalClient。用于Deploy, RS, RC等的扩/缩容。
    ├── tools                       # 定义诸如SharedInformer、Reflector、DealtFIFO和Indexer等常用工具。实现client查询和缓存机制,减少client与api-server请求次数,减少api-server的压力。
    ├── transport
    └── util                        # 提供诸如WorkQueue、Certificate等常用方法。
    
    12 directories
    

    3. 代码使用简单示例

    在对每一部分进行讲解前,先用一个图来讲解各部分之间的关系:

    对于图中的每一个带有标号的部分,下面给出简单的代码使用展示, 如果暂时不明白下面的代码可以先进行下一章节的学习。

    3.1 获取kubeconfig及context

    这一部分对应于序号1---tools/clientcmd。

    func main() {
            var kubeconfig *string
    
            // 默认会从~/.kube/config路径下获取配置文件
            if home := homeDir(); home != "" {
                    kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional)absolute path to the kubeconfig file")
            } else {
                    kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
            }
    
            flag.Parse()
    
            // 使用k8s.io/client-go/tools/clientcmd生成config的对象
            if config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig); err != nil {
                    panic(err.Error())
            }
    }
    

    3.2 创建ClientSet

    这一部分对应于序号2---ClientSet。

    // 使用k8s.io/client-go/kubernetes生成一个ClientSet的客户端,客户端生成后,就可以使用这个客户端与k8s API server进行交互了,如获取资源列表、Create/Update/Delete资源等
    clientset, err := kubenetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }
    

    3.3 使用ClientSet获取集群中的pods

    这一部分对应于序号2/3/4---RestClient。

    for {
        // 使用ClientSet客户端获取集群中所有的Pods。其中:ListOptions的结构如下:
        // type ListOptions struct {
        //      TypeMeta `json:",inline"`
        //      LabelSelector string `json:"labelSelector,omitempty"`
        //      FieldSelector string `json:"fieldSelector,omitempty"`    
        //}
        pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
        if err != nil {
            panic(err.Error())
        }
    
        fmt.Printf("Number of pods are: %d
    ", len(pods.Items))
    }
    

    3.4 使用ClientSet获取指定的pod

    这一部分对应于序号2/3/4---tools/clientcmd。

    for {
        // 在这里我们从default这个namespace中获取了名为my-pod的Pod对象
        pod, err := clientset.CoreV1().Pods("default").Get("my-pod", metav1.GetOptions{})
        if err != nil {
            painc(err.Error())
        }
    
        fmt.Printf("%v
    
    
    
    ", pod.spec)
    }
    

    4. 各种Clients详解

    client-go中定义的比较重要的client有:

    其中,RestClient是所有客户端的基础,后三者都是对RestClient的封装。RestClient它通过kubeconfig与k8s-api-server进行交互。详细结构如下图:

    ClientSets使用预生成的API对象, 这样的好处是当本地的API对象与k8s-api-server进行交互时会变得比较方便,方便的同时,随之也带来了版本与类型强耦合的问题。

    DynamicClient则使用unstructured.Unstructured表示来自API Server的所有对象值。Unstructured类型是一个嵌套的map[string]inferface{}值的集合来创建一个内部结构,这一点类似于RESTful API中的Json数据,这样可以解决ClientSet中出现的强耦合的问题,换句话说,当客户端的API发生变化时,DynamicClient无需重新编译。DynamicClient使所有数据实现延时绑定,即只有到运行时才会实现绑定,这意味着程序运行之前,使用DynamicClient的程序将不会对对象进行Validation,这也是本client的一个缺点。

    5. 其它组件

    client-go中除了上面提到比较重要的客户端外, 本库还包含了各种机制(tools/cache)。

    下图比较直观的展示了client-go与customer controller及client-go各组件之间的交互关系,是我们在开发自定义控制器时经常需要使用的机制,了解这个图有助于我们更好的理解client-go及controller背后的实现逻辑。

    如果您对client-go之前就比较了解,建议您移步sample-controller看一下控制器实现的具体代码。

    5.1 Reflector

    refelector是定义在包缓存里面的Reflector结构体,可以用于监视指定资源类型(kind)的Kubernetes API。

    实现这个功能的函数是ListAndWatch。监视的对象可以是一个内置的资源,也可以是一个自定义的资源(CRD)。

    当reflector通过watch API接收到关于新资源实例存在的通知时,它会使用相应的listing API获取新创建的对象,并将其放在watchHandler函数里面的DeltaFIFO队列中。

    5.2 Informer

    它是定义在包缓存中的一个基础控制器,它可以w使用函数processLoopDeltaFIFO队列中取出对象。

    这个基础控制器的工作是保存对象以便以后检索,并调用我们的控制器将对象传递给它。

    5.3 Indexer

    提供对对象的索引功能。它被定义在tools/cache包中的Indexer类型中。

    一个典型的索引用例是基于对象标签创建一个索引。Indexer可以基于几个索引函数来维护索引。Indexer使用一个线程安全的数据存储来存储对象和它们的键值。

    tools/cache内的Store类型中定义了一个名为MetaNamespaceKeyFunc的默认函数,该函数为该对象生成一个对象的键,作为<namespace>/<name>组合。

    5.4 WorkQueue

    这是在控制器代码中创建的队列,用于将对象的分发与处理解耦。编写 Resource Event Handler 函数来提取所分发对象的键值并将其添加到工作队列中。


    欢迎关注我的微信公众号:

  • 相关阅读:
    HDU 2196 Computer
    HDU 1520 Anniversary party
    POJ 1217 FOUR QUARTERS
    POJ 2184 Cow Exhibition
    HDU 2639 Bone Collector II
    POJ 3181 Dollar Dayz
    POJ 1787 Charlie's Change
    POJ 2063 Investment
    HDU 1114 Piggy-Bank
    Lca hdu 2874 Connections between cities
  • 原文地址:https://www.cnblogs.com/double12gzh/p/13806424.html
Copyright © 2020-2023  润新知