Module 1.7: Hubble - Network Observability with Cilium
Complexity: [MEDIUM]
Section titled “Complexity: [MEDIUM]”Time to Complete: 90 minutes Prerequisites: Module 1.6 (Pixie), Basic networking concepts (TCP/IP, DNS), Kubernetes networking basics Learning Objectives:
- Understand eBPF-based network observability
- Deploy Hubble with Cilium CNI
- Use Hubble CLI and UI to visualize network flows
- Troubleshoot network policies and connectivity issues
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After completing this module, you will be able to:
- Deploy Hubble for Cilium-based network observability with real-time flow visualization
- Configure Hubble’s flow filters to monitor service-to-service communication and DNS resolution
- Implement Hubble metrics export to Prometheus for network-layer alerting and dashboards
- Integrate Hubble UI with Grafana dashboards for comprehensive network traffic analysis
Why This Module Matters
Section titled “Why This Module Matters”Traditional network troubleshooting in Kubernetes is painful. You end up running tcpdump in containers, parsing packet captures, and correlating logs across dozens of pods. Network policies are “deny by default” black boxes—when traffic is blocked, you rarely know why.
Hubble changes network observability from guesswork to clarity.
Built on Cilium’s eBPF foundation, Hubble observes all network traffic at the kernel level. You see every connection, every packet, every policy decision—without modifying applications or installing sidecars. It’s like having Wireshark for your entire cluster, but organized by Kubernetes resources.
“Before Hubble, network debugging was ‘add logs, redeploy, hope.’ Now we see exactly what’s happening—which pod talked to which service, what got blocked and why.”
Did You Know?
Section titled “Did You Know?”- Hubble processes millions of network events per second with minimal overhead thanks to eBPF
- The Hubble UI provides a real-time service map showing all connections between pods and services
- Hubble can show you exactly which network policy blocked a connection—no more guessing
- DNS visibility is built-in: you see every lookup, resolution time, and failure
- Hubble supports HTTP/gRPC-layer observability without any application changes
- The name “Hubble” is a reference to the space telescope—giving visibility into the dark spaces of your network
Hubble Architecture
Section titled “Hubble Architecture”┌────────────────────────────────────────────────────────────────────────┐│ Kubernetes Cluster ││ ││ ┌──────────────────────────────────────────────────────────────────┐ ││ │ Hubble Components │ ││ │ │ ││ │ ┌─────────────┐ ┌─────────────┐ ┌───────────────────────────┐ │ ││ │ │ Hubble UI │ │ Hubble Relay│ │ Hubble CLI │ │ ││ │ │ (Web) │ │ (gRPC) │ │ (hubble observe) │ │ ││ │ └──────┬──────┘ └──────┬──────┘ └─────────────┬─────────────┘ │ ││ │ │ │ │ │ ││ │ └────────────────┼───────────────────────┘ │ ││ │ ▼ │ ││ │ ┌──────────────────────┐ │ ││ │ │ gRPC API │ │ ││ │ └──────────┬───────────┘ │ ││ └───────────────────────────┴──────────────────────────────────────┘ ││ │ ││ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ││ │ Node 1 │ │ Node 2 │ │ Node 3 │ ││ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ ││ │ │ Cilium │ │ │ │ Cilium │ │ │ │ Cilium │ │ ││ │ │ Agent │ │ │ │ Agent │ │ │ │ Agent │ │ ││ │ │ +Hubble │ │ │ │ +Hubble │ │ │ │ +Hubble │ │ ││ │ └────┬────┘ │ │ └────┬────┘ │ │ └────┬────┘ │ ││ │ │eBPF │ │ │eBPF │ │ │eBPF │ ││ │ ┌────┴────┐ │ │ ┌────┴────┐ │ │ ┌────┴────┐ │ ││ │ │ Network │ │ │ │ Network │ │ │ │ Network │ │ ││ │ │ Events │ │ │ │ Events │ │ │ │ Events │ │ ││ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ ││ └───────────────┘ └───────────────┘ └───────────────┘ │└────────────────────────────────────────────────────────────────────────┘Components
Section titled “Components”| Component | Role | Description |
|---|---|---|
| Cilium Agent | Data collection | Runs on each node, collects network events via eBPF |
| Hubble Server | Event processing | Embedded in Cilium agent, provides gRPC API |
| Hubble Relay | Aggregation | Aggregates data from all nodes for cluster-wide queries |
| Hubble CLI | Command-line | Query flows from terminal (hubble observe) |
| Hubble UI | Visualization | Web UI with service maps and flow visualization |
Installing Hubble
Section titled “Installing Hubble”Prerequisites
Section titled “Prerequisites”Hubble requires Cilium as your CNI. If you’re not using Cilium yet:
# Install Cilium CLICILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)curl -L --fail --remote-name-all \ https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gzsudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/binOption 1: Install Cilium with Hubble Enabled
Section titled “Option 1: Install Cilium with Hubble Enabled”# Install Cilium with Hubblecilium install --version 1.14.4 \ --set hubble.enabled=true \ --set hubble.relay.enabled=true \ --set hubble.ui.enabled=true
# Verify installationcilium status --waitOption 2: Enable Hubble on Existing Cilium
Section titled “Option 2: Enable Hubble on Existing Cilium”# If Cilium is already installed via Helmhelm upgrade cilium cilium/cilium --namespace kube-system \ --reuse-values \ --set hubble.enabled=true \ --set hubble.relay.enabled=true \ --set hubble.ui.enabled=true \ --set hubble.metrics.enabled="{dns,drop,tcp,flow,icmp,http}"Install Hubble CLI
Section titled “Install Hubble CLI”# Install Hubble CLIHUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)curl -L --fail --remote-name-all \ https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-amd64.tar.gzsudo tar xzvfC hubble-linux-amd64.tar.gz /usr/local/bin
# Verify installationhubble versionVerify Hubble is Running
Section titled “Verify Hubble is Running”# Check Cilium status (includes Hubble)cilium status
# Expected output includes:# Hubble Relay: OK# Hubble UI: OK
# Check Hubble status specificallyhubble status
# Output:# Healthcheck (via localhost:4245): Ok# Current/Max Flows: 8192/8192 (100.00%)# Flows/s: 45.67Using the Hubble CLI
Section titled “Using the Hubble CLI”Basic Flow Observation
Section titled “Basic Flow Observation”# Observe all network flows in real-timehubble observe
# Output:# TIMESTAMP SOURCE DESTINATION TYPE VERDICT# Jun 15 14:23:01.123 default/frontend-xxx default/api-xxx L7/HTTP to-endpoint FORWARDED# Jun 15 14:23:01.234 default/api-xxx kube-system/coredns L4/UDP to-endpoint FORWARDEDFiltering by Namespace
Section titled “Filtering by Namespace”# Observe flows in a specific namespacehubble observe --namespace production
# Observe flows from a specific podhubble observe --from-pod production/api-server-7b9f8c6d5-abcd
# Observe flows to a specific servicehubble observe --to-service kube-system/kube-dnsFiltering by Verdict
Section titled “Filtering by Verdict”# Show only dropped traffic (great for debugging)hubble observe --verdict DROPPED
# Show only forwarded traffichubble observe --verdict FORWARDED
# Show traffic denied by network policyhubble observe --verdict POLICY_DENIEDProtocol-Specific Filtering
Section titled “Protocol-Specific Filtering”# Show only HTTP traffichubble observe --protocol HTTP
# Show only DNS traffichubble observe --protocol DNS
# Show TCP connection eventshubble observe --type trace:to-endpoint --type trace:from-endpointOutput Formats
Section titled “Output Formats”# JSON output for processinghubble observe --output json | jq '.flow.source.pod_name'
# Compact output (one line per flow)hubble observe --output compact
# Dictionary output (detailed)hubble observe --output dictNetwork Policy Debugging
Section titled “Network Policy Debugging”One of Hubble’s killer features is network policy verdict visibility.
See Why Traffic Was Dropped
Section titled “See Why Traffic Was Dropped”# Show all dropped traffichubble observe --verdict DROPPED
# Output:# TIMESTAMP SOURCE DESTINATION TYPE VERDICT# Jun 15 14:23:01.123 default/frontend-xxx default/db-xxx L4/TCP DROPPED (Policy denied)# Policy: default/deny-all-db-accessTrace Policy Decisions
Section titled “Trace Policy Decisions”# See exactly which policy allowed/denied traffichubble observe --verdict POLICY_DENIED --output json | jq '.flow.policy_match_type'
# Show the policy that matchedhubble observe --to-pod default/database-0 --output json | jq '.flow.traffic_direction, .flow.policy_match_type'Test Policy Before Applying
Section titled “Test Policy Before Applying”# Run in one terminal: watch traffic to your podhubble observe --to-pod default/my-app --verdict DROPPED
# In another terminal: apply your network policykubectl apply -f my-network-policy.yaml
# Immediately see if the policy is blocking expected trafficHTTP/L7 Observability
Section titled “HTTP/L7 Observability”Hubble can parse HTTP traffic and show request-level details:
# Enable HTTP visibility (if not already)# This requires Cilium to be configured with L7 policy
# Observe HTTP requestshubble observe --protocol HTTP
# Output:# TIMESTAMP SOURCE DESTINATION TYPE VERDICT HTTP INFO# Jun 15 14:23:01.123 default/frontend default/api L7/HTTP FORWARDED GET /api/users 200# Jun 15 14:23:01.456 default/frontend default/api L7/HTTP FORWARDED POST /api/orders 201HTTP Filtering
Section titled “HTTP Filtering”# Filter by HTTP methodhubble observe --http-method GET
# Filter by status codehubble observe --http-status 500
# Filter by URL pathhubble observe --http-path /api/usersThe Hubble UI
Section titled “The Hubble UI”Accessing Hubble UI
Section titled “Accessing Hubble UI”# Port-forward the UIcilium hubble ui
# Or manuallykubectl port-forward -n kube-system svc/hubble-ui 12000:80
# Open http://localhost:12000UI Features
Section titled “UI Features”The Hubble UI provides:
- Service Map: Visual graph showing all service-to-service connections
- Flow Table: Real-time table of network flows
- Namespace Filtering: Focus on specific namespaces
- Protocol Breakdown: See HTTP, TCP, DNS separately
- Policy Verdicts: Visual indication of allowed/denied traffic
┌─────────────────────────────────────────────────────────────────┐│ Hubble UI ││ ┌───────────────────────────────────────────────────────────┐ ││ │ Service Map │ ││ │ │ ││ │ ┌──────────┐ ┌──────────┐ │ ││ │ │ frontend │────────▶│ api │ │ ││ │ └──────────┘ └────┬─────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌──────────┐ ┌──────────┐ │ ││ │ │ redis │◀────────│ database │ │ ││ │ └──────────┘ └──────────┘ │ ││ │ │ ││ │ Legend: ──▶ HTTP ··▶ TCP ╳ Dropped │ ││ └───────────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────────┐ ││ │ Flow Table │ ││ │ Source Destination Protocol Verdict │ ││ │ frontend-x api-y HTTP FORWARDED │ ││ │ api-y database-z TCP FORWARDED │ ││ │ api-y external-ip TCP DROPPED │ ││ └─────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘Hubble Metrics
Section titled “Hubble Metrics”Hubble can export Prometheus metrics for alerting and dashboards:
# Enable Hubble metrics in Ciliumhelm upgrade cilium cilium/cilium --namespace kube-system \ --reuse-values \ --set hubble.metrics.enabled="{dns,drop,tcp,flow,icmp,http}"Available Metrics
Section titled “Available Metrics”| Metric | Description |
|---|---|
hubble_flows_processed_total | Total flows processed |
hubble_drop_total | Dropped packets by reason |
hubble_tcp_flags_total | TCP flag distribution |
hubble_dns_queries_total | DNS queries by type |
hubble_http_requests_total | HTTP requests by method/status |
Example Prometheus Queries
Section titled “Example Prometheus Queries”# Dropped packets rate by reasonrate(hubble_drop_total[5m])
# HTTP error ratesum(rate(hubble_http_requests_total{http_status=~"5.."}[5m]))/sum(rate(hubble_http_requests_total[5m]))
# DNS query latencyhistogram_quantile(0.99, rate(hubble_dns_response_types_total[5m]))Hubble vs Other Network Observability Tools
Section titled “Hubble vs Other Network Observability Tools”| Feature | Hubble | Wireshark/tcpdump | Service Mesh Telemetry |
|---|---|---|---|
| Deployment | Automatic with Cilium | Manual per pod | Sidecar per pod |
| Overhead | Minimal (eBPF) | Moderate (packet capture) | Significant (proxy) |
| Kubernetes-aware | Yes | No | Yes |
| Policy visibility | Full verdict details | None | Partial |
| Scale | Cluster-wide | Single pod | Cluster-wide |
| Real-time UI | Yes | No | Varies |
| L7 visibility | With Cilium L7 policy | Yes (manual) | Yes |
War Story: The Mysterious Database Timeouts
Section titled “War Story: The Mysterious Database Timeouts”A SaaS company was experiencing intermittent database connection failures. Their application logs showed “connection timeout to PostgreSQL,” but the database was healthy and had plenty of capacity.
The Investigation:
- Database monitoring: All green
- Application logs: Sporadic timeout errors
- Network team: “Network is fine”
- Everyone blamed everyone else
Enter Hubble:
# They ran this query:hubble observe --to-pod database/postgres-0 --verdict DROPPED
# Output:# TIMESTAMP SOURCE DESTINATION VERDICT# Jun 15 14:23:01.123 production/api-6x4f2 database/postgres-0 DROPPED (Policy denied)# Jun 15 14:23:05.789 production/api-9k2m3 database/postgres-0 DROPPED (Policy denied)The Discovery: A network policy was applied to the database namespace that only allowed connections from pods with a specific label. When new API pods were deployed, they didn’t have the label—but the Kubernetes readiness probe passed before the first database connection attempt.
# The problematic policyapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-api-to-database namespace: databasespec: ingress: - from: - podSelector: matchLabels: db-access: "true" # <-- API pods were missing this label!The Fix: Updated the API deployment to include the db-access: "true" label.
The Lesson: Without Hubble, they would have spent days debugging application code. Hubble showed the policy verdict in seconds.
Common Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Solution |
|---|---|---|
| Not enabling Hubble Relay | Can’t see cluster-wide flows | Enable hubble.relay.enabled=true |
| Missing HTTP visibility | Only see L4 flows | Configure Cilium L7 policy for HTTP parsing |
| Hubble buffer too small | Missing flows during high traffic | Increase hubble.flowBuffer |
| Not using namespaces | Too much noise in output | Always filter with --namespace |
| Forgetting to check verdicts | Missing dropped traffic | Include --verdict DROPPED in debugging |
| Running without Cilium | Hubble requires Cilium CNI | Can’t use Hubble with other CNIs |
Advanced: Exporting to External Systems
Section titled “Advanced: Exporting to External Systems”Export to OpenTelemetry
Section titled “Export to OpenTelemetry”# Enable OTel export in Ciliumhelm upgrade cilium cilium/cilium --namespace kube-system \ --reuse-values \ --set hubble.export.enabled=true \ --set hubble.export.otelExporter.enabled=true \ --set hubble.export.otelExporter.endpoint="otel-collector:4317"Export to S3 for Analysis
Section titled “Export to S3 for Analysis”# Enable file exporthelm upgrade cilium cilium/cilium --namespace kube-system \ --reuse-values \ --set hubble.export.enabled=true \ --set hubble.export.fileExporter.enabled=true \ --set hubble.export.fileExporter.path="/var/run/cilium/hubble/export"
# Then sync to S3 using a sidecar or cronjobHands-On Exercise: Debug a Network Policy Issue
Section titled “Hands-On Exercise: Debug a Network Policy Issue”Objective: Use Hubble to identify and fix a broken network policy.
# Create test namespaceskubectl create namespace frontendkubectl create namespace backendkubectl create namespace database
# Deploy test applicationskubectl apply -f - <<EOFapiVersion: v1kind: Podmetadata: name: frontend namespace: frontend labels: app: frontendspec: containers: - name: curl image: curlimages/curl:latest command: ["/bin/sh", "-c", "sleep infinity"]---apiVersion: v1kind: Podmetadata: name: api namespace: backend labels: app: apispec: containers: - name: nginx image: nginx:alpine---apiVersion: v1kind: Servicemetadata: name: api namespace: backendspec: selector: app: api ports: - port: 80---apiVersion: v1kind: Podmetadata: name: postgres namespace: database labels: app: postgresspec: containers: - name: postgres image: postgres:15-alpine env: - name: POSTGRES_PASSWORD value: testpass---apiVersion: v1kind: Servicemetadata: name: postgres namespace: databasespec: selector: app: postgres ports: - port: 5432EOF
# Wait for podskubectl wait --for=condition=ready pod -l app=frontend -n frontend --timeout=60skubectl wait --for=condition=ready pod -l app=api -n backend --timeout=60skubectl wait --for=condition=ready pod -l app=postgres -n database --timeout=60sTask 1: Verify Connectivity Works
Section titled “Task 1: Verify Connectivity Works”# Test frontend -> apikubectl exec -n frontend frontend -- curl -s api.backend.svc.cluster.local
# Test api -> postgres (just DNS for now)kubectl exec -n backend api -- nslookup postgres.database.svc.cluster.localTask 2: Apply a Restrictive Network Policy
Section titled “Task 2: Apply a Restrictive Network Policy”# Apply a network policy that's too restrictivekubectl apply -f - <<EOFapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: api-policy namespace: backendspec: podSelector: matchLabels: app: api policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: tier: web # Note: frontend pod doesn't have this label ports: - port: 80EOFTask 3: Use Hubble to Identify the Problem
Section titled “Task 3: Use Hubble to Identify the Problem”# In one terminal: watch for dropped traffichubble observe --namespace backend --verdict DROPPED
# In another terminal: try to connectkubectl exec -n frontend frontend -- curl -s --max-time 5 api.backend.svc.cluster.local# This will timeoutYou should see output like:
TIMESTAMP SOURCE DESTINATION VERDICTJun 15 14:23:01.123 frontend/frontend backend/api DROPPED (Policy denied)Task 4: Get More Details
Section titled “Task 4: Get More Details”# Get detailed policy informationhubble observe --to-pod backend/api --verdict DROPPED --output json | head -1 | jq '.'
# Look for:# - traffic_direction# - policy_match_type# - drop_reason_descTask 5: Fix the Network Policy
Section titled “Task 5: Fix the Network Policy”# Option 1: Add the label to the frontend podkubectl label pod -n frontend frontend tier=web
# Option 2: Update the network policy to match the actual labelkubectl apply -f - <<EOFapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: api-policy namespace: backendspec: podSelector: matchLabels: app: api policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: frontend podSelector: matchLabels: app: frontend ports: - port: 80EOFTask 6: Verify the Fix
Section titled “Task 6: Verify the Fix”# Watch for successful traffichubble observe --namespace backend --verdict FORWARDED
# Test connectivity againkubectl exec -n frontend frontend -- curl -s api.backend.svc.cluster.local# Should succeed nowSuccess Criteria
Section titled “Success Criteria”- Identified that the network policy was blocking traffic
- Used Hubble to see the
DROPPEDverdict - Understood which policy caused the block
- Fixed the policy or labels to allow traffic
- Verified the fix with Hubble showing
FORWARDEDverdicts
Cleanup
Section titled “Cleanup”kubectl delete namespace frontend backend databaseQuestion 1
Section titled “Question 1”What is Hubble and what CNI does it require?
Show Answer
Hubble is an observability platform built on eBPF that requires Cilium as the CNI
Hubble is tightly integrated with Cilium and leverages the same eBPF infrastructure that Cilium uses for networking. It cannot be used with other CNIs.
Question 2
Section titled “Question 2”What command shows all dropped network traffic in Hubble?
Show Answer
hubble observe --verdict DROPPED
This filters the flow output to show only traffic that was dropped, which is invaluable for debugging network policy issues.
Question 3
Section titled “Question 3”What is Hubble Relay and why is it needed?
Show Answer
Hubble Relay aggregates network flow data from all nodes in the cluster
Each Cilium agent collects flows for its node. Hubble Relay provides a single endpoint to query flows across all nodes, enabling cluster-wide observability.
Question 4
Section titled “Question 4”How does Hubble help debug network policies?
Show Answer
Hubble shows exactly which policy allowed or denied each network flow
When traffic is dropped, Hubble shows the POLICY_DENIED verdict along with details about which policy matched. This eliminates guesswork when debugging policy issues.
Question 5
Section titled “Question 5”What is the difference between L4 and L7 observability in Hubble?
Show Answer
L4 shows TCP/UDP connection-level flows; L7 shows HTTP/gRPC request-level details
L4 observability is automatic. L7 observability requires Cilium to be configured with L7 network policies, which enables parsing of HTTP traffic including method, path, and status codes.
Question 6
Section titled “Question 6”How do you enable Hubble metrics for Prometheus?
Show Answer
Set hubble.metrics.enabled with the desired metrics categories in the Cilium Helm values
Example: --set hubble.metrics.enabled="{dns,drop,tcp,flow,icmp,http}" enables metrics for those categories.
Question 7
Section titled “Question 7”What does the Hubble UI Service Map show?
Show Answer
A real-time visual graph of all service-to-service connections in the cluster
The service map shows pods/services as nodes and connections as edges, making it easy to understand traffic patterns and identify unexpected communication.
Question 8
Section titled “Question 8”How can you filter Hubble output to show only HTTP 500 errors?
Show Answer
hubble observe --http-status 500
This requires L7 visibility to be enabled. You can also use ranges like --http-status 5xx for all server errors.
Key Takeaways
Section titled “Key Takeaways”- Hubble is Cilium’s observability layer - requires Cilium CNI
- eBPF provides kernel-level visibility - see all traffic without sidecars
- Verdicts show policy decisions - know exactly why traffic was dropped
- Hubble CLI is powerful - filter by namespace, pod, protocol, verdict
- Service maps visualize dependencies - see cluster topology in real-time
- L7 visibility is optional - configure Cilium for HTTP-level details
- Metrics enable alerting - export to Prometheus for dashboards
- Relay enables cluster-wide queries - aggregate flows from all nodes
- Essential for network policy debugging - no more guessing
- Low overhead - eBPF makes it production-safe
Further Reading
Section titled “Further Reading”- Hubble Documentation - Official Cilium docs
- Cilium Network Policies - Understanding policy verdicts
- Hubble Metrics Reference - All available metrics
- eBPF.io - Understanding the underlying technology
Next Module
Section titled “Next Module”Continue to Module 1.8: Coroot to learn about auto-instrumentation observability platforms, or move to Module 4.5: Tetragon to explore eBPF-based security.