Skip to content

Agent on Kubernetes

The agent ships as a Helm chart published as an OCI artifact. It deploys the collector plus all three co-located local stores — VictoriaMetrics (metrics), Loki (logs), and Tempo (traces) — each as its own workload, all enabled by default in central mode.

You need your tenant name and an agent key from the LeanSignal app (Agents → Add Agent).

Terminal window
helm upgrade --install leansignal-agent \
oci://ghcr.io/leansignal/charts/leansignal-agent \
--namespace leansignal --create-namespace \
--set leansignal.tenant="YOUR_TENANT" \
--set leansignal.agentKey.value="YOUR_KEY"

To keep the key out of your values, reference an existing Secret:

leansignal:
tenant: YOUR_TENANT
agentKey:
existingSecret: my-agent-secret
existingSecretKey: agent-key

leansignal.agentName sets the leansignal_agent_name label; leave it unset and it defaults to the Kubernetes node name.

On Kubernetes the agent collects cluster and node metrics (the k8s_cluster and kubeletstats receivers) and accepts OTLP from your workloads.

Resource names come from the chart’s fullname helper, which always prefixes the release name. Installing with the release name leansignal-agent therefore produces the doubled leansignal-agent-leansignal-agent:

WorkloadName (release leansignal-agent)
Deployment + ConfigMap + Service (collector)leansignal-agent-leansignal-agent
Deployment + ConfigMap + Service (local Loki)leansignal-agent-leansignal-agent-loki
Deployment + ConfigMap + Service (local Tempo)leansignal-agent-leansignal-agent-tempo
StatefulSet + Service (local VictoriaMetrics)leansignal-agent-victoria-metrics-single-server

Plus a ServiceAccount, a ClusterRole/Binding for the cluster and kubelet receivers, and a Secret unless you supply one.

Configuration is Helm values, not files edited in place. The collector config is a rendered ConfigMap, so hand-editing it in the cluster is undone by the next helm upgrade — unless you own it out-of-band with config.existingConfigMap.

Terminal window
# see the rendered collector config
kubectl -n leansignal get cm leansignal-agent-leansignal-agent -o jsonpath='{.data.config\.yaml}'
# change a value and roll it out
helm upgrade leansignal-agent oci://ghcr.io/leansignal/charts/leansignal-agent \
--namespace leansignal --reuse-values \
--set leansignal.tenant=NEW_TENANT \
--set leansignal.agentKey.value=NEW_KEY

A helm upgrade that changes the ConfigMap restarts the pod automatically. If you rotate an external Secret instead, restart it yourself with rollout restart.

Point the agent at a store you already run — setting a writeEndpoint disables the bundled one:

localLoki:
writeEndpoint: http://loki.monitoring.svc:3100/otlp/v1/logs
localTempo:
writeEndpoint: http://tempo.monitoring.svc:4318/v1/traces
# queryEndpoint has no derivation (the query API is a different port), so set it:
queryEndpoint: http://tempo.monitoring.svc:3200
victoria-metrics-single:
enabled: false
localVM:
writeEndpoint: http://my-vm.monitoring.svc:8428/api/v1/write

LeanSignal reads these stores over the gRPC tunnel via their queryEndpoint, so they never need to be exposed.

To store nothing locally, set localLoki.deploy=false / localTempo.deploy=false without a writeEndpoint — telemetry still reaches LeanSignal, but there is no local buffer to explore before demanding.

The bundled Loki and Tempo use an emptyDir by default, so a pod restart drops the local window. That is acceptable for a roughly one-hour buffer and never affects what LeanSignal already holds. Give either one a PVC to survive restarts:

localLoki:
persistence: { enabled: true, size: 5Gi, storageClassName: "" }
localTempo:
persistence: { enabled: true, size: 5Gi, storageClassName: "" }
Terminal window
# status
kubectl -n leansignal get pods,deploy,sts,svc,cm
# restart (rolling; PVCs and store data are retained)
kubectl -n leansignal rollout restart deploy/leansignal-agent-leansignal-agent
kubectl -n leansignal rollout status deploy/leansignal-agent-leansignal-agent
kubectl -n leansignal rollout restart deploy/leansignal-agent-leansignal-agent-loki
kubectl -n leansignal rollout restart deploy/leansignal-agent-leansignal-agent-tempo
kubectl -n leansignal rollout restart sts/leansignal-agent-victoria-metrics-single-server
Terminal window
kubectl -n leansignal logs deploy/leansignal-agent-leansignal-agent -f # collector
kubectl -n leansignal logs deploy/leansignal-agent-leansignal-agent-loki -f # local log store
kubectl -n leansignal logs deploy/leansignal-agent-leansignal-agent-tempo -f # local trace store
kubectl -n leansignal logs sts/leansignal-agent-victoria-metrics-single-server -f
# after a crash
kubectl -n leansignal logs deploy/leansignal-agent-leansignal-agent -f --previous

What is actually being forwarded? Each demand filter logs its verdict per batch:

Terminal window
kubectl -n leansignal logs deploy/leansignal-agent-leansignal-agent | grep 'demand filter' | tail -20

allowed=0 on a fresh agent is normal and correct — nothing is forwarded until a dashboard or alert demands it. The local stores keep receiving everything either way.

Port-forward, then use the same queries as any other platform:

Terminal window
kubectl -n leansignal port-forward svc/leansignal-agent-victoria-metrics-single-server 8428:8428
kubectl -n leansignal port-forward svc/leansignal-agent-leansignal-agent-loki 3100:3100
kubectl -n leansignal port-forward svc/leansignal-agent-leansignal-agent-tempo 3200:3200
kubectl -n leansignal port-forward deploy/leansignal-agent-leansignal-agent 13133:13133 # health

Add receivers through Helm values so they survive upgrades, then let the chart roll the pod. The agent bundles the full OpenTelemetry Collector Contrib set, and the integration pages give you a ready-made receiver block plus a demand you can import in one step.

For configuration you want to own entirely, point the chart at a ConfigMap you manage:

config:
existingConfigMap: my-agent-config # must contain a config.yaml key

The chart then renders no ConfigMap and mounts yours instead — and you trigger the rollout yourself when it changes.

An edge agent forwards OTLP to a central agent instead of running the full pipeline — no local stores, no demand filtering, no control stream, so no tenant is needed:

Terminal window
helm upgrade --install leansignal-agent-edge \
oci://ghcr.io/leansignal/charts/leansignal-agent \
-n leansignal --create-namespace \
--set leansignal.agentKey.value="YOUR_KEY" \
--set leansignal.agentName="edge-cluster-1" \
--set leansignal.centralAgentGrpcUrl="central-agent.central-ns.svc:4317"

The central agent’s OTLP Service must be reachable and is unauthenticated by design — keep it in-cluster or on a trusted network.

Terminal window
helm upgrade leansignal-agent oci://ghcr.io/leansignal/charts/leansignal-agent \
--namespace leansignal --reuse-values --version <chart-version>
helm uninstall leansignal-agent --namespace leansignal

Upgrading bumps the collector image; the local stores’ PVCs are retained.

Full detail lives in the Kubernetes install guide in the agent repository.

Was this page helpful?