Skip to content

Agent configuration ​

Both agents are configured through Helm values, which the chart renders into container environment variables. Every setting below can also be supplied as an environment variable directly if you run the container outside Helm.

Precedence: an explicit Helm value wins over the chart default.

kubespend-agent (metrics) ​

Helm valueEnvironment variableDefaultPurpose
clusterIdCLUSTER_IDauto-detectedlogical cluster name shown in the console
apiKey / existingSecretAPI_KEY— (required)ingest credential
serverAddrSERVER_ADDRingest.kubespend.io:443ingest endpoint; override when self-hosting
ingestInsecureINGEST_INSECUREfalsedial the ingest endpoint without TLS; local plaintext stacks only, since the API key is then sent in cleartext
scrapeIntervalSCRAPE_INTERVAL30sscrape and push cadence; must be greater than zero
namespaceNAMESPACEall namespacesrestrict collection to a single namespace
resources—50m / 64Mi requestsrequests and limits

Cluster ID auto-detection prefers a friendly node label (for example eksctl's alpha.eksctl.io/cluster-name), then falls back to a stable identifier derived from the kube-system namespace UID. Set it explicitly if you want a readable name — a UID works but reads badly in the console. You can also rename a cluster in the console after it registers.

Lowering scrapeInterval increases both stored volume and cost-query precision. The retention figures in Data retention assume the 30s default.

Restricting to one namespace means cluster-level cost is incomplete by design, and coverage will reflect that. See Coverage and confidence.

kubespend-ebpf-agent (network) ​

Helm valueEnvironment variableDefaultPurpose
modeRELAY_MODErelayrelay (via the metrics agent) or direct
clusterIdCLUSTER_IDauto-detectedmust match the metrics agent
apiKey / existingSecretAPI_KEY—required in direct mode only
vethRegexPOD_VETH_REGEX^(veth|lxc|cali|eni)pod interfaces; direction is inverted
nodeRegexNODE_IFACE_REGEX^(ens|eth|en[posx])node uplinks; "" to skip
ifaceWatchIntervalIFACE_WATCH_INTERVAL5show often to rescan for new interfaces
windowFLOW_WINDOW30saggregation and upload window
flowDetailFLOW_DETAILconversationconversation folds client ports into a connection count; connection keeps one record per 5-tuple
enableJitInitContainer—falsesets net.core.bpf_jit_enable=1 on the node; only needed where it reads 0
securityContext.privileged—falseprefer the default; capabilities suffice on kernel 6.6+
securityContext.capabilities.add—[BPF, PERFMON, NET_ADMIN]add SYS_RESOURCE below 5.11, SYS_ADMIN below 5.8

In the default relay mode the DaemonSet holds no API key — it authenticates to the in-cluster metrics agent with a projected ServiceAccount token, and the org key stays in a single Secret in one namespace. That is why rotating your key does not require touching every node.

Keep the two interface patterns disjoint

vethRegex and nodeRegex must not overlap. If they do, every pod byte is counted twice — once on the pod's veth and again on the node uplink. The defaults are disjoint; verify any override against ip link output on a real node.

Passing the API key ​

Prefer a pre-created Secret over an inline value, especially under GitOps:

bash
kubectl -n kubespend create secret generic kubespend-creds \
  --from-literal=api-key="$KUBESPEND_API_KEY"

helm install kubespend-agent oci://public.ecr.aws/kubespend.io/charts/kubespend-agent \
  --namespace kubespend --create-namespace \
  --set existingSecret=kubespend-creds \
  --set existingSecretKey=api-key

--set apiKey=... writes the key into Helm release metadata stored in the cluster, where anyone with read access to the release can recover it. existingSecret avoids that.

Verifying a change ​

bash
kubectl -n kubespend rollout status deploy/kubespend-agent
kubectl -n kubespend logs -l app.kubernetes.io/name=kubespend-agent --tail=50

The agent logs a periodic summary rather than a line per scrape, so a healthy agent is quiet. Failures are always logged at warn or error regardless of level.

See also ​

Every figure in KubeSpend traces to a real cloud price. Where we cannot measure something, we say so.