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

相关推荐
BUG弄潮儿21 分钟前
k8s 部署 grafana
容器·kubernetes·grafana
我叫于豆豆吖2 小时前
K8S:开源容器编排平台,助力高效稳定的容器化应用管理
容器·节点·调度
mujingluo3 小时前
不同场景下的弹性伸缩
云原生
打败4045 小时前
docker_阿里云镜像仓库
阿里云·docker·容器
StevenZeng学堂5 小时前
【Kubernetes知识点】 解读 Service 和 EndpointSlice 之间的关系
linux·云原生·容器·kubernetes·云计算·go
弥琉撒到我5 小时前
微服务SpringGateway解析部署使用全流程
spring cloud·微服务·云原生·架构·springgateway
雲烟8 小时前
Docker技术
运维·docker·容器
大新新大浩浩9 小时前
centos7.9使用docker容器方式部署jenkins环境
docker·容器·jenkins
汪子熙9 小时前
Kubernetes 节点何时处于就绪状态?
云原生·容器·kubernetes
当天不总结完不回家10 小时前
kubernetes helm 扩容
云原生·容器·kubernetes