[k8s源码]5.自己写一个informer控制器

k8s的informer控制器有一个informer,有一个indexer,还需要一个队列来存储从kubernetes API获取的信息。

初始化自己的informer的结构

Go 复制代码
type Controller struct {
	indexer  cache.Indexer
	informer cache.Controller
	queue    workqueue.RateLimitingInterface
}

func NewController(queue workqueue.RateLimitingInterface, indexer cache.Indexer, informer cache.Controller) *Controller {
	return &Controller{
		indexer:  indexer,
		informer: informer,
		queue:    queue,
	}

随后设计一个run函数,从而开始从官方的informer拿取数据,但是我们自己设计的informer会有多个worker来处理从队列拿到的任务。

Go 复制代码
func (c *Controller) Run(workers int, stopCh chan struct{}) {
	go c.informer.Run(stopCh)
	if !cache.WaitForCacheSync(stopCh, c.informer.HasSynced) {
		fmt.Println("not synced!")
		return
	}
	for i := 0; i < workers; i++ {
		go wait.Until(c.runWorker, time.Second, stopCh)
	}
	<-stopCh
	fmt.Println("stop")
}

可以看到我们定义了一个Run方法,接收informer,然后这个方法会调用runWorker这个方法,执行具体事务。那这个方法也要定义。我们先写一个最简单的方法,就是把item打印出来。

Go 复制代码
func (c *Controller) runWorker() {
	item, quit := c.queue.Get() //从队列获取数据
	if quit {
		fmt.Println("has quit the queue")
	}
	fmt.Println("the item is ", item)
	defer c.queue.Done(item)
}

defer 是 Go 语言中的一个关键字,用于延迟(推迟)某个函数或方法的执行,直到包含 defer 语句的函数执行完毕。

现在开始写执行的函数:

Go 复制代码
func main() {
	var kubeconfig *string // 声明为指针
	kubeconfig = flag.String("kubeconfig", "C:/Users/gx/.kube/config", "absolute path to the kubeconfig file")
	flag.Parse() // 需要解析命令行参数

	//创建clientset
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		panic(err.Error())
	}
	kubeClient, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}

	queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())

	//创建控制器
	listWatcher := cache.NewListWatchFromClient(kubeClient.CoreV1().RESTClient(), "pod", v1.NamespaceDefault, fields.Everything())
	indexer, informer := cache.NewIndexerInformer(listWatcher, &v1.Pod{}, 0, cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			key, err := cache.MetaNamespaceKeyFunc(obj)
			if err == nil {
				queue.Add(key)
			}
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			key, err := cache.MetaNamespaceKeyFunc(newObj)
			if err == nil {
				queue.Add(key)
			}
		},
		DeleteFunc: func(obj interface{}) {
			key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
			if err == nil {
				queue.Add(key)
			}
		},
	}, cache.Indexers{})

runtime.Object它代表了任何可以被序列化/反序列化为 Kubernetes API 对象的类型。所有 Kubernetes 资源类型(如 Pod、Service、Deployment 等)都实现了这个接口。在 NewIndexerInformer 中它告诉 Informer 如何解析从 API 服务器接收到的数据。对于 Pod:&v1.Pod{},对于 Service:&v1.Service{},对于 Deployment:&appsv1.Deployment{}。需确保传入的 runtime.Object 与你的 ListerWatcher 监视的资源类型匹配。使用错误的类型可能导致运行时错误或不正确的行为。

回调函数将得到的对象的key添加到队列中。

Indexer 实际上存储的是完整的对象(如 Pod、Service 等),允许通过多种方式(如名字、命名空间等)快速检索对象。作为 API 服务器中对象的本地缓存。Queue 存储的是对象的键(通常是 "namespace/name" 格式的字符串)。作为一个工作队列,存储需要处理的项目。只存储键,而不是完整对象,以节省内存。

Indexer 被设计为可以存储任何类型的 Kubernetes 资源。同一个 Indexer 实现可以用于不同的资源类型(Pod、Service、Deployment 等)。所以indexer和controller接收到的类型为interface。由于返回的是 interface{},我们需要使用类型断言来将其转换为具体的类型。

随着创建的成功,现在我们需要真正的执行:

Go 复制代码
	stop := make(chan struct{})
	controller := NewController(queue, indexer, informer)
	go controller.Run(1, stop)
	select {}

随后执行成功,获得集群里的默认命名空间下的pod名称:

相关推荐
YCyjs1 小时前
K8S群集调度二
云原生·容器·kubernetes
Hoxy.R1 小时前
K8s小白入门
云原生·容器·kubernetes
€☞扫地僧☜€4 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
全能全知者5 小时前
docker快速安装与配置mongoDB
mongodb·docker·容器
为什么这亚子7 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
ZHOU西口9 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
牛角上的男孩9 小时前
Istio Gateway发布服务
云原生·gateway·istio
JuiceFS11 小时前
好未来:多云环境下基于 JuiceFS 建设低运维模型仓库
运维·云原生
景天科技苑12 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
wclass-zhengge12 小时前
K8S篇(基本介绍)
云原生·容器·kubernetes