Skip to content

kindnetd: WaitForCacheSync before reconcile loop to avoid 10s NodeReady lag - #4216

Open
k-simons wants to merge 5 commits into
kubernetes-sigs:mainfrom
k-simons:patch-1
Open

kindnetd: WaitForCacheSync before reconcile loop to avoid 10s NodeReady lag#4216
k-simons wants to merge 5 commits into
kubernetes-sigs:mainfrom
k-simons:patch-1

Conversation

@k-simons

@k-simons k-simons commented Jul 12, 2026

Copy link
Copy Markdown

Problem

On fresh kind clusters, node NodeReady=true flips ~10 seconds later than necessary.
During those 10 seconds, kubelet's runtime status stays at KubeletNotReady with reason
NetworkPluginNotReady even though CNI configuration and kindnet's control loop are ready
to run.

Root cause

images/kindnetd/cmd/kindnetd/main.go starts informers but never waits for their cache to
sync before entering the reconcile ticker loop:

informersFactory.Start(ctx.Done())
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()

for {
    nodes, err := nodeLister.List(labels.Everything())  // empty on 1st iteration
    ...
    reconcileNodes(nodes)  // no-op, nothing to reconcile
    select {
    case <-ticker.C:  // waits a full 10 seconds
    }
}

The informer's initial LIST typically completes within a few hundred milliseconds of
Start, but the first loop iteration runs synchronously right after Start returns —
before the LIST response has landed. nodeLister.List(...) returns an empty slice,
reconcileNodes finds nothing to do, and the loop blocks on the 10-second ticker before
trying again. The first meaningful reconcile — the one that writes
/etc/cni/net.d/10-kindnet.conflist and logs Handling node with IPs — is thus gated
behind the ticker rather than behind the (fast) cache-sync.

Fix

Wait for the node informer cache to sync before entering the reconcile loop.

 import (
     ...
     "k8s.io/client-go/informers"
     "k8s.io/client-go/kubernetes"
     "k8s.io/client-go/rest"
+    "k8s.io/client-go/tools/cache"
     "k8s.io/klog/v2"
 )
     // main control loop
     informersFactory.Start(ctx.Done())
+    // Wait for the node cache to populate before entering the reconcile
+    // loop. Without this, the first iteration lists an empty cache and
+    // blocks on the 10s ticker before doing any real work — delaying
+    // NodeReady by a full tick.
+    if !cache.WaitForCacheSync(ctx.Done(), nodeInformer.Informer().HasSynced) {
+        klog.Fatalf("failed to sync node informer cache")
+    }
     ticker := time.NewTicker(10 * time.Second)
     defer ticker.Stop()

Evidence

Kindnetd container logs on a fresh single-node kind cluster (v1.33.7, arm64). Same host,
same node image, same cluster — only the kindnetd binary differed between runs.

Before:

17:54:23.430  probe TCP address ...:6443
17:54:23.432  connected to apiserver
17:54:23.697  Starting controller: kube-network-policies
17:54:23.697  Waiting for informer caches to sync
17:54:23.927  Caches are synced
17:54:23.928  Synchronized state with the runtime
17:54:33.642  Handling node with IPs: map[172.19.0.2:{}]   <-- 10s later

After (patched binary):

20:13:12.921  connected to apiserver
20:13:13.112  Starting controller: kube-network-policies
20:13:13.112  Waiting for the policy engine to become ready...
20:13:13.413  Handling node with IPs: map[172.19.0.2:{}]   <-- 492ms after connect
20:13:13.616  Policy engine is ready

Reduction in kindnetd's own timeline in the observed environment: ~9.5 seconds. The
theoretical maximum savings on any bring-up is one full reconcile ticker period (10s).

Downstream impact (motivation)

Consumers of kind that fan out CNI-dependent workloads during cluster bring-up
(cert-manager, service meshes, trust-bundle mounts) frequently observe pods stuck in
ContainerCreating with FailedMount events, retrying against kubelet's
nestedpendingoperations exponential backoff (500ms → 1s → 2s → 4s → 8s → 16s → ...). The
10s NodeReady lag pushes these pods into the 8-16s backoff tier before the resources they
depend on become available; removing the lag lets those pods succeed on their first mount
attempt.

Risk

  • WaitForCacheSync returns false only on ctx cancellation.
  • klog.Fatalf for the sync-fail branch matches the idiom used across
    kubelet/controller-manager and flushes klog buffers before exiting; the existing panic on
    line 286 could be aligned separately if desired.
  • No change to steady-state behavior — the 10-second reconcile ticker is untouched. This
    only affects the first iteration after startup.
  • The pod, namespace, and network-policy informers are still started concurrently and
    continue to sync in the background. kube-network-policies already does its own
    WaitForCacheSync for what it needs. Happy to extend the sync-wait to all four informers
    if reviewers prefer uniformity.

Testing

  • Verified manually by rebuilding kindnetd, overlaying the binary onto
    docker.io/kindest/kindnetd:v20251212-v0.29.0-alpha-105-g20ccfc88, retagging inside the
    kind node's containerd, restarting the DaemonSet pod, and comparing pre-/post-patch log
    timestamps for Handling node with IPs (see logs above).
  • The change is 3 lines using a well-established client-go idiom (WaitForCacheSync
    following informersFactory.Start); regression risk is bounded to the first-iteration
    ordering.

This PR was drafted with AI assistance; code, logs, and testing are my own.

@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 12, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

@kubernetes-prow kubernetes-prow Bot added the cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. label Jul 12, 2026
@kubernetes-prow

Copy link
Copy Markdown
Contributor

Welcome @k-simons!

It looks like this is your first PR to kubernetes-sigs/kind 🎉. Please refer to our pull request process documentation to help your PR have a smooth ride to approval.

You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. Here is the bot commands documentation.

You can also check if kubernetes-sigs/kind has its own contribution guidelines.

You may want to refer to our testing guide if you run into trouble with your tests not passing.

If you are having difficulty getting your pull request seen, please follow the recommended escalation practices. Also, for tips and tricks in the contribution process you may want to read the Kubernetes contributor cheat sheet. We want to make sure your contribution gets all the attention it needs!

Thank you, and welcome to Kubernetes. 😃

@kubernetes-prow

Copy link
Copy Markdown
Contributor

Hi @k-simons. 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 /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions 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.

@kubernetes-prow kubernetes-prow Bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Jul 12, 2026
@kubernetes-prow
kubernetes-prow Bot requested review from aojea and stmcginnis July 12, 2026 20:14
@kubernetes-prow kubernetes-prow Bot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Jul 12, 2026
@kubernetes-prow kubernetes-prow Bot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. and removed cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Jul 12, 2026
@k-simons k-simons changed the title Update main.go kindnetd: WaitForCacheSync before reconcile loop to avoid 10s NodeReady lag Jul 12, 2026
@k-simons

Copy link
Copy Markdown
Author

/cc @aojea @BenTheElder

@kubernetes-prow
kubernetes-prow Bot requested a review from BenTheElder July 12, 2026 20:29
@kubernetes-prow kubernetes-prow Bot added size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jul 12, 2026
@stmcginnis

Copy link
Copy Markdown
Contributor

/ok-to-test

@kubernetes-prow kubernetes-prow Bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jul 13, 2026
@k-simons

Copy link
Copy Markdown
Author

@stmcginnis Thanks for the tag! Please let me know if there is any more information or details that you need

@stmcginnis

Copy link
Copy Markdown
Contributor

This does make sense to wait up front rather than getting into the potentially longer retry loop right away. Thanks for looking into this.

/lgtm

@kubernetes-prow kubernetes-prow Bot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jul 14, 2026
Comment thread images/kindnetd/cmd/kindnetd/main.go Outdated
@kubernetes-prow kubernetes-prow Bot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jul 15, 2026
@kubernetes-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: k-simons
Once this PR has been reviewed and has the lgtm label, please ask for approval from stmcginnis. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubernetes-prow kubernetes-prow Bot removed the size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. label Jul 15, 2026
@kubernetes-prow kubernetes-prow Bot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Jul 15, 2026
@k-simons

Copy link
Copy Markdown
Author

@stmcginnis I went ahead and added the timeout per the recommendation. Let me know if there are any other comments/changes you'd like to see!

@stmcginnis

Copy link
Copy Markdown
Contributor

@stmcginnis I went ahead and added the timeout per the recommendation. Let me know if there are any other comments/changes you'd like to see!

Thanks @k-simons, that looks good to me. @BenTheElder any concerns with this?

/lgtm

@kubernetes-prow kubernetes-prow Bot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jul 17, 2026
@k-simons

k-simons commented Aug 4, 2026

Copy link
Copy Markdown
Author

@stmcginnis / @aojea Anything I can do here? Or is this pr just in the review process?

@k-simons

Copy link
Copy Markdown
Author

@stmcginnis / @aojea Just wanted to check in here :)

Comment on lines +276 to +280
syncCtx, syncCancel := context.WithTimeout(ctx, 30*time.Second)
defer syncCancel()
if !cache.WaitForCacheSync(syncCtx.Done(), nodeInformer.Informer().HasSynced) {
klog.Fatalf("failed to sync node informer cache")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what erroring and crashing gives us here? It seems we should follow same convention as all controllers and wait forever or until the context is cancelled

Comment on lines +276 to +277
syncCtx, syncCancel := context.WithTimeout(ctx, 30*time.Second)
defer syncCancel()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just remove this context and pass ctx.Done() and we are good to go

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you able to make this update @k-simons?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On vacation atm but can land it when I get back; or if for some reason you'd like to add it feel free!

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

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/S Denotes a PR that changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants