Back to KB
Difficulty
Intermediate
Read Time
11 min

Monitoring Kubernetes Clusters with OpenTelemetry Collector: The Agent + Gateway Pattern Explained

By Codcompass TeamΒ·Β·11 min read

Architecting Resilient Telemetry Pipelines: Decoupling Collection from Delivery in Kubernetes

Current Situation Analysis

Modern observability stacks are frequently deployed with a single, monolithic OpenTelemetry Collector instance per node. This approach appears efficient during initial setup: one binary, one configuration, direct forwarding to Tempo, Loki, or Prometheus. The architecture collapses under production scale because it conflates two fundamentally incompatible operational profiles. Local signal collection requires minimal resource footprint and high availability. Remote signal delivery requires stateful buffering, cryptographic credential management, and aggressive batching.

The primary failure mode manifests as connection exhaustion. When every application pod or sidecar exporter opens a direct gRPC channel to a central ingest endpoint, the backend receives thousands of concurrent connections. Observability backends like Grafana Tempo or Loki are optimized for aggregated streams, not unbounded fan-out. Each gRPC connection maintains keepalive state, negotiates TLS handshakes, and consumes file descriptors. At 20+ nodes with autoscaling workloads, connection counts easily exceed 500. The ingest layer does not degrade linearly; it hits concurrency thresholds and begins returning RESOURCE_EXHAUSTED or UNAVAILABLE status codes. Most SDK exporters log the error once, discard the payload, and continue. Traces and logs vanish silently.

Resource contention compounds the problem. A collector attempting to scrape kubeletstats, tail container logs, and maintain retry queues for remote backends will experience memory pressure during scrape spikes. The batch processor accumulates payloads while the prometheusreceiver or filelog receiver consumes CPU and RAM. Without strict isolation, the collector pod exceeds its memory limit, triggers an OOMKill, and restarts. During the 30–90 second restart window, node-level telemetry goes dark. When the pod returns, the retry queue is empty. Data loss becomes a feature of the deployment model rather than an exception.

Teams overlook this architectural flaw because official documentation often presents single-pipeline examples for simplicity. Tutorials rarely demonstrate how backpressure propagates through the collector's internal queues. The assumption that "more memory solves buffering problems" ignores the reality of node-level resource constraints. Kubernetes schedules pods based on requests/limits, not actual runtime behavior. A collector configured with a 512Mi memory limit on a busy node will compete with application workloads, trigger eviction policies, and destabilize the very telemetry it was meant to collect.

WOW Moment: Key Findings

Decoupling collection from delivery transforms an unbounded fan-out problem into a controlled, predictable stream. The following comparison illustrates the operational divergence between monolithic and split architectures:

ApproachUpstream ConnectionsMemory ProfileFailure ModeSecurity Blast RadiusTail Sampling Capability
Monolithic CollectorUnbounded (scales with pod count)High (requires persistent queues)OOMKill loops, silent data dropsFull cluster API + backend credentialsNot possible (spans fragmented across nodes)
Agent + GatewayBounded (3–5 per gateway replica)Low (agent: 200–300Mi, gateway: scalable)Graceful degradation, controlled dropsStrictly isolated (agent: read-only, gateway: network-only)Native (all spans converge at gateway)

This finding matters because it shifts telemetry infrastructure from a reactive, resource-draining model to a proactive, capacity-planning model. The gateway acts as a pressure valve: it absorbs connection spikes, applies sampling policies, and maintains a single authenticated channel to external backends. The agent remains lightweight, node-local, and disposable. When a backend experiences latency, the gateway's retry queue absorbs the delay while agents continue accepting local OTLP traffic. The system degrades predictably instead of collapsing under connection limits.

Core Solution

The architecture separates telemetry handling into two distinct Kubernetes workloads: a node-scoped DaemonSet for collection and a cluster-scoped Deployment for delivery. Each component operates under explicit resource boundaries and security contexts.

Step 1: Deploy the Node Agent (DaemonSet)

The agent runs exactly once per node. It listens on loopback interfaces to receive OTLP traffic from local SDKs and sidecars. It scrapes node-level metrics and tails container logs. Its configuration enforces strict memory limits and avoids persistent storage.

Architecture Decision: Use memory_limiter as the first processor in every pipeline. The collector evaluates memory pressure before payloads enter the batch queue. Placing it later allows memory to exhaust before the li

πŸŽ‰ Mid-Year Sale β€” Unlock Full Article

Base plan from just $4.99/mo or $49/yr

Sign in to read the full article and unlock all 635+ tutorials.

Sign In / Register β€” Start Free Trial

7-day free trial Β· Cancel anytime Β· 30-day money-back