Make pod informer transform idempotent so WatchList streaming sync does not fall back to full LIST - #4881
Conversation
…nc from falling back to full LIST With client-go >= 0.35 the WatchListClient feature is on by default, so the pod informer attempts a streaming initial sync (KEP-3157) on every start. During the stream the reflector transforms objects in its temporary store, and the destination FIFO applies the transform again on Replace. podInfoConverter rejected its own output (*PodInfo), which aborted the streaming sync and made the reflector fall back to a conventional LIST that decodes every pod in the cluster into memory at once. Return an existing *PodInfo unchanged so the streaming sync completes. On a 20k-pod test cluster this reduced peak heap during initial sync from 483MiB to 36MiB.
|
Hi @yash97. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: yash97 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Issue
N/A. Happy to file one if maintainers prefer tracking this as an issue first.
Description
The pod informer transform (
podInfoConverter) only accepts*corev1.Podand returns an error for anything else. That breaks streaming initial sync.Since client-go v0.35 the
WatchListClientfeature is enabled by default, and this repo pins v0.36.2, so the controller attempts a WatchList streaming sync (KEP-3157) for the pod informer on every start. During the stream, the reflector applies the informer transform to objects in its temporary store, then the destination FIFO applies the same transform again onReplace. The second application hands the converter its own output, a*PodInfo. The converter returns "expect pod object", the streaming sync aborts, and the reflector silently falls back to a conventional LIST.The fallback is expensive: it decodes every pod in the cluster into memory at once before the transform can slim anything down. On small clusters nobody notices. On a cluster with roughly 380k pods (kwok scale testing), the controller could not finish initial sync inside a 20Gi memory limit and crash looped on OOM, logging
problem wait for podInfo repo syncon every attempt.The fix is a two-line early return: when the transform receives a
*PodInfo, hand it back unchanged. With an idempotent transform the streaming sync completes and peak memory during sync stays close to one decoded pod at a time, instead of the whole cluster.Testing was done in three layers:
*PodInfoinstead of an error.WatchList=truefeature gate), with a recordinghttp.RoundTripperon the pods endpoint. Before the fix the request log shows the streaming attempt followed by the fallback:HeapInuseevery 20ms through initial sync:The envtest harness for layers 2 and 3 is not part of this PR to keep it focused, since it needs kubebuilder assets in CI. I can contribute it in a follow-up if there is interest.
On API servers without WatchList support, client-go falls back to a plain LIST exactly as it does today, so behavior there is unchanged.
Checklist
README.md, or thedocsdirectory)