Hubble Component Deep-Dive
What This Component Does
Hubble is Cilium’s observability engine, providing real-time visibility into network flows (L3/L4/L7), service dependencies, and policy enforcement across a Kubernetes cluster secured by Cilium. It leverages eBPF programs in the Cilium agent to capture flow data from kernel BPF maps without performance overhead or sampling.
Use cases:
- Debugging: Trace connectivity issues between pods/services (e.g., “why can’t pod A reach service B?”).
- Monitoring: Export flows as metrics (Prometheus) or logs for dashboards/alerts.
- Security: Audit policy drops, detect anomalous traffic.
- Visualization: Generate service maps via Hubble UI.
Enable it for any production Cilium deployment needing network observability. It’s lightweight (reads map deltas, no per-flow overhead) and scales horizontally via the Relay aggregator.
How It Works
Hubble operates in a publisher-subscriber model with two main processes: Hubble Observers (embedded in each cilium-agent) and Hubble Relay (optional aggregator).
Architecture Overview
graph TD
subgraph "Per-Node: cilium-agent"
BPF[BPF Maps<br/>(conntrack, L7, sockops)<br/>Real-time deltas] -->|subscribe & read| Observer[Hubble Observer<br/>pkg/hubble/observer<br/>Enrich + filter flows]
Observer -->|Prometheus metrics<br/>[pkg/metrics/hubble]| Metrics[Metrics Exporter]
Observer -->|gRPC stream<br/>[pkg/hubble/exporter/]| PeerCache[Peer Service Cache]
end
Observer -.->|Unix/GRPC socket<br/>enable-peer-service| Relay[Hubble Relay<br/>pkg/hubble/relay<br/>Aggregates + caches flows]
Relay -->|RocksDB cache<br/>[relay/cache]| Cache[Flow Cache<br/>Time-series store]
Relay -->|gRPC API server<br/>[pkg/hubble/api]| APIServer[gRPC API v1<br/>Query/filter flows]
APIServer --> CLI[Hubble CLI<br/>Observe, status]
APIServer --> UI[Hubble UI<br/>Service map, flows]
APIServer -->|Protobuf export| Custom[Custom clients<br/>e.g., Kafka exporter]
style BPF fill:#ff9999
style Cache fill:#99ff99
Step-by-Step Process
- Flow Capture (Passive): Cilium’s eBPF programs populate kernel BPF maps (
bpf/maps/conntrack-v2,bpf/maps/l7), emitting deltas on connect/update/close. - Observation:
Observer(pkg/hubble/observer/observer.go) subscribes viabpf.Mapring buffers. It polls for deltas efficiently (sub-ms latency). - Enrichment: Each
Flowprotobuf is enriched with:- Endpoint identities (
identityRepo). - DNS/service names (
serviceCache). - Policy verdicts (
verdictCache). - Deduplication/timestamping (
observer.go:handleConntrackNotification).
- Endpoint identities (
- Export:
- Local: Metrics (
CounterVecfor Prometheus) or direct CLI socket. - Remote: gRPC to Relay (
grpc.Dial, TLS optional).
- Local: Metrics (
- Relay Aggregation (if enabled): Receives streams from all nodes, stores in
RocksDB-backed cache (relay/cache/local.go), handles queries with filters (time, endpoint, labels). - Querying: Clients use gRPC
ServerAPI.GetFlowswithFlowFilter(proto-defined). Relay fans out to cache; supports follow/tail modes.
Trade-offs:
- Clever: Zero-copy map reads + protobuf serialization minimize CPU. Peer service discovery via K8s API avoids central state.
- Scales to 100k+ flows/sec/node but Relay cache grows with
--max-flows; evicts old flows (LRU). - No persistence by default (ephemeral); use external sinks for long-term.
Key Code Paths
Core Files
pkg/hubble/: Entry points, types (flow.pb.go).pkg/hubble/observer/: Node-local flow reader.pkg/hubble/relay/: Aggregator server.pkg/hubble/api/v1/: gRPC protobuf defs (api.proto).cmd/hubble/: CLI binary.
Key Functions
| File/Function | Purpose |
|---|---|
observer.go:NewObserver | Initializes map subscriptions, caches (identity/service/verdict). Starts goroutines for polling. |
observer.go:handleConntrackNotification | Core loop: Parses map entry → NewFlow → enrich → queue to exporters. Handles L4/L7. |
observer.go:RegisterExporter | Plugs in metrics/GRPC sinks; callback-based. |
relay/relay.go:NewRelay | Sets up gRPC server, cache, peer connections to agents. |
relay/api/server.go:GetFlows | Handles client RPC: Filters cache → streams Response. Supports --follow. |
exporter/exporter.go:GRPCExporter | Streams flows to Relay; retries, backpressure. |
Startup Flow: CiliumConfig → enableHubble → observer.New() → cmd/cilium-agent.runDaemon() integrates it.
Configuration
Hubble is configured via Cilium ConfigMap/CRD (HubbleConfig), Helm values, or agent flags/env vars.
Key Options
| Setting | Type | Default | Effect |
|---|---|---|---|
enableHubble | Bool (agent) | false | Enables observer in cilium-agent. |
hubble.inactiveSvcCleanInterval | Duration | 60s | Service cache TTL. |
hubble.flows | Bool (config CRD) | true | Capture L3/L4 flows. |
hubble.tlsClientCertFiles | Paths | "" | mTLS for agent→relay. |
hubble.listen-address | String (relay) | “:80” | Relay gRPC/HTTP port. |
hubble.max-flows | Int (relay) | 5000 | Cache size; evicts oldest. |
hubble.metrics.enabled | Bool | true | Prometheus endpoint /metrics. |
Env: HUBBLE_SOCK | UnixSocket | /var/run/cilium/hubble.sock | CLI direct connect. |
Apply: kubectl apply -f hubble-config.yaml or Helm --set hubble.enabled=true.
Flags (cilium-agent): --enable-hubble --hubble-sock-path=/var/run/hubble.sock --peer-service-path=/var/run/cilium/peer-service.sock.
Extension Points
-
Custom Exporters: Implement
observer.ExportFunc(observer/types.go):func MyExporter(flow *v1.Flow) { /* Kafka sink */ } observer.RegisterExporter(MyExporter)See
pkg/exportsink/for Kafka/Elastic examples. -
Relay Plugins: Extend
cache.Storageinterface for custom backends (e.g., Kafka producer inrelay/cache/). -
Filters: Add to
FlowFilterproto; handled inapi.Match(). -
UI/CLI: Build custom clients using
hubble.pb.gogRPC stubs. Fork UI (install/kubernetes/hubble-ui). -
BPF Hooks: Inject custom flow parsers via
conntrack.NewObserverOpts().
To modify: Vendor protos, rebuild agent/relay/CLI. Test with hubble observe --to-fqdn k8s.io --verdict DROP.