Skip to content

Navigation Menu

Sign in
Sign up

Filter headless Services from the informer cache via spec.clusterIP field selector #258

Open
Assignees
Labels

Description

What

Add a server-side field selector to the Service informer so headless Services are never listed, watched, or cached:

&corev1.Service{}: {
 Transform: k8s.StripDownServiceTransformFunc,
 Field: fields.OneTermNotEqualSelector("spec.clusterIP", corev1.ClusterIPNone),
},

This is the same pattern the controller already uses for Pods (podCacheFieldSelector in pkg/config/runtime_config.go), and the same optimization kubelet adopted in Kubernetes 1.31 to stop watching headless Services (kubernetes/kubernetes#122541, motivated by kubernetes/kubernetes#122394).

Why

Every consumer of the Service cache already ignores headless Services, so caching them is pure overhead:

  • pkg/resolvers/endpoints.gogetMatchingServiceClusterIPs skips headless Services (no ClusterIP to resolve).
  • pkg/resolvers/policies_for_service.go — NetworkPolicy and ApplicationNetworkPolicy service-reference resolution early-returns on headless Services.
  • internal/eventhandlers/service.go — headless Service create/update/delete events still fire the handler, and GetReferredClusterPoliciesForService enqueues all ClusterNetworkPolicies for reconcile even though headless Services can never contribute endpoints.

Filtering server-side eliminates:

  1. Cache memory for headless Services (can be a large fraction of total Services in StatefulSet-heavy clusters).
  2. List/watch bandwidth on the apiserver connection.
  3. Iteration overhead in getMatchingServiceClusterIPs, which lists Services per egress-peer per namespace.
  4. Spurious full-CNP reconciles triggered by headless Service churn.

spec.clusterIP is immutable, so Services do not transition in/out of the filtered set. For the ExternalName↔ClusterIP type-change edge case, the apiserver synthesizes Added/Deleted watch events, which the existing handlers already handle.

Constraint

The spec.clusterIP field selector for Services requires Kubernetes 1.31+. On older apiservers the list/watch fails with field label not supported and the informer never syncs. The README currently states a 1.25+ prerequisite, so this needs one of:

  • a minimum-version bump to 1.31+, or
  • server-version discovery at startup with conditional application of the selector (kubelet-style fallback).

Note: existing IsServiceHeadless checks should remain regardless — they cover the unfiltered fallback path and ExternalName Services (clusterIP == ""), which the != "None" selector does not exclude.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    AltStyle によって変換されたページ (->オリジナル) /