[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名称:

相关推荐
阿里云大数据AI技术3 分钟前
千万级数据秒级响应!碧桂园基于 EMR Serverless StarRocks 升级存算分离架构实践
大数据·云原生·serverless
容器魔方42 分钟前
Bilibili、中电信人工智能科技、商汤科技、联通云等正式加入Volcano社区用户组
云原生·容器·云计算
努力的IT小胖子1 小时前
Docker 镜像下载太慢?手把手教你修改镜像源,速度起飞!
后端·docker·容器
阿里云云原生2 小时前
MCP云托管最优解,揭秘国内最大MCP中文社区背后的运行时
云原生
有谁看见我的剑了?2 小时前
docker 运行时权限和 Linux 能力了解
linux·docker·容器
数字化综合解决方案提供商3 小时前
云原生时代的双轮驱动
云原生
小马爱打代码3 小时前
云原生 - Service Mesh
云原生·service_mesh
敖云岚3 小时前
【那些年踩过的坑】Docker换源加速详细教程(截至2025年4月)
运维·docker·容器
柳如烟@4 小时前
Docker安装ES :确保 Kibana 正确连接 Elasticsearch
运维·数据库·elasticsearch·docker·容器·kibana
weisian1514 小时前
云原生--核心组件-容器篇-2-认识下Docker(三大核心之镜像,容器,仓库)
docker·云原生·容器