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 读取最新对象状态。
整体流程(按时间顺序):
- SharedInformerFactory -> 创建/获取 SharedIndexInformer(InformerFor/ForResource)
- Start(stopCh) -> 对每个 informer 启动 goroutine(内部启动 Reflector、并循环处理 DeltaFIFO)
- Reflector 首先执行 List 获取现有对象并 Push 到 DeltaFIFO(初始化 full sync),随后开启 Watch,将收到的 watch events 转成 deltas 送入 DeltaFIFO
- SharedInformer 的 processLoop 从 DeltaFIFO pop delta,更新本地 Store/Indexer,然后调用 Handler(Add/Update/Delete 回调)
- 控制器的回调通常不做 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)。
还有一些工厂和样例的关键代码:
- SharedInformerFactory / dynamic/metadata informer(工厂用于复用 informer):
- metadata/metadatainformer/informer.go(factory 的字段与 start/wait 实现片段)
- dynamic/dynamicinformer/informer.go(用于 CRD 或 runtime.Object 的 dynamic informer)
示例文档说明了“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 的设计建议(架构与代码实践)
使用 SharedInformerFactory 复用 informer:
- 在每个控制平面进程/daemon(或 controller manager)中使用一个 SharedInformerFactory(或若按租户/逻辑划分,可多个,但应尽量复用),避免为每个 controller 单独创建 informer,节省连接与内存。
- 例:factory := informers.NewSharedInformerFactory(clientset, resyncPeriod)
使用 lister 来减少 API Server 请求:
- 在 worker reconcile 中使用 lister(而不是每次调用 API Server)。只有在需要最精确或写入操作前再用 clientset 请求或 PATCH。lister 会基于 informer 的本地缓存实现快速读取。
将事件处理与业务逻辑解耦(controller 模式):
- AddEventHandler 中只把 key(namespace/name)放入 RateLimitingQueue(或 workqueue),具体的处理放到后台多 worker goroutine 中。这样可以重试、限流、统一错误处理和并发控制。
CRD / 动态资源支持:
- 如果需要支持大量未知类型资源或 CRD,优先使用 dynamicinformer(dynamic client + dynamicinformer),或通过 code-generator 生成 typed informers(生成的 typed informer 性能更好且类型安全)。
- dynamicinformer 的示例位置:staging/src/k8s.io/client-go/dynamic/dynamicinformer/informer.go
leader election(多副本部署):
- 在云平台中 controller 可能水平部署,使用 leader election(k8s.io/client-go/tools/leaderelection)只让 leader 做写操作(controller reconcile),其他副本作为热备,这样可以避免重复操作/冲突。Informer 缓存可以在 non-leader 也保持同步(读缓存),但写操作仅 leader 执行。
错误处理与重试:
- Worker 在业务失败时使用 workqueue 的 requeue/backoff 机制;避免将错误暴露到事件处理通路以阻塞事件分发。
监控与指标:
- 监控 informer 的 sync 状态(WaitForCacheSync 返回的 bool map)、watch 重连频率、队列长度、处理时延等。
- 关键指标:informer watch 重连次数、delta 队列长度、worker 失败次数与重试次数。
性能与内存:
- 将无需全量对象的 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)。
下面把要点和实践建议说清楚,便于你在云平台中正确使用。
- 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 等接口。
- 云平台后端需要做什么?
- 不用重写 informer 的内部实现;应该:
- 创建并复用 SharedInformerFactory(进程/服务级别)来管理所有需要的 informers。
- 在 informer 上注册事件处理器(Add/Update/Delete),但事件回调中只 enqueue key(namespace/name)。
- 在 controller 中用 workqueue + 多 worker goroutine 来做实际 reconcile(使用 lister 从本地缓存读取对象)。
- 在启动时调用 factory.Start(stopCh) 并 WaitForCacheSync 确保缓存同步后再开始处理。
- 常见工程实践(云平台适配)
- 复用 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 错误率等)。
- 什么时候需要自己实现或定制 informer 相关代码?
- 仅在下面场景才考虑自己实现或深度定制:
- API 路径不是标准 Kubernetes API,需要自定义 List/Watch(实现 ListerWatcher)。
- 需要把事件交给跨进程共享的缓存层(例如外部缓存服务),而不是内存 Store。
- 需要非常特殊的合并/去重策略,DeltaFIFO 默认行为不满足。
- 做跨集群同步或代理 watch/list,需要在 Reflector 入口做适配。
- 否则直接复用 client-go 的实现更安全、稳定、节省维护成本。
- 精简示例(使用模式,伪代码)
- 主流程(要点: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。)
- 小结(一句话)
- 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)。