Skip to content

Support Kubernetes v1.36 ShardSelector in informer injection framework #3383

Open

Description

@vdemeester

Summary

Kubernetes v1.36 introduced Server-Side Sharded List and Watch as an alpha feature (KEP-5866). This adds a ShardSelector field to metav1.ListOptions that allows informers to request only objects within a specific hash range, so the API server filters watch events at the source.

The knative.dev/pkg injection framework currently has no support for injecting shardSelector into informer ListOptions. This blocks downstream projects (e.g., Tekton Pipelines) from adopting sharded watches while staying within the injection framework.

Background

The injection framework already supports filtering via WithTweakListOptions — the filtered informer factory uses this to inject label selectors. The ShardSelector would follow a similar pattern but targets the ListOptions.ShardSelector field instead of LabelSelector.

The ShardSelector field accepts CEL expressions like:

shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')

Proposed Changes

  1. New context decorator — similar to filteredinformerfactory.WithSelectors, add a mechanism to inject a shardSelector string into all informer ListOptions. For example:

    ctx = sharding.WithShardSelector(ctx, "shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')")
  2. Plumb through informer factories — both the standard and filtered informer factories (and their generated CRD-specific counterparts from injection-gen) should respect the shard selector from context, appending it via WithTweakListOptions.

  3. Coordinate with bucket-based leader election — when shard selectors are active, the informer cache only contains objects in the shard range. The bucket-based leader election partitioning must align with the shard boundaries, or a replica could be elected leader for keys it never receives via its watch. This likely means:

    • When sharding is enabled, bucket count should equal the number of shards
    • Or shard assignment should derive from the bucket/lease ownership
  4. Graceful fallback — when the API server doesn't support the feature (pre-v1.36 or feature gate disabled), the controller should fall back to full watches transparently.

Use Case

Tekton Pipelines controllers processing thousands of concurrent PipelineRuns/TaskRuns. With N replicas today, each replica watches all objects and only reconciles its bucket — CPU, memory, and network scale with replica count rather than shard size. With sharded watches, each replica only receives 1/N of events.

Upstream issue: tektoncd/pipeline#10610

Kubernetes References

Activity

  1. shashankxrm commented on Sep 7, 2026

    @shashankxrm

    I've been looking into this as a prerequisite for Tekton's server-side sharded watch work in tektoncd/pipeline#10610, and traced the informer injection path in knative.dev/pkg.

    I think the informer plumbing can be implemented independently of the Tekton-specific sharding policy.

    The approach I'm considering is:

    1. Add a context decorator such as sharding.WithShardSelector(ctx, selector) to carry the selector through injection.
    2. Update the injection-gen factory templates so standard and filtered informer factories apply the selector through WithTweakListOptions.
    3. For filtered factories, compose the shard selector with the existing LabelSelector in the same tweak callback, since SharedInformerFactory only keeps a single tweakListOptions callback.
    4. Regenerate the generated informer factories.
    5. Add unit tests covering the context value and generated ListOptions behavior.
    6. Bump the Kubernetes dependencies to a version containing metav1.ListOptions.ShardSelector (currently the repo is on v0.35.8, where the field is not present).

    I'd prefer to keep the first change focused on the generic informer plumbing and not include leader-election/bucket changes in the same PR. The latter seems to require a separate design decision because the existing bucket ownership is based on namespace/name, while Kubernetes server-side sharding uses the UID hash range.

    There is also a Tekton-specific question around cross-resource informers (PipelineRun → TaskRun), but I believe that should be handled by Tekton's sharding policy rather than by the generic injection layer.

    Before I start implementing this, I'd appreciate maintainer feedback on whether this scope makes sense for #3383, particularly whether the leader-election alignment should be part of this change or handled separately.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions