You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置client-go informer仅缓存DaemonSet所属Pod降低内存占用

实现Pod Informer仅缓存DaemonSet归属Pod的方案

原生client-go的NewFilteredSharedInformerFactory仅支持通过TweakListOptionsFunc传递API服务端可识别的labelSelector/fieldSelector参数,不支持本地自定义谓词过滤入缓存对象,针对「仅缓存携带DaemonSet类型ownerReference的Pod」的需求,最稳妥无侵入的方案是自定义带过滤逻辑的Indexer包装层,替换Informer默认使用的缓存存储实现。

核心实现逻辑

Informer的内存缓存由cache.Indexer接口承载,所有全量同步、增量更新的对象都会先写入Indexer再触发事件回调。你可以包装原生Indexer实现,重写所有写入类方法,仅将符合谓词规则的对象存入底层存储,从根源减少缓存内存占用。

1. 定义过滤谓词

先实现Pod归属判断逻辑,兼容Informer删除事件的DeletedFinalStateUnknown兜底场景:

func isDaemonSetPod(obj interface{}) bool {
    pod, ok := obj.(*corev1.Pod)
    if !ok {
        tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
        if !ok {
            return false
        }
        pod, ok = tombstone.Obj.(*corev1.Pod)
        if !ok {
            return false
        }
    }
    for _, ref := range pod.OwnerReferences {
        if ref.Kind == "DaemonSet" && ref.APIVersion == "apps/v1" {
            return true
        }
    }
    return false
}

2. 实现带过滤能力的Indexer包装

重写Add、Update、Replace三个写入方法,不符合规则的对象直接丢弃,不进入底层存储;Delete方法直接透传,避免残留脏数据:

type FilteredIndexer struct {
    cache.Indexer
    predicate func(obj interface{}) bool
}

func (f *FilteredIndexer) Add(obj interface{}) error {
    if !f.predicate(obj) {
        return nil
    }
    return f.Indexer.Add(obj)
}

func (f *FilteredIndexer) Update(obj interface{}) error {
    if !f.predicate(obj) {
        key, err := cache.MetaNamespaceKeyFunc(obj)
        if err == nil {
            _, exists, _ := f.Indexer.GetByKey(key)
            if exists {
                return f.Indexer.Delete(obj)
            }
        }
        return nil
    }
    return f.Indexer.Update(obj)
}

func (f *FilteredIndexer) Replace(objects []interface{}, rv string) error {
    filteredObjs := make([]interface{}, 0, len(objects))
    for _, obj := range objects {
        if f.predicate(obj) {
            filteredObjs = append(filteredObjs, obj)
        }
    }
    return f.Indexer.Replace(filteredObjs, rv)
}

注意必须重写Replace方法:Informer首次启动全量List、以及重连全量同步时都会调用该方法写入全量对象,不重写会导致全量非目标Pod被塞入缓存。

3. 初始化Informer时传入自定义Indexer

不要使用默认SharedInformerFactory生成的Pod Informer,手动创建SharedIndexInformer,传入包装好的FilteredIndexer作为缓存存储:

// 初始化基础Indexer
baseIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{
    cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
})
// 包装为带DaemonSet Pod过滤的Indexer
filteredIndexer := &FilteredIndexer{
    Indexer:   baseIndexer,
    predicate: isDaemonSetPod,
}

// 创建自定义Pod Informer
podInformer := cache.NewSharedIndexInformer(
    &cache.ListWatch{
        ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
            return clientset.CoreV1().Pods("").List(context.TODO(), opts)
        },
        WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
            return clientset.CoreV1().Pods("").Watch(context.TODO(), opts)
        },
    },
    &corev1.Pod{},
    0, // 按需设置resync周期
    filteredIndexer,
)

4. 事件回调层补充过滤

由于Informer的事件回调触发逻辑在对象写入Indexer之前,需要配合client-go原生提供的cache.FilteringResourceEventHandler包装你的业务处理逻辑,确保回调仅收到符合规则的Pod事件:

podInformer.AddEventHandler(cache.FilteringResourceEventHandler{
    FilterFunc: isDaemonSetPod,
    Handler: cache.ResourceEventHandlerFuncs{
        AddFunc: func(obj interface{}) {
            // 业务处理逻辑,入参一定是DaemonSet归属的Pod
        },
        UpdateFunc: func(oldObj, newObj interface{}) {
            // 业务处理逻辑
        },
        DeleteFunc: func(obj interface{}) {
            // 业务处理逻辑
        },
    },
})

其他可选方案

  • 对象裁剪方案:如果使用client-go v0.27及以上版本,可以通过NewSharedInformerFactoryWithOptions的WithTransform选项注册转换函数,在对象入缓存前裁减掉非必要字段(比如Pod的大段Status、冗余Annotation等),可降低30%-50%内存占用,但无法完全丢弃非目标Pod,内存优化效果弱于自定义Indexer方案。
  • 服务端过滤方案:如果有权限修改集群内所有DaemonSet的Pod模板,可给DaemonSet管控的Pod统一注入固定标识标签(比如workload-owner=daemonset),后续直接通过TweakListOptionsFunc设置labelSelector=workload-owner=daemonset,让API Server直接仅返回目标Pod,可同时降低List/Watch的网络传输开销和本地内存占用,但对存量集群侵入性较高。

常见误区

仅在事件回调层加过滤逻辑、或者仅使用FilteringResourceEventHandler无法降低内存占用,所有API Server返回的Pod对象依然会全量存入Informer的Indexer缓存。


内容的提问来源于stack exchange,提问作者ahmet alp balkan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:27:32