Client-go

        想要读懂kubernetes 源码,首先要理解client-go, 因为client-go 是 Kubernetes 官方的 Go 语言客户端库,被 Kubernetes 中的众多组件和功能模块使用。其中包括 kube-apiserver、kube-controller-manager、kube-scheduler 等核心组件,以及一些扩展功能如 kube-proxy、kubelet 等。client-go 还提供了访问 Kubernetes API 的便捷方式,所以在后面开发CRD operator时,也被广泛使用。

1. Client-go的重要组件

  1. DiscoveryClient:DiscoveryClient 是一个用于发现 Kubernetes API 的组件,它可以获取集群中所有的 API 版本和资源类型。

  2. DynamicClient:DynamicClient 是一个用于处理 Kubernetes API 对象的组件,它允许进行动态操作,这意味着你可以编写处理任意 Kubernetes API 对象的代码,而不需要提前知道这些对象的模式。

  3. RESTClient:RESTClient 是 client-go 的核心,它发送所有的 HTTP 请求。当你使用 ClientSet,DynamicClient 或 DiscoveryClient 时,这些请求实际上是由 RESTClient 发送的。

  4. Informers和Listers:这些组件用于在本地缓存 Kubernetes API 对象,并提供了一种通知框架,以便可以在 Kubernetes 对象更改时接收到通知。这对于构建控制器和其他需要对 Kubernetes 状态进行长时间运行的操作非常有用。

  5. Workqueue:这是一个实现了生产者/消费者队列的工具,主要用于构建控制器和其他需要处理 Kubernetes 对象的长时间运行的操作。

2. Client-go的cache工具包

        在开发CRD operator时最离不开的就是cache,它提供了一些用于监听、缓存和查询 Kubernetes 资源对象的工具。下面这张图来自于client-go的文档。上半部分属于client-go cache提供的组件。下半部分是开发controller需要实现的操作。

  1. Reflector
    Reflector 是一个用于从 Kubernetes API 获取资源并将其同步到本地缓存的工具。这个是事件驱动的。

    1.1监听事件:Reflector 首先会与 Kubernetes API 服务器建立连接,并通过 Watch 机制来监听资源对象的增删改事件。

    1.2.处理事件:当 Reflector 接收到 API 服务器发送的事件通知时,它会将这些事件转换成 DeltaFIFO 中的操作,如 Add、Update、Delete 等。

    1.3.操作 DeltaFIFO:Reflector 会将这些事件操作应用到 DeltaFIFO 中,以确保本地缓存中的资源对象能够与实际的集群状态保持同步。这可能涉及将事件操作应用到 DeltaFIFO 队列中,以确保它们按正确的顺序进行处理。

  2. DeltaFIFO
    DeltaFIFO 是一个用于存储 Kubernetes 资源对象更改事件的队列,它是 Informer 和 Reflector 的底层存储结构。每种资源类型(如 Pod、Service、Deployment 等)都会有一个相关的 Informer,而每个 Informer 会维护一个自己的 DeltaFIFO 队列来追踪该类型资源的增删改变化事件。DeltaFIFO 队列默认情况下没有设置大小,如果需要对 DeltaFIFO 的大小进行限制,可以在创建 DeltaFIFO 实例时,通过设置 MaxSize 参数来指定队列的最大值。

    fifo := cache.NewDeltaFIFO(cache.MetaNamespaceKeyFunc, runtime.NewScheme(), nil, <maxSize>)
    
  3. Informer:
    Informer 是一个用于监听和缓存 Kubernetes API 资源对象的工具,它会在资源对象发生变化时发送通知。Informer 包括 SharedInformer 和具体的资源类型 Informer,如 PodInformer。虽然 podInformer 主要用于 Pod 资源对象的监听和消费,但它并不限定于只监听 Pod 资源的变化。实际上,podInformer 也可以监听与 Pod 相关的其他事件,比如 Node、Service、Endpoints 等与 Pod 相关的资源对象的变化。常见的Informer类型:

    1.PodInformer:用于监听和管理 Pod 资源对象的变化。
    2.NodeInformer:用于监听和管理 Node 资源对象的变化。
    3.ServiceInformer:用于监听和管理 Service 资源对象的变化。
    4.DeploymentInformer:用于监听和管理 Deployment 资源对象的变化。
    5.ReplicaSetInformer:用于监听和管理 ReplicaSet 资源对象的变化。
    6.DaemonSetInformer:用于监听和管理 DaemonSet 资源对象的变化。
    7.StatefulSetInformer:用于监听和管理 StatefulSet 资源对象的变化。
    8.JobInformer:用于监听和管理 Job 资源对象的变化。
    9.NamespaceInformer:用于监听和管理 Namespace 资源对象的变化。
    10.ConfigMapInformer:用于监听和管理 ConfigMap 资源对象的变化。
    11.SecretInformer:用于监听和管理 Secret 资源对象的变化。
    12.PersistentVolumeInformer:用于监听和管理 PersistentVolume 资源对象的变化。
    13.PersistentVolumeClaimInformer:用于监听和管理 PersistentVolumeClaim 资源对象的变化。
  4. Indexer:
    Indexer 提供了一种对缓存对象进行索引和查询的方式,可以根据不同的字段(如名称、标签等)对资源进行索引。Indexer 是基于 Store 接口扩展出来的。Store 提供了对 Kubernetes 资源对象进行基本操作的一组方法,如添加(Add)、更新(Update)、删除(Delete)、获取(Get)和列出(List)等。Indexer 在 Store 的基础上,增加了一组用于对 Kubernetes 资源对象进行索引和查询的方法,如 Index、IndexKeys、ListIndexFuncValues、ByIndex、GetIndexers 和 AddIndexers 等。

        举个例子,假设我们想要根据一个 Pod 的标签来索引 Pod。我们可以定义一个索引函数,这个函数接收一个 Pod 对象,读取它的标签字段,然后返回这些标签作为索引键。这种索引函数可能如下所示(假设我们对 "app" 标签感兴趣):

func podAppIndexFunc(obj interface{}) ([]string, error) {
    pod, ok := obj.(*v1.Pod)
    if !ok {
        return []string{}, nil
    }

    if app, exists := pod.Labels["app"]; exists {
        return []string{app}, nil
    }

    return []string{}, nil
}

        在这个例子中,索引函数接收一个 Pod 对象,检查它是否有 "app" 标签。如果有,函数就返回这个标签的值作为索引键。然后,你可以将这个索引函数添加到 Indexer 中:

indexers := cache.Indexers{
    "byApp": podAppIndexFunc,
}
informer := cache.NewSharedIndexInformer(
    &cache.ListWatch{...},
    &v1.Pod{},
    0, // 不同步
    indexers,
)

然后,你就可以使用 "byApp" 索引来检索 Pod 了:

pods, err := informer.GetIndexer().ByIndex("byApp", "myapp")

        这段代码会返回所有 "app" 标签值为 "myapp" 的 Pod。        

     5.ThreadSafeStore 的数据结构包括:

  • items:一个字典,用于存储 Kubernetes 资源对象,其中字典的键是资源对象的键(通常是资源的 Namespace 和 Name 的组合),字典的值是资源对象本身。

  • indexers:一个字典,用于存储多个索引函数,其中字典的键是索引的名称,字典的值是索引函数。索引函数用于根据资源对象的某些属性生成索引键。

  • indices:一个字典,用于存储由索引函数生成的索引键及对应的资源对象键。其中字典的键是索引键,字典的值是一个集合,集合中的元素是对应的资源对象键。
    这些数据结构都由一个读写锁(sync.RWMutex)保护,以确保在多线程环境中对其进行操作时的线程安全。

3. Client-go是如何暴露给custom controller的?

        从上图中可以看出,custom controller是通过调用三个reference(res event handlers reference, informer reference,indexer reference)实现的。具体的方法是:

  1. ResourceEventHandler:ResourceEventHandler 是一个接口,可以定义对 Kubernetes 资源对象变更事件的处理方法。在 controller 中,你可以实现这个接口,然后将其添加到 Informer 中。当 Kubernetes 资源对象发生变更时,Informer 会调用相应的处理方法。

  2. Informer:Informer 可以通过 client-go 的 informers 包来获取。每种类型的 Kubernetes 资源(如 Pod、Service、Deployment 等)都有自己的 Informer。controller 可以通过调用 Informer 的 Listers 方法来获取资源对象的列表,或者通过调用 Informer 的 AddEventHandler 方法来添加事件处理器。

  3. Indexer:Indexer 是 Informer 的一部分,可以通过调用 Informer 的 GetIndexer 方法来获取。Indexer 提供了对 Kubernetes 资源对象进行索引和查询的功能,controller 可以使用这些功能来快速查找特定的资源对象。

举个例子:

import (
    "k8s.io/client-go/informers"
    "k8s.io/client-go/tools/cache"
)

func main() {
    // 创建 Kubernetes 客户端
    kubeClient, _ := kubernetes.NewForConfig(config)

    // 创建 Informer 工厂
    informerFactory := informers.NewSharedInformerFactory(kubeClient, 0)

    // 获取 Pod Informer
    podInformer := informerFactory.Core().V1().Pods().Informer()

    // 在 Pod Informer 上添加事件处理器
    podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
        AddFunc: func(obj interface{}) {
            // 处理 Pod 创建事件
        },
        UpdateFunc: func(oldObj, newObj interface{}) {
            // 处理 Pod 更新事件
        },
        DeleteFunc: func(obj interface{}) {
            // 处理 Pod 删除事件
        },
    })

    // 获取 Indexer
    indexer := podInformer.GetIndexer()

    // 使用 Indexer 进行查询
    pods, err := indexer.ByIndex("my-index", "my-value")

    // 启动 Informer
    informerFactory.Start(wait.NeverStop)
}

一个 ResourceEventHandler 被添加到 Pod Informer 中以处理 Pod 的变更事件,同时 Indexer 被用于查询特定的 Pod。

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值