Deploy Beyla with Kubernetes manifests
You can deploy Grafana Beyla in Kubernetes with your own manifests instead of a Helm chart. Use this option to create and manage all the Kubernetes resources that run Beyla yourself. The manifests run Beyla as a DaemonSet, which runs a Beyla Pod on your cluster nodes and instruments the applications on each node.
To deploy Beyla with a Helm chart instead, refer to Deploy Beyla with the Beyla Helm chart. To configure the Helm chart for Grafana Cloud Application Observability, refer to Deploy Beyla with the Beyla Helm chart for Grafana Cloud. To deploy Beyla with Kubernetes cluster monitoring, refer to Deploy Beyla with the Kubernetes Monitoring Helm chart. To run Beyla inside Grafana Alloy, refer to Deploy Beyla with the Grafana Alloy Helm chart.
Before you begin
Before you deploy Beyla, make sure you have the following:
- A Kubernetes cluster whose nodes meet the Beyla requirements and limitations
kubectl, configured for the cluster- Permission to create cluster-scoped resources and privileged Pods
- An OpenTelemetry Protocol (OTLP) endpoint for the Beyla metrics and traces, and the credentials for it, if any. For Grafana Cloud, follow the procedure in Send data to the Grafana Cloud OTLP endpoint. For Grafana Alloy, refer to Collect OpenTelemetry data and forward it to any OpenTelemetry-compatible endpoint.
Pod requirements
Beyla loads eBPF programs into the node kernel, so its container needs elevated privileges. Run the container in privileged mode, or grant only the Linux capabilities Beyla needs, as described in Deploy Beyla unprivileged.
Beyla also needs to see the processes it instruments.
Set hostPID: true in the Pod, so Beyla shares the process ID (PID) namespace of the node.
When Beyla runs in a Pod, it adds Kubernetes metadata, such as the namespace and Pod name, to metrics and traces. To get the metadata, Beyla needs permission to list and watch Pods, Services, Nodes, and ReplicaSets in the Kubernetes API. Beyla doesn’t instrument a process in a container until it finds the Pod for that container, so without these permissions Beyla doesn’t instrument containerized applications. For the metadata attributes and options, refer to Kubernetes decorator.
Note
If the Beyla container doesn’t have the capabilities it needs, Beyla logs a warning and keeps running, but it might malfunction. To stop Beyla at startup instead, set
BEYLA_ENFORCE_SYS_CAPS=true.
Create the service account and RBAC
Create a namespace for Beyla, and a service account with the permissions that Beyla needs to read Kubernetes metadata:
Create the
beylanamespace:kubectl create namespace beylaSave the following manifest as
beyla-rbac.yml:apiVersion: v1 kind: ServiceAccount metadata: name: beyla namespace: beyla --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: beyla rules: - apiGroups: ["apps"] resources: ["replicasets"] verbs: ["list", "watch"] - apiGroups: [""] resources: ["pods", "services", "nodes"] verbs: ["list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: beyla subjects: - kind: ServiceAccount name: beyla namespace: beyla roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: beylaCreate the resources:
kubectl apply -f beyla-rbac.yml
Create the Beyla configuration
Beyla reads its configuration from the file that BEYLA_CONFIG_PATH points to, and from environment variables.
Store the file in a ConfigMap, and store the OTLP credentials in a Secret:
Save the following ConfigMap as
beyla-config.yml:apiVersion: v1 kind: ConfigMap metadata: name: beyla-config namespace: beyla data: beyla-config.yml: | discovery: instrument: - k8s_namespace: <NAMESPACE>Replace
<NAMESPACE>with the namespace of the applications to instrument. To instrument applications in all namespaces, use"*", which is what the Beyla Helm chart uses by default. Without a selector, Beyla exits at startup with amissing application discovery sectionerror. Beyla still skips Kubernetes system namespaces and other services that it excludes by default. For other ways to select applications, refer to Configure Beyla service discovery.Save the following Secret as
grafana-secret.yml:apiVersion: v1 kind: Secret metadata: name: grafana-secret namespace: beyla type: Opaque stringData: otlp-headers: "<OTLP_HEADERS>"Replace
<OTLP_HEADERS>with the headers your OTLP endpoint needs, such as authentication, as comma-separatedkey=valuepairs. If your endpoint doesn’t need headers, skip this step.For Grafana Cloud, copy the
OTEL_EXPORTER_OTLP_HEADERSvalue that the OpenTelemetry tile of your stack generates. The value has the formAuthorization=Basic <BASE64_CREDENTIALS>, where<BASE64_CREDENTIALS>is your instance ID and token, joined by a colon and Base64-encoded. To create the credentials yourself, runecho -n '<INSTANCE_ID>:<TOKEN>' | base64 | tr -d '\n'.Create the ConfigMap and the Secret:
kubectl apply -f beyla-config.yml -f grafana-secret.ymlIf you skipped the Secret, apply only
beyla-config.yml.
Deploy Beyla as a DaemonSet
A DaemonSet runs a Beyla Pod on each node.
Each Pod instruments the applications on its node that match the discovery section of your configuration:
Save the following manifest as
beyla-daemonset.yml:apiVersion: apps/v1 kind: DaemonSet metadata: name: beyla namespace: beyla labels: app: beyla spec: selector: matchLabels: app: beyla template: metadata: labels: app: beyla spec: serviceAccountName: beyla hostPID: true containers: - name: beyla image: grafana/beyla:latest securityContext: privileged: true readOnlyRootFilesystem: true env: - name: BEYLA_CONFIG_PATH value: /config/beyla-config.yml - name: OTEL_EXPORTER_OTLP_ENDPOINT value: "<OTLP_ENDPOINT>" - name: OTEL_EXPORTER_OTLP_HEADERS valueFrom: secretKeyRef: name: grafana-secret key: otlp-headers volumeMounts: - name: beyla-config mountPath: /config volumes: - name: beyla-config configMap: name: beyla-configReplace
<OTLP_ENDPOINT>with the base URL of your OTLP endpoint. Beyla appends/v1/metricsand/v1/traces. For Grafana Cloud, copy the endpoint from the OpenTelemetry tile of your stack, for examplehttps://otlp-gateway-prod-eu-west-0.grafana.net/otlp.For Grafana Alloy in the same cluster, use the Alloy Service and the HTTP port of the
otelcol.receiver.otlpcomponent. The default port is4318, for examplehttp://<ALLOY_SERVICE>.<ALLOY_NAMESPACE>:4318. Replace<ALLOY_SERVICE>and<ALLOY_NAMESPACE>with the name and namespace of the Alloy Service.The
otelcol.receiver.otlpcomponent needs anhttpblock, and the Alloy Service must expose the port. With the Alloy Helm chart, add the port to thealloy.extraPortsvalue.If you skipped the Secret, remove the
OTEL_EXPORTER_OTLP_HEADERSvariable.The DaemonSet skips nodes with taints that it doesn’t tolerate, such as control-plane nodes. To run Beyla on every node, add the following
tolerationsto the Pod spec, at the same level ascontainers:tolerations: - effect: NoSchedule operator: Exists - effect: NoExecute operator: ExistsCreate the DaemonSet:
kubectl apply -f beyla-daemonset.ymlCheck that the Beyla Pods are running:
kubectl get pods --namespace beylaCheck the logs of a Beyla Pod:
kubectl logs --namespace beyla <POD_NAME>Replace
<POD_NAME>with a Pod name from the previous command. The log includes aGrafana Beylaline that shows the Beyla version. If the log showsRequired system capabilities not present, Beyla may malfunction, grant the capabilities that the message lists.(Optional) To see each request that Beyla instruments, add the following variable to the
envlist of the Beyla container inbeyla-daemonset.yml:- name: BEYLA_TRACE_PRINTER value: textThen run
kubectl apply -f beyla-daemonset.ymlagain. After the applications receive requests, Beyla writes one line for each request tostdout, sokubectl logsshows the lines with the rest of the Beyla log. Remove the variable when you finish testing.
After the instrumented applications receive requests, their metrics and traces appear in your OTLP backend.
With this configuration, Beyla does the following:
- Instruments applications in the
<NAMESPACE>namespace, except services that Beyla excludes by default - Adds Kubernetes metadata attributes, for example
k8s.namespace.nameandk8s.pod.name - Exports application metrics and traces to your OTLP endpoint
- Doesn’t export network-level metrics or Prometheus metrics
To also expose Prometheus metrics, or to use them instead of OTLP, refer to Configure Beyla Prometheus and OpenTelemetry data export.
Deploy Beyla unprivileged
Instead of a privileged container, you can run Beyla with only the Linux capabilities it needs.
Whether this works depends on your Kubernetes version and container runtime, for example containerd, CRI-O, or Docker.
These steps were tested mainly with containerd on GKE, kubeadm, k3s, MicroK8s, and kind.
For what each capability does, refer to Beyla security, permissions, and capabilities.
To run Beyla unprivileged, complete the following steps:
In the Beyla container of your DaemonSet, replace the
securityContextsection with the following:securityContext: runAsUser: 0 readOnlyRootFilesystem: true capabilities: add: - BPF # Required for most eBPF probes - SYS_PTRACE # Access the container namespaces and inspect executables - NET_RAW # Use socket filters for HTTP requests - CHECKPOINT_RESTORE # Open the libraries of instrumented processes through /proc/<pid>/map_files - DAC_READ_SEARCH # Open ELF files - PERFMON # Load BPF programs # - SYS_RESOURCE # Kernels earlier than 5.11 only: increase the locked memory limit drop: - ALLApply the updated manifest, for example:
kubectl apply -f beyla-daemonset.yml
Deploy unprivileged Beyla on OpenShift
The default OpenShift Security Context Constraint (SCC) policy doesn’t allow the host access, user ID, and Linux capabilities that unprivileged Beyla needs. A cluster administrator can create a dedicated SCC that permits these settings without allowing privileged containers:
Save the following SCC as
beyla-scc.yml:apiVersion: security.openshift.io/v1 kind: SecurityContextConstraints metadata: name: beyla allowHostPID: true allowPrivilegedContainer: false allowedCapabilities: - BPF - SYS_PTRACE - NET_RAW - CHECKPOINT_RESTORE - DAC_READ_SEARCH - PERFMON readOnlyRootFilesystem: true runAsUser: type: MustRunAs uid: 0 seLinuxContext: type: RunAsAny fsGroup: type: RunAsAny supplementalGroups: type: RunAsAnyCreate the SCC, and grant it only to the
beylaservice account:oc apply -f beyla-scc.yml oc adm policy add-scc-to-user beyla -z beyla -n beylaKeep the capability-based
securityContextfrom the previous section. The SCC permits those settings but keepsallowPrivilegedContainerdisabled.
SCC assignments grant elevated permissions. Use a dedicated namespace and service account for Beyla, and review the SCC with your OpenShift administrator before you deploy it in production.