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

相关推荐
老年DBA3 小时前
Kubernetes 上的 GitLab + ArgoCD 实践(三):使用 ArgoCD 打通 CD 流程
kubernetes·gitlab·argocd
帅帅梓8 小时前
docker图形化管理
docker·容器·eureka
努力搬砖的咸鱼14 小时前
容器之间怎么通信?Docker 网络全解析
网络·docker·云原生·容器
liming49516 小时前
Ubuntu18.04部署k8s
云原生·容器·kubernetes
YC运维18 小时前
Kubernetes资源管理全解析
java·容器·kubernetes
Leinwin18 小时前
微软发布Azure Kubernetes Service Automatic国际版
microsoft·kubernetes·azure
不爱笑的良田20 小时前
从零开始的云原生之旅(六):DaemonSet 实战日志采集器
云原生
chinesegf20 小时前
Docker篇6-项目app.py和flask_app.service配置和映射到docker中
docker·容器·flask
退役小学生呀20 小时前
二十二、DevOps:基于Tekton的云原生平台落地(三)
linux·云原生·容器·kubernetes·k8s·devops·tekton
橙色云-智橙协同研发20 小时前
PLM实施专家宝典:离散制造企业跨域协同与数字化审核方案
云原生·解决方案·数字化转型·plm·国产plm·工程方案·专家总结