Merge pull request #130859 from hakuna-matatah/optimize-ds

Optimize DS Controller Performance: Reduce Work Duration Time & Minimize Cache Locking.
This commit is contained in:
Kubernetes Prow Robot 2025-03-20 14:16:39 -07:00 committed by GitHub
commit dca334e350
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 59 additions and 5 deletions

View File

@ -86,6 +86,13 @@ const (
// PodNodeNameKeyIndex is the name of the index used by PodInformer to index pods by their node name.
PodNodeNameKeyIndex = "spec.nodeName"
// OrphanPodIndexKey is used to index all Orphan pods to this key
OrphanPodIndexKey = "_ORPHAN_POD"
// podControllerUIDIndex is the name for the Pod store's index function,
// which is to index by pods's controllerUID.
PodControllerUIDIndex = "podControllerUID"
)
var UpdateTaintBackoff = wait.Backoff{
@ -1076,6 +1083,30 @@ func AddPodNodeNameIndexer(podInformer cache.SharedIndexInformer) error {
})
}
// AddPodControllerUIDIndexer adds an indexer for Pod's controllerRef.UID to the given PodInformer.
// This indexer is used to efficiently look up pods by their ControllerRef.UID
func AddPodControllerUIDIndexer(podInformer cache.SharedIndexInformer) error {
if _, exists := podInformer.GetIndexer().GetIndexers()[PodControllerUIDIndex]; exists {
// indexer already exists, do nothing
return nil
}
return podInformer.AddIndexers(cache.Indexers{
PodControllerUIDIndex: func(obj interface{}) ([]string, error) {
pod, ok := obj.(*v1.Pod)
if !ok {
return nil, nil
}
// Get the ControllerRef of the Pod to check if it's managed by a controller
if ref := metav1.GetControllerOf(pod); ref != nil {
return []string{string(ref.UID)}, nil
}
// If the Pod has no controller (i.e., it's orphaned), index it with the OrphanPodIndexKey
// This helps identify orphan pods for reconciliation and adoption by controllers
return []string{OrphanPodIndexKey}, nil
},
})
}
// PodKey returns a key unique to the given pod within a cluster.
// It's used so we consistently use the same key scheme in this module.
// It does exactly what cache.MetaNamespaceKeyFunc would have done

View File

@ -113,7 +113,7 @@ type DaemonSetsController struct {
historyStoreSynced cache.InformerSynced
// podLister get list/get pods from the shared informers's store
podLister corelisters.PodLister
// podIndexer allows looking up pods by node name.
// podIndexer allows looking up pods by node name or by ControllerRef UID
podIndexer cache.Indexer
// podStoreSynced returns true if the pod store has been synced at least once.
// Added as a member to the struct to allow injection for testing.
@ -217,6 +217,7 @@ func NewDaemonSetsController(
dsc.podLister = podInformer.Lister()
dsc.podStoreSynced = podInformer.Informer().HasSynced
controller.AddPodNodeNameIndexer(podInformer.Informer())
controller.AddPodControllerUIDIndexer(podInformer.Informer())
dsc.podIndexer = podInformer.Informer().GetIndexer()
nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
@ -688,6 +689,30 @@ func (dsc *DaemonSetsController) updateNode(logger klog.Logger, old, cur interfa
dsc.nodeUpdateQueue.Add(curNode.Name)
}
// getPodsFromCache returns the Pods that a given DS should manage.
func (dsc *DaemonSetsController) getDaemonPodsFromCache(ds *apps.DaemonSet) ([]*v1.Pod, error) {
// Iterate over two keys:
// The UID of the Daemonset, which identifies Pods that are controlled by the Daemonset.
// The OrphanPodIndexKey, which helps identify orphaned Pods that are not currently managed by any controller,
// but may be adopted later on if they have matching labels with the Daemonset.
podsForDS := []*v1.Pod{}
for _, key := range []string{string(ds.UID), controller.OrphanPodIndexKey} {
podObjs, err := dsc.podIndexer.ByIndex(controller.PodControllerUIDIndex, key)
if err != nil {
return nil, err
}
for _, obj := range podObjs {
pod, ok := obj.(*v1.Pod)
if !ok {
utilruntime.HandleError(fmt.Errorf("unexpected object type in pod indexer: %v", obj))
continue
}
podsForDS = append(podsForDS, pod)
}
}
return podsForDS, nil
}
// getDaemonPods returns daemon pods owned by the given ds.
// This also reconciles ControllerRef by adopting/orphaning.
// Note that returned Pods are pointers to objects in the cache.
@ -697,10 +722,8 @@ func (dsc *DaemonSetsController) getDaemonPods(ctx context.Context, ds *apps.Dae
if err != nil {
return nil, err
}
// List all pods to include those that don't match the selector anymore but
// have a ControllerRef pointing to this controller.
pods, err := dsc.podLister.Pods(ds.Namespace).List(labels.Everything())
// List all pods indexed to DS UID and Orphan pods
pods, err := dsc.getDaemonPodsFromCache(ds)
if err != nil {
return nil, err
}