LinkMesh

Search docs, blog and changelog

ENDE

Snippets · Processors

Add Kubernetes pod, namespace and deployment to telemetry

A span or log line from a pod says nothing about which deployment, namespace or node it came from unless something adds it. The k8sattributes processor looks the sending pod up in the Kubernetes API, by the k8s.pod.ip resource attribute or the connection's source IP, and adds those names to every record.

Signals
LogsMetricsTraces
Category
Kubernetes
Source
OTLP
Components
otlpbatchk8sattributesmemory_limiterotlphttp
Destination
OTLP/HTTP endpoint

OpenTelemetry Collector

OpenTelemetry Collector YAML
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 80
    spike_limit_percentage: 25
  # Adds pod, namespace, deployment and node to every record, looked up from
  # the Kubernetes API by the sending pod's IP. Needs RBAC: get/watch/list on
  # pods, namespaces and replicasets (deployment name).
  k8sattributes:
    auth_type: serviceAccount
    passthrough: false
    extract:
      metadata:
        - k8s.namespace.name
        - k8s.pod.name
        - k8s.pod.uid
        - k8s.deployment.name
        - k8s.node.name
    pod_association:
      - sources:
          - from: resource_attribute
            name: k8s.pod.ip
      - sources:
          - from: connection
  batch:
    timeout: 5s

exporters:
  otlphttp:
    endpoint: https://your-backend:4318

service:
  pipelines:
    logs:
      receivers: [otlp]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlphttp]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlphttp]
    traces:
      receivers: [otlp]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlphttp]

LinkMesh

LinkMesh has no built-in template for this job. Add it as a custom processor in raw mode, with k8sattributes as the component type and this body - the same lines as under k8sattributes in the collector config:

Custom processor body (k8sattributes)
auth_type: serviceAccount
passthrough: false
extract:
  metadata:
    - k8s.namespace.name
    - k8s.pod.name
    - k8s.pod.uid
    - k8s.deployment.name
    - k8s.node.name
pod_association:
  - sources:
      - from: resource_attribute
        name: k8s.pod.ip
  - sources:
      - from: connection

How custom components are validated and rolled out: create a custom processor.

Download config.yamlValidated with otelcol-contrib v0.161.0 on 2026-10-26

Complete config files, each checked with the collector's own validate command (otelcol-contrib v0.161.0). Replace https://your-backend:4318 with your own OTLP endpoint before you run it.

The gotcha

validate accepts this config anywhere, but outside a cluster - or inside one without a service account - the collector does not start working. In our test it logged "unable to load k8s config, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined", then kept running without ever reporting ready: a live process with no working pipeline. Run it in-cluster with RBAC for pods, namespaces and replicasets (needed for the deployment name).

What it does not catch

This page has no before/after table: the processor needs a live Kubernetes API, and our CI runs the collector outside a cluster.

Manage this across a fleet

LinkMesh manages collector configuration across a fleet from one self-hosted control plane, so a change like this is made once rather than host by host. The first 25 Collectors are free after a no-card registration in the OpenSight Customer Portal (5 without one).

Doing this in LinkMesh: Onboard Kubernetes layer by layer