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

相关推荐
扣脚大汉在网络5 分钟前
云原生安全渗透篇
安全·云原生·dubbo
csdn_aspnet1 小时前
使用 .NET 9 和 Azure 构建云原生应用程序:有什么新功能?
microsoft·云原生·azure
字节源流2 小时前
【spring cloud Netflix】Eureka注册中心
云原生·eureka
Brilliant Nemo3 小时前
Docker 镜像相关的基本操作
运维·docker·容器
基哥的奋斗历程4 小时前
kubernetes configMap 存储
云原生·容器·kubernetes
阿里云云原生1 天前
LLM 不断提升智能下限,MCP 不断提升创意上限
云原生
阿里云云原生1 天前
GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩
云原生
云上艺旅1 天前
K8S学习之基础七十四:部署在线书店bookinfo
学习·云原生·容器·kubernetes
c无序1 天前
【Docker-7】Docker是什么+Docker版本+Docker架构+Docker生态
docker·容器·架构
FixBug_Nick1 天前
使用Docker安装及使用最新版本的Jenkins
docker·容器·jenkins