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