2025-10-23 informer模式

informer 机制的原理、关键源码点(来自 kubernetes 仓库)和针对云平台使用 client-go 时的设计/实现建议与示例代码。穿插对核心源码(Reflector、SharedInformer、SharedInformerFactory、Lister/Indexer、ListerWatcher 等)的引用与要点摘录,最后给出在云平台中常用的工程实践和示例实现。

一、核心概念与整体流程(高层架构)

  • ListerWatcher:负责通过 Kubernetes API 做 List(获取当前快照)和 Watch(订阅增量事件)。通常由 client-go 提供的 ListWatch(实现 ListerWatcher 接口)创建。
  • Reflector:对某个资源类型运行 List + Watch,将 API Server 的结果转换为“delta”(变化)推入 Delta FIFO(DeltaFIFO 是一种队列,存储 add/update/delete 以及同步等事件)。
  • SharedIndexInformer(简称 SharedInformer):消费 DeltaFIFO(processLoop),把变化应用到本地 Store/Indexer(用于缓存对象并提供索引),并把事件分发给已注册的事件处理器(event handlers)。
  • SharedInformerFactory:管理与复用多个 informers(同一进程中对同一类型资源只创建一个 informer),并负责并发启动、WaitForCacheSync 等。
  • Lister / Indexer:基于 informer 的本地缓存提供高效本地读(避免再去 API Server)。控制器通常在处理队列时使用 lister 读取最新对象状态。

整体流程(按时间顺序):

  1. SharedInformerFactory -> 创建/获取 SharedIndexInformer(InformerFor/ForResource)
  2. Start(stopCh) -> 对每个 informer 启动 goroutine(内部启动 Reflector、并循环处理 DeltaFIFO)
  3. Reflector 首先执行 List 获取现有对象并 Push 到 DeltaFIFO(初始化 full sync),随后开启 Watch,将收到的 watch events 转成 deltas 送入 DeltaFIFO
  4. SharedInformer 的 processLoop 从 DeltaFIFO pop delta,更新本地 Store/Indexer,然后调用 Handler(Add/Update/Delete 回调)
  5. 控制器的回调通常不做 heavy work,而是把对象 key 放入 workqueue,后台 worker 从队列取 key,用 lister 获取对象并执行 reconcile(幂等处理)

二、关键源码位置(引用原仓库片段与说明) 下面列出并引用了在 kubernetes 仓库中与 informer 机制最相关的源码文件与片段(有助于跟踪实现细节):

/* 片段来源,Reflector 管理 List+Watch、重试和资源版本、以及是否使用 watch-list 流式获取等逻辑 */
	// MaxInternalErrorRetryDuration defines how long we should retry internal errors returned by watch.
	MaxInternalErrorRetryDuration time.Duration
	// useWatchList if turned on instructs the reflector to open a stream to bring data from the API server.
	// Streaming has the primary advantage of using fewer server's resources to fetch data.
	//
	// The old behaviour establishes a LIST request which gets data in chunks.
	// Paginated list is less efficient and depending on the actual size of objects
	// might result in an increased memory consumption of the APIServer.
	//
	// See https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/3157-watch-list#design-details
	useWatchList bool

说明:

  • Reflector 实现了 ListAndWatch 的核心(在 client-go 的 reflector.go 中),负责维护 resourceVersion、重连和错误重试、以及把变更放入 DeltaFIFO(watchHandler)。
/* 片段来源,SharedIndexInformer 创建、结构体字段与 resync/handler 管理 */
func NewSharedIndexInformer(lw ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration, indexers Indexers) SharedIndexInformer {
	return NewSharedIndexInformerWithOptions(
		lw,
		exampleObject,
		SharedIndexInformerOptions{
			ResyncPeriod: defaultEventHandlerResyncPeriod,
			Indexers:     indexers,
		},
	)
}

/* ... */
	// resyncCheckPeriod is how often we want the reflector's resync timer to fire so it can call
	// shouldResync to check if any of our listeners need a resync.
	resyncCheckPeriod time.Duration
	// defaultEventHandlerResyncPeriod is the default resync period for any handlers added via
	// AddEventHandler (i.e. they don't specify one and just want to use the shared informer's default
	// value).
	defaultEventHandlerResyncPeriod time.Duration

说明:

  • SharedIndexInformer 将 ListerWatcher 传入用于创建内部的 Reflector/DeltaFIFO/Indexer,管理 handler 的分发与周期性 resync(如果指定了 resync)。

还有一些工厂和样例的关键代码:

示例文档说明了“Reflector + Informer” 的职责划分(sample-controller 文档):

# client-go under the hood
* Reflector: ... watches the Kubernetes API for the specified resource type ...
* Informer: ... pops objects from the Delta Fifo queue, 保存 object 并调用 controller

三、关键实现细节(更技术的点)

  • DeltaFIFO:负责把 List 的快照和 Watch 的事件转成 “delta” 并按顺序发送给 informer。它内部会合并相同 Key 的连续 delta(避免重复处理),并为第一次全量 List 构造 Sync/Replace 类型的 delta。
  • Store / Indexer:Store 保存对象以 key(namespace/name)为索引;Indexer 允许额外的索引函数(例如按 namespace、node、label 等),便于高效查询。
  • Resync:SharedInformer 支持 handler-level 的 resync。Resync 并不是去 API Server 做全量 List,而是触发 handler 的周期性通知,方便做周期性校验逻辑。Resync 周期可通过 factory 设置默认值或在 AddEventHandlerWithResyncPeriod 指定。
  • 资源版本(resourceVersion)和可靠性:Reflector 使用 resourceVersion 做持续 watch;遇到 watch 丢失或超时会进行 re-list,然后继续 watch。还有内部重试参数(MaxInternalErrorRetryDuration)来控制内部错误的重试持续时间。
  • 并发与启动:SharedInformerFactory 确保每种资源类型只启动一个 informer;Start 可以被多次安全调用(使用 startedInformers map),Stop 通过 stopCh 通知所有 goroutine 退出。

四、云平台使用 client-go + informer 的设计建议(架构与代码实践)

  1. 使用 SharedInformerFactory 复用 informer:

    • 在每个控制平面进程/daemon(或 controller manager)中使用一个 SharedInformerFactory(或若按租户/逻辑划分,可多个,但应尽量复用),避免为每个 controller 单独创建 informer,节省连接与内存。
    • 例:factory := informers.NewSharedInformerFactory(clientset, resyncPeriod)
  2. 使用 lister 来减少 API Server 请求:

    • 在 worker reconcile 中使用 lister(而不是每次调用 API Server)。只有在需要最精确或写入操作前再用 clientset 请求或 PATCH。lister 会基于 informer 的本地缓存实现快速读取。
  3. 将事件处理与业务逻辑解耦(controller 模式):

    • AddEventHandler 中只把 key(namespace/name)放入 RateLimitingQueue(或 workqueue),具体的处理放到后台多 worker goroutine 中。这样可以重试、限流、统一错误处理和并发控制。
  4. CRD / 动态资源支持:

    • 如果需要支持大量未知类型资源或 CRD,优先使用 dynamicinformer(dynamic client + dynamicinformer),或通过 code-generator 生成 typed informers(生成的 typed informer 性能更好且类型安全)。
    • dynamicinformer 的示例位置:staging/src/k8s.io/client-go/dynamic/dynamicinformer/informer.go
  5. leader election(多副本部署):

    • 在云平台中 controller 可能水平部署,使用 leader election(k8s.io/client-go/tools/leaderelection)只让 leader 做写操作(controller reconcile),其他副本作为热备,这样可以避免重复操作/冲突。Informer 缓存可以在 non-leader 也保持同步(读缓存),但写操作仅 leader 执行。
  6. 错误处理与重试:

    • Worker 在业务失败时使用 workqueue 的 requeue/backoff 机制;避免将错误暴露到事件处理通路以阻塞事件分发。
  7. 监控与指标:

    • 监控 informer 的 sync 状态(WaitForCacheSync 返回的 bool map)、watch 重连频率、队列长度、处理时延等。
    • 关键指标:informer watch 重连次数、delta 队列长度、worker 失败次数与重试次数。
  8. 性能与内存:

    • 将无需全量对象的 controller 使用 indexers(自定义索引)来快速筛选子集,避免把全部对象扫描一遍。
    • resyncPeriod 不宜设太小,避免大量 resync 导致重复处理;对短期需要强一致的逻辑可以用短 resync 或在 reconcile 中主动校验。

五、示例代码(在云平台中常见的 controller 主流程) 下面给出一个简化的 controller main 和 controller 的示例实现,展示如何正确使用 SharedInformerFactory、AddEventHandler、workqueue、lister、WaitForCacheSync 等(可直接在云平台控制器中使用)。

package main

import (
	"context"
	"flag"
	"time"

	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
)

func main() {
	resync := flag.Duration("resync", 0, "default resync period")
	flag.Parse()

	cfg, err := rest.InClusterConfig()
	if err != nil {
		// for local dev, use kubeconfig...
		panic(err)
	}
	clientset, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		panic(err)
	}

	// 共享 factory(建议为整个进程/服务只创建一个)
	factory := informers.NewSharedInformerFactory(clientset, *resync)

	// 以 Pod 为例,获取 informer & lister
	podInformer := factory.Core().V1().Pods()
	controller := NewPodController(clientset, podInformer, workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "pods"))

	stopCh := make(chan struct{})
	defer close(stopCh)

	// 注册事件处理器
	podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    controller.EnqueueAdd,
		UpdateFunc: controller.EnqueueUpdate,
		DeleteFunc: controller.EnqueueDelete,
	})

	// 启动 factory(内部会启动 informer 的 goroutine)
	factory.Start(stopCh)

	// 等待缓存同步
	if ok := cache.WaitForCacheSync(stopCh, podInformer.Informer().HasSynced); !ok {
		panic("failed to wait for caches to sync")
	}

	// 启动 controller 工作协程
	go controller.Run(2, stopCh)

	<-stopCh
}
package main

import (
	"context"
	"fmt"
	"time"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/client-go/kubernetes"
	listersv1 "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/klog/v2"
)

// PodController 是简化版示例
type PodController struct {
	client    kubernetes.Interface
	podLister listersv1.PodLister
	queue     workqueue.RateLimitingInterface
}

// NewPodController 构造
func NewPodController(client kubernetes.Interface, podInformer cache.SharedIndexInformer, q workqueue.RateLimitingInterface) *PodController {
	return &PodController{
		client:    client,
		podLister: listersv1.NewPodLister(podInformer.GetIndexer()),
		queue:     q,
	}
}

// EnqueueAdd/Update/Delete 只把 key push 到 queue
func (c *PodController) EnqueueAdd(obj interface{})    { c.enqueue(obj) }
func (c *PodController) EnqueueUpdate(old, new interface{}) { c.enqueue(new) }
func (c *PodController) EnqueueDelete(obj interface{}) { c.enqueue(obj) }

func (c *PodController) enqueue(obj interface{}) {
	key, err := cache.MetaNamespaceKeyFunc(obj)
	if err != nil {
		klog.Errorf("failed to get key: %v", err)
		return
	}
	c.queue.Add(key)
}

// Run 启动 worker
func (c *PodController) Run(threadiness int, stopCh <-chan struct{}) {
	defer c.queue.ShutDown()
	for i := 0; i < threadiness; i++ {
		go func() {
			for c.processNextItem() {
			}
		}()
	}
	<-stopCh
}

func (c *PodController) processNextItem() bool {
	key, quit := c.queue.Get()
	if quit {
		return false
	}
	defer c.queue.Done(key)
	if err := c.syncHandler(key.(string)); err != nil {
		// 失败重试
		c.queue.AddRateLimited(key)
		klog.Errorf("sync failed: %v", err)
	} else {
		c.queue.Forget(key)
	}
	return true
}

func (c *PodController) syncHandler(key string) error {
	// 使用 lister 从缓存读取(避免去 API Server)
	ns, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		return err
	}
	pod, err := c.podLister.Pods(ns).Get(name)
	if err != nil {
		// not found -> 可能已被删除
		return nil
	}

	// 业务逻辑(示例)
	fmt.Printf("处理 Pod: %s/%s phase=%s\n", pod.Namespace, pod.Name, pod.Status.Phase)
	// 这里会做真正的 reconcile(幂等)
	time.Sleep(10 * time.Millisecond)
	return nil
}

六、常见问题与注意事项

  • 不要在事件回调中做长耗时操作(应使用 workqueue)。事件回调应尽量轻量(只 enqueue key)。
  • 尽量复用 SharedInformerFactory,避免大量重复 watch/连接。
  • 当处理 CRD 或动态资源时,dynamicinformer 比自己实现 ListerWatcher 更方便,但性能/类型安全与 typed informer 有差距。对大量高性能场景推荐 code-generator 生成 typed informer。
  • 监控和 readiness:在 startup 时 WaitForCacheSync 非常重要,确保在 reconcile 前 informer 的 cache 已经同步(否者可能读取到空/不完整数据)。
  • 处理 Watch 断开和全量 list:Reflector 内部已经处理了重连、re-list,业务层一般不需要再关心,但应做好日志和监控,检测频繁重连指示 API Server 或网络问题。

七、总结(关键信息回顾)

  • informer 机制的核心是:Reflector(List+Watch) -> DeltaFIFO -> SharedInformer(更新本地 Store/Indexer)-> EventHandler -> controller workqueue -> reconcile(使用 lister)。
  • 在云平台中推荐使用一个 SharedInformerFactory 复用 informer,使用 lister 做本地读,事件回调仅 enqueue,实际处理放在 worker 中,并结合 leader election、指标、监控与合理的 resync 策略来保证稳定性与伸缩性。
  • 对 CRD 与未知资源使用 dynamicinformer 或生成 typed informer,根据场景权衡类型安全与灵活性。

如果你愿意,我可以:

  • 基于你们云平台现有的代码结构,帮你生成一个具体的 controller 模板(包括 leader election、metrics、健康探针、日志)。
  • 或者把某个具体资源(例如 Node、Pod、CustomResource)的 informer 创建与 reconcile 逻辑写成可直接复制的工程化代码示例。

你想要哪一种:生成完整模板(包含 leader election + metrics + graceful shutdown),还是把上面示例扩展成处理某个具体业务(请说明资源类型和业务需求)?

啥意思 client-go里面有实现informer机制吗,需要我在云平台的后端去实现informer机制吗? #

短答:不需要你自己从头实现 informer 机制。client-go 已经实现了完整的 informer 体系(Reflector、DeltaFIFO、SharedIndexInformer、SharedInformerFactory、Indexer/Lister 等),在云平台后端应当复用 client-go 提供的实现,自己只需写 controller 的业务逻辑、事件处理器和可能的少量适配(比如自定义 ListerWatcher 或 dynamic informer)。

下面把要点和实践建议说清楚,便于你在云平台中正确使用。

  1. client-go 有没有实现 informer?
  • 有。client-go tools/cache 包实现了 Reflector(List+Watch)、DeltaFIFO、SharedIndexInformer(事件分发、本地 Store/Indexer、resync)、以及相关的 Lister/Indexer。client-go 还提供了 SharedInformerFactory 用于复用 informer,另外有 typed informers(code-generator 生成的)和 dynamic/metadata informer 支持动态资源。
  • 你可以直接使用 informers.NewSharedInformerFactory、dynamicinformer、或者 metadatainformer 等接口。
  1. 云平台后端需要做什么?
  • 不用重写 informer 的内部实现;应该:
    • 创建并复用 SharedInformerFactory(进程/服务级别)来管理所有需要的 informers。
    • 在 informer 上注册事件处理器(Add/Update/Delete),但事件回调中只 enqueue key(namespace/name)。
    • 在 controller 中用 workqueue + 多 worker goroutine 来做实际 reconcile(使用 lister 从本地缓存读取对象)。
    • 在启动时调用 factory.Start(stopCh) 并 WaitForCacheSync 确保缓存同步后再开始处理。
  1. 常见工程实践(云平台适配)
  • 复用 factory:整个后端进程一般只创建一个(或少量) SharedInformerFactory,避免重复 watch/过多连接。
  • 使用 lister:在 reconcile 中尽量用 lister(本地缓存)读取,只有在必须写操作前调用 API Server。
  • 事件处理轻量化:在 ResourceEventHandler 中不要做 heavy work,只 push key 到工作队列。
  • leader election:如果 controller 多副本部署,结合 leader election(client-go 提供)只让 leader 做写操作。
  • CRD/动态资源:若需要支持未知资源或大量 CRD,使用 dynamicinformer;若资源固定且性能重要,优先用 code-generator 生成 typed informers。
  • 自定义 List/Watch:只有在需要代理 API、做特殊过滤或跨集群同步时才实现自定义 ListerWatcher;否则用 client-go 提供的默认实现和 tweakListOptions。
  • Resync 与索引:合理设置 resync 周期(默认可以不频繁),使用 Indexers 做高效查询(按 namespace/label 等)。
  • 错误/重试:通过 workqueue 的 rate limiting/backoff 处理失败重试;监控 watch 重连频繁度和 Queue 长度。
  • 监控/就绪:用 WaitForCacheSync 保证启动时缓存已同步,并导出指标(sync 状态、队列长度、处理延迟、reconcile 错误率等)。
  1. 什么时候需要自己实现或定制 informer 相关代码?
  • 仅在下面场景才考虑自己实现或深度定制:
    • API 路径不是标准 Kubernetes API,需要自定义 List/Watch(实现 ListerWatcher)。
    • 需要把事件交给跨进程共享的缓存层(例如外部缓存服务),而不是内存 Store。
    • 需要非常特殊的合并/去重策略,DeltaFIFO 默认行为不满足。
    • 做跨集群同步或代理 watch/list,需要在 Reflector 入口做适配。
  • 否则直接复用 client-go 的实现更安全、稳定、节省维护成本。
  1. 精简示例(使用模式,伪代码)
  • 主流程(要点:factory、AddEventHandler、Start、WaitForCacheSync、worker):
    • NewSharedInformerFactory(clientset, resync)
    • podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{…enqueue key…})
    • factory.Start(stopCh)
    • cache.WaitForCacheSync(stopCh, podInformer.Informer().HasSynced)
    • 启动 worker 循环,从 workqueue 取 key,用 lister 获取对象进行 reconcile

(如果需要我可以把完整可运行的模板代码给你,包括 leader election、metrics、健康探针与 graceful shutdown。)

  1. 小结(一句话)
  • client-go 已经实现 informer 机制。你在云平台后端一般不用也不应该从头实现该机制;应当基于 client-go 的 informer + lister + workqueue 模式实现控制器逻辑,并在必要时做少量适配(dynamic informer / 自定义 ListerWatcher / tweakListOptions)。

需要的话我可以:

  • 给出你需要的完整 controller 模板代码(包括 leader election + metrics + health 路由),或
  • 针对你们平台的特殊 API(如果有)给出如何实现自定义 ListerWatcher / 适配的示例。

你想要哪一种?或者告诉我你具体要监控/处理的资源类型和部署场景(单实例/多副本/多集群),我就生成相应模板。

OK 云平台的什么api请求可以通过client-go的informer机制获取,pod/deployment/service的状态和详细信息可以吗? #

可以。要点总结先给你,然后配上简短的代码示例和注意事项,方便你在云平台后端直接应用。

要点总结

  • client-go 的 informer 通过对 API Server 发起 LIST(初始化快照)和 WATCH(增量流)来维护本地缓存(Store/Indexer)。因此凡是 API Server 暴露的资源(REST 资源),都可以用 informer 获取:Pod、Deployment、Service、Node、ConfigMap、Secret、CRD(CustomResource)等。
  • informer 缓存中保存的是对象的完整内容(默认 typed informer 和 dynamic informer 都返回完整对象,包括 spec、status、metadata 等字段),所以你可以通过 lister 读取到对象的状态(比如 Pod.Status、Deployment.Status、Service.Spec/Status 等)。
  • 注意有一个 metadata-only 的 informer(metadatainformer),它只缓存 metadata(节省内存),如果需要 status/detail,要用 typed informer 或 dynamic informer(unstructured)。
  • informer 发起的 API 请求类型主要是 LIST 和 WATCH(client-go 的 Reflector 实现)。你不需要自己向 API Server 频繁请求读取,因为 lister 可以从缓存读取;仅在需要强一致或写前验证时才直接用 clientset GET/PATCH。
  • 权限:能否 List/Watch/GET 取决于所用的 ServiceAccount 的 RBAC(需要对应资源的 list/watch/get 权限)。
  • 缓存是“最终一致”的(eventual consistent),有可能有短暂滞后;若需要绝对最新值,可在 reconcile 中在必要时直接调用 API Server。

几个实用点

  • Typed informer(推荐,类型安全、性能好):factory.Core().V1().Pods() / factory.Apps().V1().Deployments() / factory.Core().V1().Services()
  • Dynamic informer(用于 CRD 或运行时未知类型):dynamicinformer.NewFilteredDynamicSharedInformerFactory(…)
  • Metadata-only informer(仅需要 metadata 时节省内存):metadatainformer
  • 过滤:可以通过 tweakListOptions(或 ListOptions)设置 labelSelector、fieldSelector、namespace 等,减少传输和缓存量。
    • 注意:不是所有字段都支持 field selector,支持字段受 API 实现限制(例如 Pod 支持 status.phase 的 field selector)。
  • 如果你在多副本部署控制器,最好配合 leader election 仅由 leader 执行写操作,其他副本可以订阅缓存但不执行写行为。

最小示例(typed informer,读取 Pod/Deployment/Service 的状态)

// 假设已有 clientset 和 factory
factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute) // 全局 factory

podInf := factory.Core().V1().Pods()
deployInf := factory.Apps().V1().Deployments()
svcInf := factory.Core().V1().Services()

stopCh := make(chan struct{})
defer close(stopCh)

// 注册简单 handler(这里只 enqueue key 的示例略去)
podInf.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) { /* enqueue key */ },
    UpdateFunc: func(old, new interface{}) { /* enqueue key */ },
    DeleteFunc: func(obj interface{}) { /* enqueue key */ },
})

// 启动并等待缓存同步
factory.Start(stopCh)
if !cache.WaitForCacheSync(stopCh, podInf.Informer().HasSynced, deployInf.Informer().HasSynced, svcInf.Informer().HasSynced) {
    // 处理 sync 失败
}

// 从 lister 读取(基于缓存)
pod, err := podInf.Lister().Pods("my-namespace").Get("mypod")
if err == nil {
    // 能直接访问 Pod 的 status/details
    fmt.Println("Pod phase:", pod.Status.Phase)
    fmt.Printf("Pod node: %s\n", pod.Spec.NodeName)
}

deploy, err := deployInf.Lister().Deployments("my-namespace").Get("mydeploy")
if err == nil {
    // Deployment status
    fmt.Println("Deployment available replicas:", deploy.Status.AvailableReplicas)
}

svc, err := svcInf.Lister().Services("my-namespace").Get("myservice")
if err == nil {
    fmt.Println("Service type:", svc.Spec.Type)
    // Service 没有 status 多数情况,但 spec、annotations、ports 都在对象中
}

示例(dynamic informer,用于 CRD 或未知类型)

dinformerFactory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynamicClient, 0, metav1.NamespaceAll, nil)
gvr := schema.GroupVersionResource{Group: "stable.example.com", Version: "v1", Resource: "foos"}
gi := dinformerFactory.ForResource(gvr) // GenericInformer
inf := gi.Informer()
inf.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) { /* ... */ },
})
dinformerFactory.Start(stopCh)
cache.WaitForCacheSync(stopCh, inf.HasSynced)

// 从 cache 获取 unstructured 对象,读取字段
obj, err := inf.GetIndexer().ByIndex(cache.NamespaceIndex, "my-namespace")

(读取具体字段可用 unstructured.NestedString/unstructured.NestedMap 等)

关于 status 与子资源

  • status 子资源:对象的 status 字段在 List/Watch 返回中通常包含(如果 API Server 按常规返回)。所以 informer 缓存里通常能拿到 Status。写 status 需要有 status subresource 的权限(PATCH/UPDATE 子资源)。
  • 有些场景下你只关心 metadata(少内存),这时可选择 metadatainformer,它只包含对象元数据,不包含完整 spec/status。

字段/标签过滤(ListOptions)

  • 通过 tweakListOptions(factory 选项或在创建 informer 时传入)可以设置 LabelSelector、FieldSelector,示例:
    • 只 watch 某个 namespace:在 factory 创建时用 NewFilteredSharedInformerFactory(client, resync, namespace, tweak)
    • label selector: listOptions.LabelSelector = “app=myapp”
    • field selector: listOptions.FieldSelector = “spec.nodeName=node-1” 或 “status.phase=Running”(以 API 支持为准)

权限和可观测性

  • RBAC:确保 ServiceAccount 有 resources: verbs: [get,list,watch](或更精细)权限。
  • 监控:关注 WaitForCacheSync 是否成功、watch 重试次数、队列长度、处理失败率等。

结论(给你的直接建议)

  • 云平台后端若要获取 Pod/Deployment/Service 的“状态和详细信息”,直接用 client-go 的 typed informer 即可(不需要自己实现 informer 机制)。
  • 使用 SharedInformerFactory + typed informers(Core().V1().Pods() / Apps().V1().Deployments() / Core().V1().Services()),通过 lister 读取 Pod.Status、Deployment.Status、Service.Spec 等字段。
  • 仅在需要更高灵活性(CRD/未知类型)或极端优化(只要 metadata)时,考虑 dynamicinformer 或 metadatainformer。

如果你愿意,我可以:

  • 给出一个针对你云平台后端典型部署(single namespace vs all namespaces;是否有 CRD)的完整模板,包括 RBAC 范例与 tweakListOptions 的使用;或者
  • 帮你写出“Pod/Deployment/Service”三者的具体 controller skeleton(含 leader election、WaitForCacheSync、workqueue、metrics)。