K
Kubernetes metrics
Observability collectors availableCollect pod/node metrics from the Kubernetes metrics API during a run.
$ loadr plugin install k8s-metrics
# Overlay Kubernetes pod CPU/memory on the load timeline, driven by the
# `loadr-plugin-k8s-metrics` native SERVICE plugin.
#
# A service plugin has a start/stop lifecycle: loadr calls `start(config)` once
# before the run and `stop()` once after. On start this plugin resolves its
# bearer token + cluster CA from the mounted service account, builds a pure-Rust
# hyper + rustls HTTPS client (no kubectl, no client SDK, no C dep), then spawns
# a background poller that scrapes the Kubernetes metrics API on `interval_ms`:
#
# GET /apis/metrics.k8s.io/v1beta1/namespaces/<namespace>/pods?labelSelector=...
#
# Each matched pod's summed container CPU/memory becomes a system-metric series
# (`k8s_pod_cpu_cores`, `k8s_pod_mem_bytes`, `k8s_scrapes`) aligned to the run
# window. A slow or unreachable scrape is counted, never fatal — the affected
# series just shows a gap. The service binds a tiny local endpoint and start()
# returns its bound address, e.g.:
#
# → k8s-metrics collector at 127.0.0.1:41881
#
# For the in-cluster defaults to work, run the loadr controller inside the same
# cluster (e.g. a Job) with the projected service-account token mounted, and give
# its service account read access to `pods.metrics.k8s.io`. To collect from
# outside the cluster, set `api_url`, `token` and `ca_cert` (or `insecure: true`).
#
# Build + install the plugin, then run:
# cargo build -p loadr-plugin-k8s-metrics --release
# mkdir -p dist && cp plugins/loadr-plugin-k8s-metrics/plugin.toml dist/ \
# && cp target/release/libloadr_plugin_k8s_metrics.so dist/
# loadr plugin install dist
# loadr run examples/plugins/k8s-metrics.yaml
#
# Or point the plan's `plugins:` entry at the built artifact directly (below).
name: k8s-metrics
description: Overlay Kubernetes pod CPU/memory on the load timeline
plugins:
# Resolve `k8s-metrics` by name from the plugins dir (after
# `loadr plugin install`). To run straight from a build tree instead, set:
# path: target/release/libloadr_plugin_k8s_metrics.so
- name: k8s-metrics
config:
# Namespace to scrape pods from.
namespace: app
# Label selector narrowing which pods are collected. Empty = all pods in
# the namespace. Passed through as the metrics API `labelSelector`.
selector: app=api
# Poll period (ms). Each tick is one scrape of the metrics API. Match it to
# your snapshot interval; metrics-server samples on its own ~15s cadence.
interval_ms: 5000
# Kubernetes API server. Defaults to the in-cluster service address.
# api_url: https://kubernetes.default.svc
# Bearer token + cluster CA default to the mounted service account. To run
# off-cluster, supply them explicitly (never inline a token in a plan):
# token: ${env.K8S_TOKEN}
# ca_cert: /etc/loadr/cluster-ca.pem
# insecure: false # skip TLS verification (off-cluster only)
defaults:
http:
base_url: https://api.example.com
scenarios:
# A steady read flow against the target service; the collector overlays the
# backing pods' CPU/memory on the same x-axis, so a throughput plateau and a
# CPU ceiling line up on one chart.
load:
executor: constant-vus
vus: 25
duration: 10m
flow:
- request:
name: list
url: /api/items
checks: [ { type: status, equals: 200 } ]
- request:
name: detail
url: /api/items/1
checks: [ { type: status, equals: 200 } ]
thresholds:
http_req_duration: [ "p(95)<400" ]
# Gate the run on the target staying healthy, not just the client SLO:
"k8s_pod_cpu_cores{namespace:app}": [ "value<3.5" ]
A real run: install from the signed index, then watch the plugin work.
A runtime plugin, never in the binary
Installing pulls a per-platform driver from the signed index, verifies its SHA-256 and checks its ABI before it ever loads. Remove it any time with loadr plugin remove k8s-metrics.