kubernetes: strip managedFields in informers

Drop metadata.managedFields from Kubernetes objects as they enter informer caches.

Traefik does not read managedFields, and keeping them increases cached object size plus downstream copy and comparison cost for watched resources.

Assisted-by: Claude Opus 4.8

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Piotr Maksymiuk 2026-05-22 12:39:36 +02:00 committed by test
parent 8773d7ead4
commit 85be7af4a2
No known key found for this signature in database
7 changed files with 79 additions and 20 deletions

View file

@ -177,7 +177,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
for _, ns := range namespaces {
factoryCrd := traefikinformers.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, traefikinformers.WithNamespace(ns), traefikinformers.WithTweakListOptions(matchesLabelSelector))
factoryCrd := traefikinformers.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, traefikinformers.WithNamespace(ns), traefikinformers.WithTweakListOptions(matchesLabelSelector), traefikinformers.WithTransform(k8s.StripManagedFields))
_, err := factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -219,7 +219,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -233,7 +233,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -271,7 +271,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
if !c.disableClusterScopeInformer {
c.clusterScopeFactory = kinformers.NewSharedInformerFactory(c.csKube, resyncPeriod)
c.clusterScopeFactory = kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithTransform(k8s.StripManagedFields))
_, err := c.clusterScopeFactory.Core().V1().Nodes().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err

View file

@ -148,20 +148,20 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
options.LabelSelector = c.labelSelector
}
c.factoryNamespace = kinformers.NewSharedInformerFactory(c.csKube, resyncPeriod)
c.factoryNamespace = kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithTransform(k8s.StripManagedFields))
_, err := c.factoryNamespace.Core().V1().Namespaces().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
c.factoryGatewayClass = gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithTweakListOptions(labelSelectorOptions))
c.factoryGatewayClass = gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithTweakListOptions(labelSelectorOptions), gateinformers.WithTransform(k8s.StripManagedFields))
_, err = c.factoryGatewayClass.Gateway().V1().GatewayClasses().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
for _, ns := range namespaces {
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -171,7 +171,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
factoryGateway := gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithNamespace(ns))
factoryGateway := gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithNamespace(ns), gateinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryGateway.Gateway().V1().Gateways().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -209,7 +209,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
}
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err

View file

@ -158,7 +158,7 @@ func (c *clientWrapper) WatchAll(ctx context.Context, namespace, namespaceSelect
}
for _, ns := range c.watchedNamespaces {
factoryIngress := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns))
factoryIngress := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err := factoryIngress.Networking().V1().Ingresses().Informer().AddEventHandler(eventHandler)
if err != nil {
@ -167,7 +167,7 @@ func (c *clientWrapper) WatchAll(ctx context.Context, namespace, namespaceSelect
c.factoriesIngress[ns] = factoryIngress
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -178,14 +178,14 @@ func (c *clientWrapper) WatchAll(ctx context.Context, namespace, namespaceSelect
}
c.factoriesKube[ns] = factoryKube
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
c.factoriesSecret[ns] = factorySecret
factoryConfigMap := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factoryConfigMap := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryConfigMap.Core().V1().ConfigMaps().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -226,7 +226,7 @@ func (c *clientWrapper) WatchAll(ctx context.Context, namespace, namespaceSelect
}
}
c.clusterScopeFactory = kinformers.NewSharedInformerFactory(c.clientset, resyncPeriod)
c.clusterScopeFactory = kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithTransform(k8s.StripManagedFields))
if !c.ignoreIngressClasses {
_, err = c.clusterScopeFactory.Networking().V1().IngressClasses().Informer().AddEventHandler(eventHandler)

View file

@ -158,7 +158,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
for _, ns := range namespaces {
factoryIngress := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(matchesLabelSelector))
factoryIngress := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(matchesLabelSelector), kinformers.WithTransform(k8s.StripManagedFields))
_, err := factoryIngress.Networking().V1().Ingresses().Informer().AddEventHandler(eventHandler)
if err != nil {
@ -167,7 +167,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
c.factoriesIngress[ns] = factoryIngress
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -178,7 +178,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
c.factoriesKube[ns] = factoryKube
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@ -213,7 +213,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
if !c.disableIngressClassInformer || !c.disableClusterScopeInformer {
c.clusterScopeFactory = kinformers.NewSharedInformerFactory(c.clientset, resyncPeriod)
c.clusterScopeFactory = kinformers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod, kinformers.WithTransform(k8s.StripManagedFields))
_, err := c.clusterScopeFactory.Networking().V1().IngressClasses().Informer().AddEventHandler(eventHandler)
if err != nil {

View file

@ -0,0 +1,16 @@
package k8s
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// StripManagedFields drops metadata.managedFields as objects enter the informer cache.
// Traefik never reads them, and they inflate the cache footprint and the cost of copying
// and comparing cached objects, which matters under heavy resource churn.
func StripManagedFields(obj any) (any, error) {
object, ok := obj.(metav1.Object)
if !ok {
return obj, nil
}
object.SetManagedFields(nil)
return obj, nil
}

View file

@ -0,0 +1,43 @@
package k8s
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestStripManagedFields(t *testing.T) {
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "whoami",
ManagedFields: []metav1.ManagedFieldsEntry{
{
Manager: "kubectl",
Operation: metav1.ManagedFieldsOperationApply,
APIVersion: "v1",
Time: &metav1.Time{Time: time.Now()},
},
},
},
}
got, err := StripManagedFields(service)
require.NoError(t, err)
assert.Same(t, service, got)
assert.Nil(t, service.ManagedFields)
assert.Equal(t, "whoami", service.Name)
}
func TestStripManagedFieldsIgnoresNonKubernetesObjects(t *testing.T) {
obj := struct{ Name string }{Name: "whoami"}
got, err := StripManagedFields(obj)
require.NoError(t, err)
assert.Equal(t, obj, got)
}

View file

@ -122,13 +122,13 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
for _, ns := range namespaces {
factory := knativenetworkinginformers.NewSharedInformerFactoryWithOptions(c.csKnativeNetworking, resyncPeriod, knativenetworkinginformers.WithNamespace(ns), knativenetworkinginformers.WithTweakListOptions(func(opts *metav1.ListOptions) {
opts.LabelSelector = c.labelSelector
}))
}), knativenetworkinginformers.WithTransform(k8s.StripManagedFields))
_, err := factory.Networking().V1alpha1().Ingresses().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err