Hubble: eBPF network observability, state of the art 2026 and the new frontier with AI agents
Contents
TL;DR
Hubble is Cilium’s native network observability, built on the same eBPF programs Cilium uses for enforcement. It does not duplicate the datapath or instrument the kernel its own way: it listens to the hooks Cilium already has and produces structured flow logs with Kubernetes context included, covering pod, namespace, labels, service, policy verdict and L7 payload where applicable. It is what happens when someone decides that tcpdump with grep does not scale to 10,000 pods and builds a distributed system of their own (a Hubble server per node, plus Hubble Relay as the aggregator, plus a CLI and a UI) with practically zero overhead, because the capture was already happening. In 2026 it is at version 1.19.3 (April 2026), with Cilium 1.19 marking the project’s tenth anniversary; IP options tracing has arrived, along with filtering by encryption status, the drop event tagged with the exact NetworkPolicy that caused it (direct attribution), a stabilised field mask API, and the first wave of ML anomaly detection applied to flows for predictive security in IoT/5G clusters. And, most interesting of all for 2026: a new frontier appears where the same eBPF observes AI agents such as Claude Code, Gemini CLI and MCP agents, intercepting SSL/TLS and stdio without instrumenting the code, which turns the Cilium + Hubble + Tetragon + AgentSight stack into a complete set of tools for understanding what an agentic system does inside a cluster.
This article is part 3 of the eBPF series. Part 1: eBPF from zero to Cilium: how the kernel learned to skip its own TCP/IP stack. Part 2: Tetragon: Cilium’s security cousin that sees every syscall in the kernel. Here we complete the observability quadrant: network with Hubble, process with Tetragon, AI agent with AgentSight.
The analogy: tcpdump that speaks Kubernetes
If you have administered networks over the last twenty years, tcpdump and Wireshark have been your daily bread. They capture packets on an interface, parse them, and let you filter with tcp.port == 443 and host 10.0.0.5. They work, they have been working since the 90s, and they are the first thing you open when something smells wrong.
Now stick tcpdump on a Kubernetes cluster with 10,000 pods. The problems show up in order:
- One
tcpdumpsession per node. You wanted to “see the traffic between the frontend and the API”; you need SSH to every node, tcpdump on every NIC, synchronised timestamps, manual aggregation. - There is no K8s context. You see a packet from
10.244.5.7to10.244.8.42. Which pod was that? Which namespace? Which label? You have to correlate withkubectl get pod -A -o wideevery single time. - No L7 understanding. You see a POST to HTTPS, and you cannot know the method and path because it is encrypted on the wire. If there is mTLS between pods, worse.
- High cost: full packet capture with a copy to userspace slows down the datapath. Under dense traffic, you notice it.
Hubble is tcpdump redesigned for all of that. It reuses the eBPF programs that are already processing every packet (Cilium puts them there for enforcement) and, while they take their allow/deny decision, they emit a flow event with all the context: source and destination pod identity, namespace, labels, protocol, verdict, and, if Cilium has done L7 parsing via Envoy, the HTTP method, path, status code, DNS query, Kafka topic. That event travels through a ringbuffer to userspace, it is received by the Hubble server that lives inside the node’s Cilium agent, and it is exposed over gRPC. A separate service, Hubble Relay, aggregates the streams from all nodes and gives you a single cluster-wide API. On top of that: a CLI (hubble) and a web UI with a real-time service graph.
Zero additional copies. Zero duplicated parsing. And the result is understandable by anyone who knows what a Pod is.
Architecture: four pieces visible from outside
Hubble is made up of four logical components, all optional depending on what you want to do:
1. Hubble Server (embedded in every Cilium agent)
It lives inside the Cilium agent process (it is not a separate binary). Each node exposes a gRPC endpoint locally on the Unix socket /var/run/cilium/hubble.sock. The server listens to the events the eBPF programs emit to the ringbuffer, enriches them with Kubernetes metadata (which the agent already has in memory), and makes them available to consumers.
Enabling it: --set hubble.enabled=true in Cilium’s Helm chart. By default, the server is only accessible locally; if you want to consume it from another node, it has to be exposed (which is what Hubble Relay does).
2. Hubble Relay (aggregator)
It is a separate Deployment (typically 1 replica, scalable) that connects to every Hubble server in the cluster and aggregates their streams into a single API. When your CLI or UI asks for “the last 1000 flows in the cluster”, the Relay collects them in parallel from all nodes and returns the union.
Enabling it: --set hubble.relay.enabled=true. Without the Relay you only see the traffic of the node you are connected to, which is useful for local debugging but not for a cluster-wide view.
3. Hubble CLI (hubble)
A Go binary that speaks gRPC with the Relay (or with a local Hubble server). It supports two main modes:
hubble observe: a real-time stream of flows, with very expressive filters (by namespace, pod, port, verdict, protocol, label).hubble status: the state of the Hubble cluster (how many nodes connected, lag, flow rate).
And the equivalent of tcpdump’s pcap dump: hubble observe --output jsonpb > flows.json to process afterwards with jq or other tools.
4. Hubble UI
A web frontend that connects to Hubble Relay and shows:
- A service graph in real time (which Pod talks to which Service, which protocols it uses, which verdict).
- A filterable list of flows.
- L7 details where there are any (HTTP method/path/status, DNS query/response).
Enabling it: --set hubble.ui.enabled=true. Useful for presentations to non-CLI teams; it does not replace the CLI for serious debugging.
What you see: the Hubble flow log from the inside
A Hubble flow in JSON format looks roughly like this (simplified):
{
"time": "2026-05-19T03:12:45.182Z",
"verdict": "FORWARDED",
"source": {
"ID": 5482,
"identity": 24871,
"namespace": "prod-api",
"labels": ["app=checkout", "team=payments"],
"pod_name": "checkout-7c9f-x8j2",
"workloads": [{"name": "checkout", "kind": "Deployment"}]
},
"destination": {
"ID": 12041,
"identity": 18356,
"namespace": "prod-db",
"labels": ["app=postgres", "tier=primary"],
"pod_name": "postgres-0"
},
"Type": "L3_L4",
"l4": {
"TCP": {
"source_port": 41982,
"destination_port": 5432,
"flags": {"SYN": true}
}
},
"node_name": "rke2-worker-03",
"Summary": "TCP Flags: SYN"
}
When L7 parsing is active (via embedded Envoy or Hubble’s lightweight parser), the same flow adds:
"l7": {
"type": "REQUEST",
"http": {
"code": 200,
"method": "GET",
"url": "/api/v1/cart/items",
"protocol": "HTTP/1.1",
"headers": [{"key": "user-agent", "value": "checkout/1.4.2"}]
}
}
The protocols natively supported for L7 parsing:
- HTTP/1.1 and HTTP/2 (including gRPC over HTTP/2).
- DNS (queries and responses, with domains, types, response codes).
- Kafka (topics, API keys).
- TLS handshake (SNI, not the encrypted payload by default).
- MySQL, Cassandra (with optional modules).
For HTTP and gRPC, Cilium can enable the embedded Envoy proxy for the flows you want to inspect (not all of them; it is selective via CiliumNetworkPolicy with L7 rules). Without Envoy there is lightweight parsing, but less detailed.
Verdict and drop attribution
Every flow has a verdict: FORWARDED, DROPPED, ERROR, AUDIT, REDIRECTED, TRACED, TRANSLATED. For the DROPPED case, Hubble includes a structured reason (drop_reason) and, since Cilium 1.19, the exact NetworkPolicy that caused it.
That last point changes day-to-day operations. Before, when a pod could not talk to another one, the debug flow was:
- See the dropped flow in Hubble.
- Look at every CiliumNetworkPolicy in the namespace.
- Reason manually about which one, with which labels, is blocking it.
With Cilium 1.19’s attribution, the policy_match_info field tells you directly “it was dropped by the frontend-egress policy, rule 3”. You go from “Sherlock Holmes for 20 minutes” to “kubectl get -o yaml of that specific policy”.
Prometheus metrics and Grafana dashboards
Hubble also exposes aggregated metrics in Prometheus format, separate from the gRPC flow stream. Enabling it: --set hubble.metrics.enabled=true (Helm) plus a list of the set you want to export.
The usual metric groups:
flow: total flows by verdict, source/dest, protocol.http: requests by method, response code, latency (histogram).dns: queries, response codes, top-N domains.tcp: handshakes, retransmissions, congestion window.drop: drops by reason, with NetworkPolicy attribution.port-distribution: histogram of active ports.policy: hits by policy and verdict.
These metrics have rich K8s labels (source_workload, destination_workload, namespace, and so on) that make them pivotable in Grafana. There are prebuilt dashboards on Grafana Labs covering the common cases; importing one and having immediate visibility costs five minutes.
Cost: metrics with many K8s labels can blow up cardinality in Prometheus. For large clusters (>1,000 pods), it is worth reviewing which set you export and using drop rules in Prometheus to keep a lid on it.
Deployment: Helm on one screen
The canonical Cilium install with full Hubble:
# values.yaml
hubble:
enabled: true
metrics:
enabled:
- dns:query;ignoreAAAA
- drop
- tcp
- flow
- port-distribution
- icmp
- httpV2:exemplars=true;labelsContext=source_ip,source_namespace,source_workload,destination_ip,destination_namespace,destination_workload,traffic_direction
serviceMonitor:
enabled: true # auto-discovered by kube-prometheus-stack
relay:
enabled: true
rollOutPods: true
ui:
enabled: true
rollOutPods: true
ingress:
enabled: true
className: cilium
hosts:
- hubble.example.local
And the install itself:
helm upgrade --install cilium cilium/cilium -n kube-system -f values.yaml
After installing, validate with cilium status (the Cilium CLI) that the Hubble section shows OK, and try your first flow with:
cilium hubble observe --namespace prod-api --pod checkout-7c9f-x8j2
State of the art in 2026
Cilium 1.19 was released in February 2026, marking the project’s tenth anniversary. Hubble reached version 1.19.3 on 22 April 2026. The relevant news:
Direct attribution of drops to a NetworkPolicy
Already covered above; it is probably the most valuable operational change in the release. Any dropped flow carries the name, namespace and specific rule of the policy responsible. It is also available via Prometheus metrics, which allows alerts of the form “policy X is dropping >N requests/second”.
Tracing with IP options
Hubble can now trace individual packets with IP options enabled. It is a mechanism similar to traceroute, but at L3: you put a mark on the packet and Cilium reports it every time the packet crosses a node or an eBPF decision. Useful for debugging multi-cluster paths, fabric mesh, or NetworkPolicies applied at different layers.
Filtering by encryption status
A new CLI flag: hubble observe --encryption-status=encrypted (or unencrypted). Useful for validating deployments with WireGuard or IPsec enabled pod-to-pod: you confirm that the traffic that should be encrypted is, and you spot regressions quickly.
Hubble field mask API stabilised
The field_mask lets you ask for only the parts of the flow you care about, hugely reducing bandwidth and processing when all you need is, say, source/dest and verdict. It used to be experimental; now it is stable and it is default-on in the CLI.
AI-driven anomaly detection (predictive security)
This is the most talked-about addition of 2026. Cilium 1.19 adds hooks so that an external consumer, typically an ML system, can process flows in streaming and detect statistical anomalies: pods that suddenly talk to new destinations, latency spikes on an API, odd DNS sequences. The detection part happens outside the Cilium agent (nobody wants heavy ML in the datapath), but Cilium exposes the flows with the pre-computed features the model needs. The published use cases focus on IoT and 5G, where traffic is high in volume and low in variety, ideal conditions for anomaly detection.
Scaling to 10,000+ pods
Cilium 1.19 has done serious work on scalability: Hubble Relay can now aggregate streams from hundreds of nodes without saturating; the default field_mask reduces inter-node bandwidth; and flows can be sampled under high load if your use is statistical analysis rather than forensic debugging.
Cilium 1.20 in development
Cilium 1.20 is in the development branch. The most relevant bits for Hubble:
- Unification of
preferIpv6: thehubble.preferIpv6flag was deprecated in favour of the globalpreferIpv6that applies to every Cilium component. tetragon-pythonSDK: although it belongs to Tetragon, not Hubble, it sets a trend, namely eBPF policies written in Python instead of YAML. Hubble will probably follow a similar path.
The new frontier: eBPF and AI agents
So far, the classic Hubble content. But there is a 2026 twist worth covering, because it closes the loop with the other series on this blog.
When a Kubernetes cluster starts running AI agents, such as Claude Code, Gemini CLI, or LangGraph-based agents calling APIs and MCP servers, the observability problem changes shape. It is no longer enough to know “which pod talked to which pod” (that is Hubble) or “which process ran what” (that is Tetragon). You need to know:
- Which external APIs the agent is calling and with which prompts.
- Which MCP tools it is invoking, with which arguments.
- How many tokens it consumes, which model it picks, how much it costs.
- Whether the agent drifts from expected behaviour (out-of-policy queries, jailbreak attempts, secret leakage).
The traditional solutions, instrumenting the agent’s code with OpenTelemetry or parsing structured logs, do not work well when the agent is a third-party binary (Anthropic’s Claude Code, Google’s Gemini CLI) or when the MCP servers live in other languages with stdio as their transport.
AgentSight: zero-instrumentation for LLM agents
AgentSight (a project from the eunomia-bpf group, the same ecosystem behind several high-profile eBPF runtimes) attacks this problem with the same philosophy as Hubble: do not instrument; listen. It puts eBPF hooks at two critical points:
uprobes on SSL/TLS libraries (
libssl,boringssl,rustls). It captures the plaintext before encryption on send and after decryption on recv. For an HTTP call tohttps://api.anthropic.com/v1/messages, AgentSight sees the full JSON of the prompt and the response without decrypting anything in transit, simply because it has reached the syscall level before the TLS layer does its work.stdiocapBPF: it capturesread,writeanddupon a process’s stdin/stdout/stderr file descriptors. This is what makes it possible to observe MCP servers that speak stdio with their client, the usual pattern for local MCP servers. You capture the JSON-RPC going back and forth without either the client or the server knowing.
Reported overhead: <3% CPU, comparable to Hubble in its own regime.
How it fits with Hubble and Tetragon
The three complement each other cleanly:
- Hubble tells you: “the agent’s pod opened a TCP connection to
api.anthropic.com:443with verdict ALLOW”. - Tetragon tells you: “the
claude-codeprocess with PID 1843 did aconnect()to that IP” (plus the binary, the arguments, the pod namespace). - AgentSight tells you: “the HTTPS content of that connection was a prompt
messages=[{role:'user', content:'analyze this repo and modify the firewall config'}]and the response included a tool call toread_filewith argument/etc/passwd”.
It is the difference between flow, process and semantics. For a security team that wants to watch AI agents in production, all three are necessary. For anyone who wants to understand cost, all three are useful (Hubble for network latency, Tetragon for resource usage, AgentSight for tokens and chosen model).
Emerging use cases
The patterns consolidating in 2026:
- Agent audit trail: recording every LLM call and every tool call for compliance, especially in regulated sectors.
- Jailbreak and prompt injection detection: applying rules over the prompts captured by AgentSight (similar to Tetragon’s TracingPolicy, but over semantic content).
- Cost accountability: seeing which team/agent consumes which tokens, without instrumenting.
- Replay and debugging: reproducing an agent’s reasoning in production without asking it to run again (which is non-deterministic).
It is a young field, AgentSight is months old rather than years, but the “eBPF as zero-instrumentation observability” pattern is very clearly spreading beyond network and process. The coming year will see consolidation and, probably, native integration with Hubble.
Common Hubble use cases
Back to Hubble proper, the cases in which any organisation deploys it:
1. NetworkPolicy debugging
The classic use: “this pod cannot reach this Service”. Without Hubble, it meant SSH, tcpdump, comparing rules. With Hubble:
hubble observe --from-pod prod-api/checkout --to-pod prod-db/postgres --verdict DROPPED
If there are drops, you see the policy responsible (Cilium 1.19+). If there are no drops, the problem is not policy: it is DNS, routing or the target service.
2. Auditing inter-namespace communication
For compliance: validating that isolated namespaces are not communicating against what was declared.
hubble observe --from-namespace prod-payments --to-namespace 'NOT prod-db' --output json
3. Exfiltration detection
Outbound traffic to suspicious public destinations. Hubble detects them by IP/SNI, not by payload (which is encrypted):
hubble observe --to-fqdn 'NOT *.example.com' --to-fqdn 'NOT *.internal' --protocol tcp
Combined with Prometheus metrics and Grafana alerts, this gives you an exfiltration radar at zero cost.
4. Real-time service SLOs
The hubble:http:response_time_seconds metrics with source_workload, destination_workload, method and status_code labels allow SLO dashboards without needing to instrument the apps. The SRE sees the p95 latency of checkout → catalog directly.
5. Performance debugging
hubble:tcp:retransmissions_total and hubble:tcp:flags_total{flag="RST"} are early signals of network problems. A rise correlated with a latency regression points you at something in the infrastructure (NIC, switch, MTU) before you go down to investigate the app.
6. Post-incident forensics
Configuring Hubble to export flows to persistent storage (via OTLP to Tempo/Loki, or hubble observe --output jsonpb to S3) gives you forensic capability: if at T+30 days you detect that something was wrong at T, you can reconstruct the traffic.
Hubble and the rest of the observability stack
Hubble does not replace Prometheus, Loki, Tempo or Jaeger; it complements them:
- Prometheus: receives Hubble’s aggregated metrics. Hubble exports a native Prometheus endpoint.
- Loki: receives the structured flow logs if you export them as logs. Hubble has no native Loki exporter, but a Fluent Bit with an OTLP plugin or a custom one bridges it easily.
- Tempo / Jaeger: the Cilium Operator has an OTLP exporter of flows in trace format (each HTTP/gRPC flow is a span). It integrates with Tempo or any other OTLP tracing backend.
- Grafana: there are already public Hubble dashboards. Combined with Prometheus, Loki and Tempo, they give you a unified panel: metrics, logs, traces, all correlated by K8s labels.
The full-stack pile seen in production in 2026 (described in Building a Production eBPF Observability & Security Stack for Kubernetes in 2026):
- Data: Cilium + Hubble (network), Tetragon (process), AgentSight (AI agent).
- Pipeline: OTLP Collector as the single router.
- Storage: Prometheus (metrics), Loki (logs), Tempo (traces).
- UI: Grafana with domain-specific dashboards.
- Alerting: AlertManager with rules over the Hubble + Tetragon metrics.
Comparison with the alternatives
| System | Layer | Focus | Model |
|---|---|---|---|
| Hubble | L3-L7 network | K8s cluster with Cilium | eBPF, pull metrics, push flows gRPC |
| GKE Dataplane v2 obs | L3-L7 network | GKE managed | eBPF (Cilium-based, managed) |
| Tigera Calico Whisker | L3-L7 network | Cluster with Calico | eBPF + pcap, own UI |
| Tetragon | Process/syscall | K8s cluster | eBPF, push events gRPC |
| Falco | Process/syscall | K8s cluster | eBPF in userspace or kernel module |
| AgentSight | LLM agent | Agentic systems | eBPF (SSL uprobes + stdio) |
| Beyla (Grafana) | Application | App L7 + tracing | eBPF (uprobes on libs) |
| Pixie | App + system | Broad cluster visibility | eBPF + PXL script |
| Parca | CPU/mem profiling | Performance | eBPF profile sampling |
If your CNI is Cilium, Hubble is the natural entry point and it does not compete with the rest: it complements them. For Calico clusters, Whisker is the equivalent. For profiling, Parca. For AI agents, AgentSight. The era of “one tool for everything” is passing: the modern stack combines several specialised pieces, all eBPF-based, exposed via OTLP.
Operational traps
Cardinality in Prometheus
Hubble metrics with all the K8s labels can blow up Prometheus. Measure cardinality before exporting everything. The most prolific metrics are flow and httpV2; start with drop and port-distribution and add the rest incrementally.
L7 visibility costs CPU
Enabling L7 parsing via embedded Envoy adds load to the agent (not to the base datapath, but yes to the node’s envoy proxy). For heavy HTTP traffic, measure. For flows where you only need L4, leave Envoy disabled.
Hubble Relay without HA
A single Relay replica is a single point of failure for the CLI and the UI (not for the local agent, which keeps working). For production, deploy with replicas: 2+ and topologySpreadConstraints so both do not go down together.
Encryption status reporting depends on the Cilium config
The new --encryption-status filter only gives real data if Cilium has encryption enabled (WireGuard or IPsec). Without that, everything is unencrypted and the filter contributes nothing.
UI exposed without auth
Hubble UI has no native auth. If you expose it through Ingress, there has to be authentication in front of it: OIDC via oauth2-proxy, mTLS, IP allowlist. It is not optional.
Storage that does not scale
If you keep flows for days for forensics, the volume is serious. For a cluster with 100 active pods, easily 1-10 GB/day of flow logs. Plan the lifecycle (compaction, retention, cold storage) before enabling it.
What we have not covered
- Mesh / multi-cluster Hubble: aggregating flows from several Cilium clusters into a single Relay. Use case: a cross-cluster view, debugging a distributed service mesh.
hubble export: local persistence on the agent’s disk for forensics with low retention.- Anomaly detection with your own models: how to connect the gRPC stream to a custom ML consumer.
- AgentSight in depth: the project deserves its own article. Next instalment.
- eBPF for LLM serving profiling: how to measure vLLM’s TTFT, TPOT and throughput without instrumenting, using uprobes on libcudart.
References
Hubble and Cilium:
- Hubble GitHub — main repo.
- Hubble — Network Observability (Cilium docs) — official reference.
- Cilium 1.19 release notes (InfoQ, feb 2026) — tenth anniversary and 1.19 news.
- Cilium releases — all releases.
- Hubble L7 HTTP Metrics — Grafana dashboard 19423 — ready to import.
- End‑to‑end L7 Visibility with Cilium Hubble (cloud-cod.com, mar 2026).
- Cilium Hubble Observability Platform Internal Analysis (Young-ju).
- CiliumNetworkPolicy Python Hubble: L7 Visibility 2026 — one of the threads on the Python SDK.
State of the art 2026 and the full stack:
- Building a Production eBPF Observability & Security Stack for Kubernetes in 2026 (DEV).
- eBPF-Based Network Observability: Exploring Cilium Hubble and Alternatives (CloudRaft).
eBPF + AI agents:
- AgentSight (GitHub eunomia-bpf) — the referenced project.
- Harnessing eBPF for High‑Performance LLM Workloads (Klizo Solutions).
Cross-references:
- Part 1: eBPF from zero to Cilium.
- Part 2: Tetragon: Cilium’s security cousin.
- LLM inference series: KV cache, vLLM on K8s, PagedAttention, LLM K8s Operators — where the traffic Hubble observes carries the prompts AgentSight inspects.