Skip to content

filter_kubernetes: bound metadata fetch I/O and negative-cache failed lookups - #12169

Open
PovilasV1 wants to merge 1 commit into
fluent:masterfrom
PovilasV1:fix/filter_kubernetes-metadata-io-timeout
Open

filter_kubernetes: bound metadata fetch I/O and negative-cache failed lookups#12169
PovilasV1 wants to merge 1 commit into
fluent:masterfrom
PovilasV1:fix/filter_kubernetes-metadata-io-timeout

Conversation

@PovilasV1

@PovilasV1 PovilasV1 commented Jul 28, 2026

Copy link
Copy Markdown

What / why

filter_kubernetes resolves pod metadata with a synchronous request (async is explicitly disabled on the upstream) that has no read timeout, on the pipeline/event-loop thread. If the API server / kubelet connection establishes and then stalls, recv() blocks that thread indefinitely and in_tail (same event loop) stops collecting — the tail input flatlines while the pod stays healthy (ingestion_paused=0, storage not overlimit). Failed lookups are not cached, so every subsequent record for an unseen pod re-issues the blocking request.

Full root-cause analysis, a deterministic reproduction (minikube + Toxiproxy), and a /proc capture of the pipeline thread parked in read() on the metadata socket are in #12168.

Change

Two operator-tunable safeguards (defaults on; 0 = legacy behaviour):

  • kube_meta_io_timeout (default 30s) — sets net.io_timeout on the API and kubelet upstreams so a stalled read errors out instead of blocking the pipeline forever.
  • kube_meta_negative_cache_ttl (default 60s) — short-TTL negative cache so a failed lookup isn't re-issued (and re-blocked) on every subsequent line for the same pod.

This bounds the synchronous fetch; it does not make it async. A fuller fix would be async metadata resolution / a background pod cache — happy to follow up if maintainers prefer that direction.

Testing

Rebuilt v5.0.9 with this change and re-ran the reproduction from #12168 (kube_meta_io_timeout 10):

  • Before: 24 continuous new-pod appends → records_total{tail.0} frozen forever; pipeline thread stuck in read() on the metadata socket.
  • After: each uncached lookup stalls ≤ the timeout, then errors and is negative-cached; records resume, and repeat lines for a known-bad pod are served from the negative cache instantly.

Fixes #12168

Summary by CodeRabbit

  • New Features

    • Added configurable timeouts for Kubernetes API server and kubelet metadata requests.
    • Added negative caching for failed pod metadata lookups to avoid repeated immediate requests.
    • Added configuration options to set the metadata timeout and negative-cache duration, or disable either feature.
  • Bug Fixes

    • Improved cleanup of metadata cache resources during filter shutdown.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 62aed8c6-a9a7-4d60-958e-af501e7405a4

📥 Commits

Reviewing files that changed from the base of the PR and between 0c06128 and 808e5ee.

📒 Files selected for processing (4)
  • plugins/filter_kubernetes/kube_conf.c
  • plugins/filter_kubernetes/kube_conf.h
  • plugins/filter_kubernetes/kube_meta.c
  • plugins/filter_kubernetes/kubernetes.c
🚧 Files skipped from review as they are similar to previous changes (4)
  • plugins/filter_kubernetes/kube_conf.c
  • plugins/filter_kubernetes/kubernetes.c
  • plugins/filter_kubernetes/kube_conf.h
  • plugins/filter_kubernetes/kube_meta.c

📝 Walkthrough

Walkthrough

The Kubernetes filter adds configurable metadata I/O timeouts and a TTL-based negative cache for failed pod metadata lookups, including configuration, context storage, initialization, cleanup, and lookup handling.

Changes

Kubernetes metadata safeguards

Layer / File(s) Summary
Configuration and negative-cache lifecycle
plugins/filter_kubernetes/kube_conf.h, plugins/filter_kubernetes/kubernetes.c, plugins/filter_kubernetes/kube_conf.c
Adds timeout and negative-cache settings, stores them in flb_kube, and creates or destroys the TTL-backed negative cache when enabled.
Bounded metadata requests
plugins/filter_kubernetes/kube_meta.c
Applies the configured I/O timeout to kubelet and Kubernetes API upstreams when the value is greater than zero.
Negative lookup suppression
plugins/filter_kubernetes/kube_meta.c
Skips recently failed network metadata lookups and records fresh failures in the negative cache, excluding tag-based metadata lookups.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: edsiper

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: bounded metadata fetch I/O and negative caching.
Linked Issues check ✅ Passed The PR implements the requested I/O timeout and short-lived negative cache for synchronous Kubernetes metadata lookups in #12168.
Out of Scope Changes check ✅ Passed The changes stay within filter_kubernetes timeout, cache, and lookup behavior; no unrelated functionality is introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
plugins/filter_kubernetes/kube_meta.c (1)

2437-2462: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the negative-cache locals to the top of the function and add a debug log on suppression.

neg_buf / neg_size are declared mid-block; the rest of this file (and the project C style) declares locals at function scope. Also, silently returning un-enriched records makes the negative cache invisible in logs — a flb_plg_debug on the suppression path makes triage of "records missing kube metadata" much easier.

♻️ Proposed refactor
 static inline int lookup_pod_meta(struct flb_kube *ctx,
                                   const char **out_buf, size_t *out_size,
                                   struct flb_kube_meta *meta,
                                   struct flb_kube_props *props)
 {
     int id;
     int ret;
     const char *hash_meta_buf;
     char *tmp_hash_meta_buf;
+    const char *neg_buf;
+    size_t neg_size;
     size_t off = 0;
     size_t hash_meta_size;
     msgpack_unpacked result;
@@
         if (ctx->neg_hash_table) {
-            const char *neg_buf;
-            size_t neg_size;
             if (flb_hash_table_get(ctx->neg_hash_table,
                                    meta->cache_key, meta->cache_key_len,
                                    (void *) &neg_buf, &neg_size) != -1) {
+                flb_plg_debug(ctx->ins, "negative cache hit for '%s', "
+                              "skipping metadata request", meta->cache_key);
                 *out_buf = NULL;
                 *out_size = 0;
                 return 0;
             }
         }

As per coding guidelines: "Declare variables at the start of functions rather than mid-block."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/filter_kubernetes/kube_meta.c` around lines 2437 - 2462, In the
function containing the negative-cache check, move neg_buf and neg_size from the
if (ctx->neg_hash_table) block to the function-scope declarations at the top. On
the suppression path where flb_hash_table_get finds meta->cache_key, add a
flb_plg_debug log identifying the negative-cache skip before returning the empty
result.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/filter_kubernetes/kube_meta.c`:
- Around line 2455-2462: Update the error handling around
get_and_merge_pod_meta() so neg_hash_table_add() runs only for failures from
network-based pod/API or kubelet lookups. Exclude merge_meta_from_tag()
failures, including the use_tag_for_meta path, from negative caching while
preserving the existing return/error handling.

In `@plugins/filter_kubernetes/kube_meta.c.orig`:
- Around line 1-52: Remove the obsolete tracked kube_meta.c.orig file from the
filter_kubernetes plugin, leaving the active kube_meta.c implementation
unchanged. Optionally add directory-scoped ignore rules for *.orig and *.rej to
prevent regenerated patch artifacts from being reintroduced.

---

Nitpick comments:
In `@plugins/filter_kubernetes/kube_meta.c`:
- Around line 2437-2462: In the function containing the negative-cache check,
move neg_buf and neg_size from the if (ctx->neg_hash_table) block to the
function-scope declarations at the top. On the suppression path where
flb_hash_table_get finds meta->cache_key, add a flb_plg_debug log identifying
the negative-cache skip before returning the empty result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 67660424-dcac-409f-8032-4beb616b06d7

📥 Commits

Reviewing files that changed from the base of the PR and between cb7256c and 0c06128.

📒 Files selected for processing (5)
  • plugins/filter_kubernetes/kube_conf.c
  • plugins/filter_kubernetes/kube_conf.h
  • plugins/filter_kubernetes/kube_meta.c
  • plugins/filter_kubernetes/kube_meta.c.orig
  • plugins/filter_kubernetes/kubernetes.c

Comment thread plugins/filter_kubernetes/kube_meta.c
Comment thread plugins/filter_kubernetes/kube_meta.c.orig Outdated
The pod metadata fetch is synchronous with async disabled and no read
timeout, on the pipeline/event-loop thread. A Kubernetes API server / kubelet
connection that establishes then stalls blocks recv() indefinitely, so in_tail
(same event loop) stops collecting and the tail input flatlines while the pod
stays healthy. Failed lookups are not cached, so every record for an unseen pod
re-issues the blocking request.

Add two safeguards (defaults on, 0 = legacy):
- kube_meta_io_timeout (30s): read timeout on the API/kubelet upstreams so a
  stalled read errors instead of wedging the pipeline forever.
- kube_meta_negative_cache_ttl (60s): remember a failed lookup briefly so
  records for that pod pass through instead of re-blocking on every line.

Fixes fluent#12168

Signed-off-by: Povilas Vaitkus <povilas.vaitkus@hostinger.com>
@PovilasV1
PovilasV1 force-pushed the fix/filter_kubernetes-metadata-io-timeout branch from 0c06128 to 808e5ee Compare July 28, 2026 16:52
@PovilasV1

Copy link
Copy Markdown
Author

Pushed `808e5ee` addressing the automated review:

  • Removed an accidentally-committed `kube_meta.c.orig` backup file.
  • Scoped the negative cache to network lookup failures only — added `&& !ctx->use_tag_for_meta` so `merge_meta_from_tag()` failures (which involve no request) are not negatively cached.
  • Added `flb_plg_debug` on the negative-cache suppression and store paths so un-enriched records are traceable.

Recompiled locally (v5.0.9 + this change builds clean) and re-checked the reproduction from #12168: behaviour is unchanged for the network path (the new guard only affects the `use_tag_for_meta` path; the added lines are debug-logging only) — the permanent wedge still becomes a bounded stall that recovers.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

filter_kubernetes: metadata fetch has no read timeout and can wedge the pipeline (in_tail flatlines) when the API/kubelet connection stalls

1 participant