Skip to content

Sensor: Kubernetes (Helm)

The Telovix Sensor deploys to Kubernetes as a DaemonSet via a Helm chart. Every Linux node in the cluster runs one sensor pod. This is the correct path for containerized workloads, O-Cloud platforms, and 5G Core clusters that use cluster lifecycle tooling.

When to use this path

ScenarioRecommendation
General-purpose clusterflavor=standard, cluster enrollment token
5G Core or O-RAN clusterflavor=telecom, cluster enrollment token, tag nodes by NF role
O-RAN vDU / vCU nodesflavor=telecom, use the values-oran-vdu.yaml overlay
Subset of nodes onlySet nodeSelector or affinity to target specific nodes
Production fleetStore the enrollment token in a Kubernetes Secret, not on the Helm command line

Prerequisites

RequirementNotes
Kubernetes 1.24+Tested; earlier versions may work
Helm 3.10+
Nodes: Linux, kernel 5.4+, BTF enabledSee Requirements
Telovix Console reachable from nodesPort 15483 (Telovix self-hosted default) outbound from nodes
Cluster enrollment tokenSee Generating the token

Generating the token

For Kubernetes, use a cluster enrollment token, not a one-time bare-metal token. Cluster tokens:

  • Are reusable by all nodes in the cluster
  • Are valid for 365 days so the DaemonSet can re-enroll after node restarts
  • Are bound to a cluster name; sensors from a different cluster name are rejected

Generate one from the Console:

  • UI path: Sensors > Deploy Sensor > Kubernetes > enter cluster name > Generate Token

Store the token as a Kubernetes Secret before installing:

bash
kubectl create namespace telovix-system

kubectl create secret generic telovix-sensor-token \
  --namespace telovix-system \
  --from-literal=enrollmentToken=<your-cluster-token>

If kubectl create secret fails with AlreadyExists, the most common cause is a previous install that left the Secret behind; delete it first with kubectl delete secret telovix-sensor-token -n telovix-system and recreate it with the new token.


Quick install

bash
helm repo add telovix https://telovix.github.io/charts
helm repo update

If helm repo add fails, the most common cause is no outbound internet access from the installation host to telovix.github.io; verify DNS resolution and HTTPS connectivity before retrying.

bash
helm install telovix-sensor telovix/telovix-sensor \
  --namespace telovix-system \
  --set sensor.consoleUrl="https://<console-host>:15483" \
  --set sensor.existingSecret="telovix-sensor-token" \
  --set clusterName="prod-cluster"

For the telecom flavor:

bash
helm install telovix-sensor telovix/telovix-sensor \
  --namespace telovix-system \
  --set sensor.consoleUrl="https://<console-host>:15483" \
  --set sensor.existingSecret="telovix-sensor-token" \
  --set clusterName="ran-zone-a" \
  --set flavor=telecom \
  --set "sensor.tags[0]=site:oslo-dc1" \
  --set "sensor.tags[1]=domain:ran" \
  --set "sensor.tags[2]=plmn:242-01"

If helm install fails with Error: INSTALLATION FAILED, the most common cause is a missing or incorrectly named Secret; confirm telovix-sensor-token exists in the telovix-system namespace with kubectl get secret telovix-sensor-token -n telovix-system.

Verify pods are running:

bash
kubectl get pods -n telovix-system -o wide

Expected output shows one pod per node, all in Running state:

NAME                      READY   STATUS    RESTARTS   AGE   NODE
telovix-sensor-2xk9p      1/1     Running   0          45s   node-01
telovix-sensor-4mv3q      1/1     Running   0          45s   node-02
telovix-sensor-r7bnf      1/1     Running   0          43s   node-03

If pods are in Init:0/1 or Pending, check the init container logs:

bash
kubectl logs -n telovix-system -l app.kubernetes.io/name=telovix-sensor -c bpf-init

If the init container logs show bpf filesystem not available or permission errors, the most common cause is the node kernel lacking BTF support or the pod not running in privileged mode; verify BTF with ls /sys/kernel/btf/vmlinux on the node.

Verify enrollment in the Console:

Go to Sensors. Sensors appear within one heartbeat cycle (up to 15 seconds per node). Each sensor should show trust state healthy and a cluster name matching clusterName.


What the chart deploys

ResourceDescription
DaemonSetOne sensor pod per node (tolerates all taints by default)
ServiceAccounttelovix-sensor in the release namespace
ClusterRole and ClusterRoleBindingRead-only access to nodes, pods, namespaces, services, endpoints, deployments, daemonsets, replicasets, statefulsets, jobs, cronjobs
ConfigMapConsole URL, cluster name, install ID
SecretEnrollment token (or reference to existingSecret)
ImagePullSecretRead-only registry deploy token (bundled)
NetworkPolicy (optional)Deny-all ingress, allow egress to DNS and Console port only
PriorityClass (optional)Prevents sensor pods from being evicted under node pressure

Init container

Each pod runs an init container (bpf-init) before the main sensor container starts. It:

  1. Mounts or verifies the BPF filesystem at /sys/fs/bpf
  2. Removes stale BPF map pins left by a previous sensor run (/sys/fs/bpf/telovix-sensor and /sys/fs/bpf/telovix)
  3. Detects stale credentials: hashes the current enrollment token, compares it with the hash stored after the last successful enrollment (/var/lib/telovix-sensor/.enrollment-token-hash). If the hash does not match (token rotated or Console wiped), it deletes the stale certificate files so the sensor re-enrolls cleanly with the new token

This makes token rotation idempotent: update the Secret, and the next pod restart automatically re-enrolls.


Security context

eBPF requires privileged mode. These settings are non-negotiable and are set by default:

yaml
securityContext:
  privileged: true
  runAsUser: 0
hostPID: true
hostNetwork: true
hostIPC: false

The sensor requires hostPID: true for host-wide process telemetry and hostNetwork: true for host-level network collection. Without privileged: true, the eBPF engine cannot attach kernel probes or access the BPF filesystem.


Host volumes

The sensor mounts these host paths read-only (except state and BPF):

MountHost pathAccess
/proc/procRead-only
/sys/sysRead-only
/sys/fs/bpf/sys/fs/bpfRead-write, Bidirectional propagation
/var/lib/telovix-sensor/var/lib/telovix-sensorRead-write (certs, policies, spool)
/host/run/runRead-only
/host/etc/etcRead-only

The state volume (/var/lib/telovix-sensor) is a hostPath volume. Certificate files and policy packs persist across pod restarts on the same node. If a pod moves to a different node, it re-enrolls fresh.


Key values reference

Required

ValueDescription
sensor.consoleUrlConsole URL, e.g. https://console.example.com:15483
sensor.enrollmentToken or sensor.existingSecretEnrollment token or name of a Secret containing it
clusterNameHuman-readable cluster name shown in the Console

Common optional values

ValueDefaultDescription
flavorstandardstandard or telecom
sensor.nodeRole(auto)Node role override. If empty, control-plane nodes get control_plane and workers get generic_linux
sensor.tags[]List of key:value tags applied at enrollment
sensor.nodeNameOverride(uses spec.nodeName)Override the node name shown in the Console
sensor.bootstrapCaCertPath(empty)Path to Console CA cert for self-signed Console TLS
tolerationsTolerate all taintsChange to target specific node groups
nodeSelector(empty)Target only matching nodes
affinity(empty)Advanced node targeting
resources.requests.cpu50m
resources.requests.memory128Mi
resources.limits.cpu500m
resources.limits.memory1Gi
updateStrategyRollingUpdate, maxUnavailable=1
terminationGracePeriodSeconds30Time to flush events on shutdown
priorityClass.createfalseCreate a PriorityClass to prevent eviction
networkPolicy.enabledfalseCreate deny-all-ingress, allow-egress-to-console NetworkPolicy
networkPolicy.consolePort15484Console mTLS port for egress rule
openshift.enabledfalseAdjusts SCCs for OpenShift
extraEnv[]Additional environment variables (e.g. HTTP_PROXY)

Sensor lifecycle

The pod's preStop hook calls /usr/local/bin/telovix-sensor --decommission before SIGTERM is sent. This notifies the Console to remove the sensor record cleanly. If the Console is unreachable, the pod still terminates after terminationGracePeriodSeconds.


Using a values file

For any non-trivial deployment, use a values file rather than --set flags:

yaml
# values-prod.yaml
sensor:
  consoleUrl: "https://console.example.com:15483"
  existingSecret: "telovix-sensor-token"
  nodeRole: "generic_linux"
  tags:
    - site:oslo-dc1
    - env:prod

clusterName: "oslo-prod-01"
flavor: standard

resources:
  requests:
    cpu: 50m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 1Gi

priorityClass:
  create: true
  name: telovix-sensor-priority
  value: 1000
  preemptionPolicy: PreemptLowerPriority
bash
helm install telovix-sensor telovix/telovix-sensor \
  --namespace telovix-system \
  -f values-prod.yaml

O-RAN vDU / vCU deployment

For O-RAN Distributed Unit and Central Unit nodes with DPDK-isolated cores, the chart includes a pre-built overlay file values-oran-vdu.yaml.

Key differences from the default values:

SettingDefaultvDU overlay
flavorstandardtelecom
resources.requests.cpu50m25m
resources.limits.cpu500m200m
resources.requests.memory128Mi64Mi
resources.limits.memory1Gi256Mi
sensor.nodeRole(empty)o_du
priorityClass.createfalsetrue (value: 1000000000)
networkPolicy.enabledfalsetrue
terminationGracePeriodSeconds3060

::: note Do not set cpu limit > 500m on a vDU node. L1 radio processing has zero tolerance for CPU contention on non-isolated cores. :::

Usage:

bash
helm install telovix-sensor telovix/telovix-sensor \
  --namespace telovix-system \
  -f values-oran-vdu.yaml \
  --set sensor.consoleUrl="https://console.example.com:15483" \
  --set sensor.existingSecret="telovix-sensor-token"

The vDU overlay also enables networkPolicy.enabled: true, which creates a NetworkPolicy that denies all ingress and allows egress only to port 53 (DNS) and the Console mTLS port. This satisfies O-RAN WG11 §6.5 management plane access control requirements. Verify your CNI supports HostEndpoint enforcement (Cilium or Calico required for full effectiveness with hostNetwork: true).

For NUMA affinity and isolcpus guidance, see the node-affinity requiredDuringSchedulingIgnoredDuringExecution example in values-oran-vdu.yaml and adapt the label key to match your cluster's vDU labeling scheme.


Configure a proxy

If nodes reach the Console through an HTTP proxy:

yaml
extraEnv:
  - name: HTTP_PROXY
    value: "http://proxy.corp.example.com:8080"
  - name: HTTPS_PROXY
    value: "http://proxy.corp.example.com:8080"
  - name: NO_PROXY
    value: "localhost,127.0.0.1,.cluster.local"

Kubernetes admission webhook (optional)

The chart can deploy a Kubernetes admission webhook that calls the Telovix Console before pods are created. This enforces admission rules configured in the Console's Admission view.

yaml
admission:
  enabled: true
  consoleUrl: "https://console.example.com:15483"
  caBundle: "<base64-encoded-Console-CA-cert>"
  failurePolicy: "Ignore"   # Use "Fail" in production after validating
  excludeNamespaces:
    - kube-system
    - telovix-system
  timeoutSeconds: 10

Get the CA bundle from Settings > Console > CA Certificate in the Console and copy the base64-encoded value into caBundle.

Start with failurePolicy: Ignore during initial rollout. Switch to Fail after confirming the webhook responds correctly. Fail means that if the Console is unreachable, all pod creation in monitored namespaces is blocked.


Post-install verification

bash
# Check pods are running on every expected node
kubectl get pods -n telovix-system -o wide

# Check logs for a specific pod
kubectl logs -n telovix-system \
  -l app.kubernetes.io/name=telovix-sensor \
  --since=5m

# Check init container logs if pods fail to start
kubectl logs -n telovix-system \
  -l app.kubernetes.io/name=telovix-sensor \
  -c bpf-init

In the Console, go to Sensors. You should see one sensor per node within one heartbeat cycle (up to 15 seconds per sensor). Each sensor shows:

  • Trust state: healthy
  • Node name: matches the Kubernetes node name (or sensor.nodeNameOverride if set)
  • Cluster name: matches clusterName
  • Flavor: standard or telecom
Fleet view showing multiple sensors enrolled from a Kubernetes cluster, each showing node name, cluster name, trust state, and last heartbeat.
Fleet view showing multiple sensors enrolled from a Kubernetes cluster, each showing node name, cluster name, trust state, and last heartbeat. Click to enlarge

Upgrade the chart

bash
helm repo update

helm upgrade telovix-sensor telovix/telovix-sensor \
  --namespace telovix-system \
  -f values-prod.yaml

If helm upgrade exits with Error: UPGRADE FAILED: release telovix-sensor not found, the most common cause is the release having been installed in a different namespace; check with helm list -A and include the correct --namespace flag.

The chart uses a RollingUpdate strategy with maxUnavailable: 1 by default. One node at a time goes through upgrade. On each node, the preStop hook calls --decommission before the old pod stops, and the new pod enrolls fresh using the cluster token.

Sensor identity (mTLS certificates) is preserved across upgrades because state lives on the hostPath volume at /var/lib/telovix-sensor. A new cert is only issued when the enrollment token changes.


Remove the sensor

bash
helm uninstall telovix-sensor --namespace telovix-system

This removes all chart resources. The preStop hook on each pod calls --decommission before termination, which removes the sensor records from the Console. If the decommission calls fail, clean up orphaned sensors manually from Sensors.

The state directory /var/lib/telovix-sensor is a hostPath and is not removed by Helm. To clean it from each node:

bash
rm -rf /var/lib/telovix-sensor

Troubleshooting

Init container fails: mount: bpf already mounted

The BPF filesystem is already mounted on this node. This is non-fatal; the init container detects the existing mount and continues without error. No action is needed.

Init container clears certs on every restart

The enrollment token stored in the Kubernetes Secret no longer matches the hash recorded after the last successful enrollment. This typically means the token was rotated without updating the Secret. Update the Secret with the current token and the init container will detect the match on the next restart and stop clearing certificates.

Pods stuck in Pending

The DaemonSet pods cannot be scheduled because a node taint is not tolerated by the chart. Check the tolerations section in your values file. The default chart tolerates all taints, so this usually means a custom tolerations override is too restrictive.

Pods scheduled but not in fleet

The pods are running but enrollment failed. Check kubectl logs -n telovix-system -l app.kubernetes.io/name=telovix-sensor -c bpf-init and kubectl logs -n telovix-system -l app.kubernetes.io/name=telovix-sensor for enrollment errors.

Sensors show stale

The Console is not reachable from the nodes. Verify that sensor.consoleUrl is correct and that nodes have outbound network access on port 15483. If a NetworkPolicy is active, confirm it permits egress to the Console port.

NodeLimitExceeded error in logs

The number of enrolled sensors has reached the license node limit. Check the active sensor count against the max_protected_nodes value shown in Console under Settings > License and either remove unused sensors or request a license upgrade from the Portal.

vDU pods evicted under load

The CPU or memory limits are too high relative to what L1 radio processing leaves available on non-isolated cores, causing the kubelet to evict the sensor pod under pressure. Apply the values-oran-vdu.yaml overlay, which reduces resource limits to values safe for vDU nodes.

NetworkPolicy blocks enrollment

The networkPolicy.consolePort value does not match the actual port your Console uses for the sensor mTLS listener. Verify networkPolicy.consolePort in your values file and correct it to match your Console's configured sensor port.

OpenShift SCCs blocking pod start

OpenShift Security Context Constraints are preventing the privileged pod from starting. Set openshift.enabled: true in your values file, which applies the required SCC adjustments for the Telovix Sensor on OpenShift.


Further reading

Released under the Telovix Commercial License.