Using Alloy for observability
Running every scrape job through a single node-level agent means one bad application can take down monitoring for the whole node. An application that labels a metric with something unique, a request ID for example, can generate hundreds of thousands of series. The agent runs out of memory and crashes. While it is down, nothing on that node is collected: not the kubelet, not etcd, not the health daemon, not the logs, and not the application that caused it. The data you need to debug the incident disappears exactly when you need it.
So we split collection in two. A DaemonSet handles infrastructure telemetry, which is required because it is the only way to reach the node's loopback endpoints. A separate agent handles application telemetry and scales on its own. If an application overwhelms its own collector, the node's monitoring keeps running.
flowchart TD
subgraph infra["Infrastructure telemetry"]
node["Worker and control-plane nodes<br/>loopback metrics endpoints"]
logs["Container, journald,<br/>and audit logs"]
ds["System Alloy<br/>host-network DaemonSet"]
node -->|"scrape 127.0.0.1"| ds
logs -->|"tail /var/log"| ds
end
subgraph apps["Application telemetry"]
app["Application pods<br/>Prometheus endpoints"]
inst["Instrumented services<br/>OTLP exporters"]
sts["Application Alloy<br/>clustered StatefulSet"]
app -->|"scrape ServiceMonitor targets"| sts
inst -->|"push OTLP"| sts
end
ds -->|"infrastructure metrics and logs"| backend["Your backend<br/>Prometheus or Mimir, Loki, Tempo"]
sts -->|"application metrics and traces"| backendBoth agents write to the same backend, so the split stops at the collection tier. Your dashboards query everything as one dataset.
What each agent owns
| System Alloy | Application Alloy | |
|---|---|---|
| Shape | DaemonSet, one pod per node, host network | StatefulSet, a few replicas, pod network |
| Metrics | Control-plane, kubelet, node, Cilium, and cluster component endpoints | Your workloads' /metrics endpoints |
| Logs | Container, journald, and the audit streams | none |
| Traces | none | OTLP over gRPC and HTTP, plus span metrics |
| Scales with | Node count, and nothing else | Application count and trace volume |
| Blast radius | One node's infrastructure view | Application telemetry only |
One rule keeps that separation intact: never add an application scrape job to the DaemonSet. A platform component emits a predictable number of series. An application emits as many as its labels allow, and that number is out of your hands.
Host network access
Most of the platform's metrics endpoints bind to 127.0.0.1 and use plain HTTP with no authentication. This is intentional: loopback-only means nothing off the node can reach them.
This also means an ordinary scraper cannot reach them. Inside a pod, 127.0.0.1 refers to the pod's own loopback, not the node's. Only a pod sharing the node's network namespace can see these endpoints. See The observability model for background, and Reference: metrics per component for which endpoint lives where.
This is why the System Alloy pod is configured the way it is:
hostNetwork: true: puts the agent on the node's network namespace, so127.0.0.1resolves to the node.dnsPolicy: ClusterFirstWithHostNet: keeps cluster DNS working, so the agent can still resolve the backend's Service name.- Read-only host mounts (
/var/log/pods,/var/log/journal, audit paths): lets one agent collect both logs and metrics, instead of running a separate agent per signal. - Tolerates all taints: the agent runs on every node, including tainted control planes and any nodes your own workloads taint. A skipped node means no telemetry from that node.
- Node-role discovery and relabeling: routes each job to the right nodes. Control-plane metrics only exist on control planes,
syself-proxyonly on workers, and the CSI node plugin only on cloud VM workers. Without this, a static target list would cause constantconnection refusederrors and falseTargetDownalerts. - Write-ahead log on disk: buffers samples when the backend is unreachable, so a backend restart costs you latency instead of data.
Warning
The System Alloy is a highly privileged collector. On the host network it can reach every loopback listener on the node, including unauthenticated ones like etcd on 2381, KubeGate on 8080, and syself-agent on 20257. Its ServiceAccount also holds cluster-wide get on /metrics and nodes/metrics. Keep it in a namespace only your platform team can write to, run no application workloads there, and review its scrape config like a firewall rule.
How the application agent scales
Application load scales with your workloads, not your machines, so splitting the work by node is the wrong split. The Application Alloy runs as a cluster of replicas instead. The replicas form a hash ring and divide the scrape targets between them, rebalancing as replicas join or leave, so every target is scraped exactly once and adding a replica adds capacity. The same pool terminates OTLP, which puts span metrics next to the traces they are generated from.
Alloy, and the alternatives
Alloy carries metrics, logs, and traces in one binary. The usual alternative is three: a Prometheus agent, Promtail, and an OpenTelemetry Collector, which means three config languages, three upgrade cycles, and three sets of host mounts on every node. Its Kubernetes service discovery also saves you a hand-written target list that breaks every time a component moves.
The architecture here does not depend on Alloy. Vector or Fluent Bit read the same log paths, the OpenTelemetry Collector takes the same OTLP, and a plain Prometheus agent scrapes the same loopback endpoints. What matters is the split: infrastructure collection in a host-network DaemonSet, application collection in a pool that scales by adding replicas. The rest of this guide uses Alloy because it lets us give you one coherent set of configs.
Start with Deploy the System Alloy for node and control-plane telemetry. Add Deploy the Application Alloy once you have applications to monitor.
Plan your observability stack
Decide in-cluster versus central, how long to keep data, and how big it will get, before you install anything.
Deploy the System Alloy
Install one Grafana Alloy DaemonSet on the host network that scrapes every loopback and cluster component metrics endpoint and ships container, journald, and audit logs off the node.