feat(prometheus_scrape): support auto discovery in k8s - #26013
feat(prometheus_scrape): support auto discovery in k8s#26013LeeTeng2001 wants to merge 4 commits into
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
d1f64e3 to
7db50fb
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1f64e3381
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| #[cfg(feature = "kubernetes")] | ||
| pub(crate) mod kubernetes_sd; |
There was a problem hiding this comment.
Gate Kubernetes SD on prometheus_scrape
When a custom build enables another Prometheus source together with Kubernetes but leaves sources-prometheus-scrape off (for example --no-default-features --features sources-prometheus-remote-write,sources-kubernetes_logs), this #[cfg(feature = "kubernetes")] still pulls in kubernetes_sd, which imports scrape-only items such as PrometheusParseError gated behind sources-prometheus-scrape. That feature set stops compiling even though it does not configure prometheus_scrape; please require both features for this module.
Useful? React with 👍 / 👎.
| const fn default_delay_deletion_ms() -> u64 { | ||
| 60_000 |
There was a problem hiding this comment.
Stop retaining deleted pods as scrape targets
With the default delay_deletion_ms, a Pod delete event stays in the reflector store for 60 seconds, and collect_targets uses that store on every scrape tick. Because each scrape already clones its Targets before issuing requests, this retention is not needed for in-flight scrapes; instead, deleted pods continue to be scraped for several intervals and can produce errors or, after IP reuse, metrics labeled with the deleted pod's metadata.
Useful? React with 👍 / 👎.
| ..Default::default() | ||
| }; | ||
|
|
||
| let api = Api::<Pod>::all(client.clone()); |
There was a problem hiding this comment.
Use namespaced watches for namespace-restricted discovery
When namespaces is set, this still creates an all-namespaces Pods API and relies on field/client-side filters. A Vector service account granted only a Role in the requested namespace will be forbidden from the cluster-scope watch, so namespace-restricted configs fail unless they also have cluster-wide pod list/watch permissions.
Useful? React with 👍 / 👎.
| TargetConfig::Static { urls } => { | ||
| for s_url in urls { | ||
| let uri = s_url.parse::<Uri>().context(sources::UriParseSnafu)?; | ||
| static_urls.push(build_url(&uri, &self.query)); |
There was a problem hiding this comment.
Avoid appending static target query parameters twice
When targets contains both a static group and a kubernetes group and the source-level query option is set, these static URLs are stored after build_url already appends the query; then the Kubernetes path converts them to Targets and scrape_target calls build_url(&target.uri, &cfg.query) again. Static targets in mixed configs therefore receive duplicate parameters, unlike static-only configs.
Useful? React with 👍 / 👎.
| }; | ||
| Uri::builder() | ||
| .scheme(scheme.as_str()) | ||
| .authority(format!("{host}:{port}")) |
There was a problem hiding this comment.
Bracket IPv6 pod IPs before building scrape URIs
In IPv6-only or dual-stack clusters where pod.status.pod_ip is an IPv6 literal, formatting the authority as {host}:{port} produces an invalid URI such as fd00::1:9100. Those annotated pods are skipped with URI build errors instead of being scraped; wrap IPv6 hosts in brackets before setting the authority.
Useful? React with 👍 / 👎.
| .buffer_unordered(usize::MAX) | ||
| .flat_map(stream::iter); | ||
|
|
||
| if out.send_event_stream(&mut events_stream).await.is_err() { |
There was a problem hiding this comment.
Preserve scrape cadence for slow Kubernetes batches
When any discovered target takes longer than scrape_interval_secs, this awaits the whole finite per-tick scrape stream before polling the next interval. Unlike the existing static path, Kubernetes discovery mode skips overlapping scrapes and lowers the sample frequency for every target in the group whenever one scrape runs long; schedule ticks independently of batch completion.
Useful? React with 👍 / 👎.
| }; | ||
|
|
||
| let (parts, body) = response.into_parts(); | ||
| let body: Bytes = match http_body::Body::collect(body).await { |
There was a problem hiding this comment.
Apply the scrape timeout while reading response bodies
When an exporter sends response headers and then stalls the body, the configured timeout has already ended because it only wraps client.send; Body::collect can await forever. In this Kubernetes path the per-tick stream must finish before the loop continues, so one bad pod can freeze all future scrapes for the source.
Useful? React with 👍 / 👎.
Summary
Support discovery of kubernetes pods via annotations
Vector configuration
Since I'm testing this own own my own cluster, I used official helm chart with following values
How did you test this PR?
Run a k3s node, deploy sample applications with pod annotations, deploy vector with above helm value configuration
Is this a breaking change?
Does this PR include user facing changes?
no-changeloglabel to this PR.References
Notes
@vectordotdev/vectorto reach out to us regarding this PR.pre-pushhook, please see this template.make fmtmake check-clippy(if there are failures it's possible some of them can be fixed withmake clippy-fix)make testgit merge origin masterandgit push.Cargo.lock), pleaserun
make build-licensesto regenerate the license inventory and commit the changes (if any). More details on the dd-rust-license-tool.