Skip to content
All flows
metrics
logs

K8s Node Agent (DaemonSet)

Per-node DaemonSet that scrapes kubelet and host metrics, tails pod logs with the container parser and file_storage checkpoints, enriches everything with k8sattributes, and forwards to the in-cluster gateway.

The per-node half of a Kubernetes setup, meant to run as a DaemonSet: kubeletstats scrapes container, pod, node, and volume metrics from the local kubelet; hostmetrics reads CPU, memory, load, disk, network, and filesystem from the node under `/hostfs`; and filelog tails pod logs with the `container` operator handling docker, containerd, and CRI-O formats. k8sattributes enriches everything with namespace, deployment, pod, and container metadata, associating by connection first and pod UID as the fallback. It forwards over OTLP to an in-cluster gateway at `otel-gateway.observability.svc.cluster.local` — change that to wherever your gateway Service lives. File offsets checkpoint to file_storage so a pod restart doesn't replay logs. It needs the usual DaemonSet privileges: a service account that can read the kubelet API and hostPath mounts for `/var/log` and `/hostfs`; `insecure_skip_verify` is on because kubelets commonly serve self-signed certificates.

Before you use this

Sends data to

otlp

You'll need to set these before it runs

K8S_NODE_NAME

The configuration

collector v0.147.0
# OpenTelemetry Collector Configuration
# Generated by Telflo

receivers:
  kubeletstats:
    auth_type: 'serviceAccount'
    endpoint: '${env:K8S_NODE_NAME}:10250'
    insecure_skip_verify: true
    collection_interval: '30s'
    metric_groups:
      - 'container'
      - 'pod'
      - 'node'
      - 'volume'
  hostmetrics:
    collection_interval: '30s'
    root_path: '/hostfs'
    scrapers:
      cpu: null
      memory: null
      load: null
      disk: null
      network: null
      filesystem: null
  filelog:
    include:
      - '/var/log/pods/*/*/*.log'
    include_file_path: true
    start_at: 'end'
    storage: 'file_storage'
    operators:
      - id: 'container-parser'
        type: 'container'
        max_log_size: 102400
    retry_on_failure:
      enabled: true
processors:
  memory_limiter:
    check_interval: '1s'
    limit_percentage: 85
    spike_limit_percentage: 20
  k8sattributes:
    passthrough: false
    filter:
      node_from_env_var: 'K8S_NODE_NAME'
    extract:
      otel_annotations: true
      metadata:
        - 'k8s.namespace.name'
        - 'k8s.deployment.name'
        - 'k8s.node.name'
        - 'k8s.pod.name'
        - 'k8s.pod.uid'
        - 'k8s.container.name'
    pod_association:
      - sources:
          - from: 'connection'
      - sources:
          - from: 'resource_attribute'
            name: 'k8s.pod.uid'
  batch:
    timeout: '10s'
exporters:
  otlp:
    endpoint: 'otel-gateway.observability.svc.cluster.local:4317'
    tls:
      insecure: true
extensions:
  file_storage:
    directory: '/var/lib/otelcol'
    create_directory: true
service:
  extensions: [file_storage]
  pipelines:
    metrics:
      receivers: [kubeletstats, hostmetrics]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlp]
    logs:
      receivers: [filelog]
      processors: [memory_limiter, k8sattributes, batch]
      exporters: [otlp]

Validated against otelcol-contrib v0.147.0. Fill in the ${env:…} placeholders before running it.

kubernetes
daemonset
collection