K8s Cilium eBPF Network Policy: 5 Core Patterns for Zero-Trust Pod Security
Kubernetes networking in 2026 has fully entered the eBPF era. Cilium, as a CNCF graduated project, has become the de facto standard for zero-trust Pod security with its kernel-level programmable networking capabilities. From traditional iptables to eBPF dataplane, from L3/L4 network policies to L7 application-layer filtering, from single-cluster to Cluster Mesh multi-cluster networking — Cilium is redefining the boundaries of cloud-native networking. This article dives deep into 5 core production patterns, taking you from installation to production-grade deployment, fully mastering Cilium eBPF network policies.
Core Concepts
| Concept | Description | Traditional Comparison |
|---|---|---|
| eBPF | Kernel programmable sandbox, extending networking without modifying kernel source | iptables rule chains, O(n) matching as rules grow |
| Cilium | eBPF-based K8s CNI plugin, providing networking, security, observability | Calico/Flannel, L3/L4 policies only |
| Identity Label | Security identity based on Labels, not IP addresses | IP-based NetworkPolicy |
| L7 Policy | HTTP/gRPC application-layer filtering, precise to API paths | L4 port-level filtering only |
| Cluster Mesh | Multi-cluster network interconnection, cross-cluster Pod direct communication | VPN/gateway forwarding |
| Hubble | Cilium network observability platform, real-time traffic visualization | tcpdump/Wireshark manual packet capture |
Problem Analysis: 5 Pain Points of Traditional K8s Network Policies
Pain Point 1: iptables Performance Bottleneck — In large-scale clusters, iptables rules can reach tens of thousands. Every rule change triggers a full replacement, causing severe network latency jitter.
Pain Point 2: Insufficient L3/L4 Policy Granularity — Native NetworkPolicy can only control port-level access, unable to distinguish between GET /api/users and DELETE /api/users.
Pain Point 3: Fragile IP-based Security Policies — Pod IPs change after recreation, IP-based firewall rules instantly become invalid, making zero-trust impossible.
Pain Point 4: Fragmented Multi-cluster Networking — Cross-cluster service communication relies on Ingress/gateway forwarding, with high latency and difficult policy unification.
Pain Point 5: Network Troubleshooting Black Box — Pod communication failures can only be diagnosed by tcpdump hop-by-hop, lacking end-to-end traffic visualization.
Pattern 1: Cilium Installation and eBPF Networking Principles
eBPF Networking Principles
eBPF programs are attached to kernel networking hooks (xdp, tc, cgroup, etc.), processing packets before they reach the protocol stack, avoiding iptables rule chain traversal overhead:
Packet In → XDP(eBPF) → tc ingress(eBPF) → Protocol Stack → tc egress(eBPF) → Out
↓ ↓ ↓
DDoS Protection Policy Match/Routing Policy Match/NAT
Helm Installation (Replacing kube-proxy)
# cilium-values.yaml
# Cilium Helm installation config, kube-proxy replacement mode
kubeProxyReplacement: true
operator:
replicas: 2
# eBPF map sizes (large-scale cluster tuning)
bpf:
mapDynamicSizeRatio: 0.0025
lbMapMax: 65536
ctMapMax: 524288
# Auto-detect node networking
autoDirectNodeRoutes: true
tunnel: vxlan
# Identity allocation mode
identityAllocationMode: kvstore
# Monitoring and observability
hubble:
enabled: true
listenAddress: ":4244"
metrics:
enabled:
- dns
- drop
- tcp
- flow
- port-distribution
- http
relay:
enabled: true
replicas: 2
ui:
enabled: true
# Resource limits
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
# Security context
securityContext:
capabilities:
add:
- NET_ADMIN
- SYS_MODULE
#!/bin/bash
# install-cilium.sh
# Cilium installation script
set -euo pipefail
CLUSTER_NAME="prod-cluster"
NAMESPACE="kube-system"
echo "=== Step 1: Add Cilium Helm repository ==="
helm repo add cilium https://helm.cilium.io/
helm repo update
echo "=== Step 2: Get API Server address ==="
API_SERVER_IP=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}')
API_SERVER_PORT=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}')
echo "API Server: ${API_SERVER_IP}:${API_SERVER_PORT}"
echo "=== Step 3: Install Cilium ==="
helm install cilium cilium/cilium \
--namespace ${NAMESPACE} \
--values cilium-values.yaml \
--set kubeProxyReplacement=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--wait
echo "=== Step 4: Wait for Cilium readiness ==="
kubectl -n ${NAMESPACE} rollout status ds/cilium --timeout=300s
kubectl -n ${NAMESPACE} rollout status deploy/cilium-operator --timeout=120s
echo "=== Step 5: Verify eBPF program loading ==="
kubectl -n ${NAMESPACE} exec ds/cilium -- cilium bpf lb list
kubectl -n ${NAMESPACE} exec ds/cilium -- cilium status
echo "=== Step 6: Verify kube-proxy replacement ==="
kubectl -n ${NAMESPACE} exec ds/cilium -- cilium service list
echo "=== Step 7: Status check ==="
cilium status --wait
echo "✅ Cilium installation complete!"
Verify eBPF Dataplane
#!/bin/bash
# verify-ebpf.sh
# Verify eBPF dataplane is working correctly
echo "=== Check Cilium eBPF programs ==="
kubectl -n kube-system exec ds/cilium -- cilium bpf tunnel list
kubectl -n kube-system exec ds/cilium -- cilium bpf ct list global
echo "=== Check identity mapping ==="
kubectl -n kube-system exec ds/cilium -- cilium identity list
echo "=== Network connectivity test ==="
kubectl run test-net --image=cilium/cilium:latest --restart=Never -- sleep infinity
kubectl exec test-net -- curl -s https://kubernetes.default.svc.cluster.local:443/api/v1/namespaces
echo "=== Bandwidth benchmark ==="
kubectl run iperf3-server --image=networkstatic/iperf3 --restart=Never -- iperf3 -s
kubectl run iperf3-client --image=networkstatic/iperf3 --restart=Never -- sleep infinity
CLIENT_POD=$(kubectl get pods -l run=iperf3-client -o jsonpath='{.items[0].metadata.name}')
SERVER_IP=$(kubectl get pod iperf3-server -o jsonpath='{.status.podIP}')
kubectl exec ${CLIENT_POD} -- iperf3 -c ${SERVER_IP} -t 10 -P 4
echo "✅ eBPF dataplane verification complete!"
Pattern 2: L3/L4 Network Policies and Identity Labels
Cilium Identity Label Mechanism
Cilium uses Labels to compute security identities (Identity) rather than relying on IP addresses. Pods with the same Labels share the same Identity, and policy matching is based on Identity rather than IP:
Pod(app=api, env=prod) → Identity: 1001 → Policy allows Identity:1001 → Identity:2001
Pod(app=web, env=prod) → Identity: 2001
Basic L3/L4 Network Policies
# cilium-l3-l4-policy.yaml
# L3/L4 network policy: Zero-trust access control based on identity labels
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
description: "API service only allows frontend and internal service access, denies all other traffic"
endpointSelector:
matchLabels:
app: api-server
env: production
ingress:
# Rule 1: Allow frontend Pods to access API port 8080
- fromEndpoints:
- matchLabels:
app: web-frontend
env: production
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/api/v1/.*"
- method: POST
path: "/api/v1/.*"
# Rule 2: Allow internal microservices to access gRPC port
- fromEndpoints:
- matchLabels:
app: internal-service
env: production
toPorts:
- ports:
- port: "9090"
protocol: TCP
# Rule 3: Allow Prometheus monitoring scrape
- fromEndpoints:
- matchLabels:
app.kubernetes.io/name: prometheus
toPorts:
- ports:
- port: "9090"
protocol: TCP
endPort: 9091
egress:
# Allow database access
- toEndpoints:
- matchLabels:
app: postgres
env: production
toPorts:
- ports:
- port: "5432"
protocol: TCP
# Allow DNS resolution
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
# Allow external API calls
- toFQDNs:
- matchName: "api.stripe.com"
- matchPattern: "*.amazonaws.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
---
# Default deny policy (zero-trust foundation)
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: default-deny-all
spec:
description: "Default deny all ingress traffic, zero-trust baseline policy"
endpointSelector: {}
ingressDeny:
- fromRequires:
- {}
---
# Namespace isolation policy
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: namespace-isolation
spec:
description: "Namespace-level isolation, only allow same-namespace communication"
endpointSelector:
matchLabels: {}
ingress:
- fromEndpoints:
- matchLabels: {}
Entity-based Network Policies
# entity-based-policy.yaml
# Entity-based network policy: Control intra-cluster and external traffic
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: entity-policy
spec:
description: "Control network access between Pods and cluster entities"
endpointSelector:
matchLabels:
app: api-server
ingress:
# Allow traffic from within the cluster
- fromEntities:
- cluster
- host
- remote-node
egress:
# Allow access to outside the cluster
- toEntities:
- world
# Allow access to K8s API Server
- toEntities:
- kube-apiserver
Pattern 3: L7 Application-Layer Policies (HTTP/gRPC Filtering)
HTTP-Layer Fine-Grained Access Control
# cilium-l7-policy.yaml
# L7 application-layer policy: HTTP/gRPC fine-grained filtering
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-api-policy
namespace: production
spec:
description: "L7 policy: HTTP method + path precise control, implementing API-level zero-trust"
endpointSelector:
matchLabels:
app: api-server
env: production
ingress:
- fromEndpoints:
- matchLabels:
app: web-frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
# Allow read-only APIs
- method: GET
path: "/api/v1/users(/.*)?"
- method: GET
path: "/api/v1/products(/.*)?"
- method: GET
path: "/api/v1/orders(/.*)?"
# Allow order creation
- method: POST
path: "/api/v1/orders"
# Deny delete operations (requests not in this list will be denied)
---
# gRPC method-level filtering
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: grpc-policy
namespace: production
spec:
description: "gRPC method-level access control"
endpointSelector:
matchLabels:
app: order-service
ingress:
- fromEndpoints:
- matchLabels:
app: api-gateway
toPorts:
- ports:
- port: "50051"
protocol: TCP
rules:
http:
- method: POST
path: "/order.OrderService/GetOrder"
- method: POST
path: "/order.OrderService/ListOrders"
- method: POST
path: "/order.OrderService/CreateOrder"
---
# HTTP Header filtering policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: header-filter-policy
namespace: production
spec:
description: "HTTP Header-based access control"
endpointSelector:
matchLabels:
app: internal-api
ingress:
- fromEndpoints:
- matchLabels:
app: gateway
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/internal/.*"
headers:
- "X-Internal-Token: ^secret-token-.*$"
---
# Kafka protocol-aware policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: kafka-policy
namespace: production
spec:
description: "Kafka topic-level access control"
endpointSelector:
matchLabels:
app: kafka-broker
ingress:
- fromEndpoints:
- matchLabels:
app: order-processor
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
- role: produce
topic: orders
- role: consume
topic: orders
- fromEndpoints:
- matchLabels:
app: analytics
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
- role: consume
topic: orders
L7 Policy Verification Script
#!/bin/bash
# verify-l7-policy.sh
# Verify L7 application-layer policies
echo "=== Test HTTP GET allowed ==="
kubectl exec deploy/web-frontend -- curl -s -o /dev/null -w "%{http_code}" http://api-server:8080/api/v1/users
# Expected: 200
echo ""
echo "=== Test HTTP DELETE denied ==="
kubectl exec deploy/web-frontend -- curl -s -o /dev/null -w "%{http_code}" -X DELETE http://api-server:8080/api/v1/users/123
# Expected: 403
echo ""
echo "=== Test access without Header denied ==="
kubectl exec deploy/gateway -- curl -s -o /dev/null -w "%{http_code}" http://internal-api:8080/internal/config
# Expected: 403
echo ""
echo "=== Test access with Token Header allowed ==="
kubectl exec deploy/gateway -- curl -s -o /dev/null -w "%{http_code}" -H "X-Internal-Token: secret-token-abc" http://internal-api:8080/internal/config
# Expected: 200
echo ""
echo "=== Check Cilium L7 policy status ==="
kubectl -n kube-system exec ds/cilium -- cilium policy get
kubectl -n kube-system exec ds/cilium -- cilium policy select
echo "✅ L7 policy verification complete!"
Pattern 4: Cluster Mesh Multi-Cluster Networking
Cluster Mesh Architecture
Cluster A (us-west) Cluster B (eu-central)
┌─────────────────┐ ┌─────────────────┐
│ Pod: api-server │◄────────►│ Pod: api-server │
│ Identity: 1001 │ │ Identity: 1001 │
│ Service: global │ │ Service: global │
└─────────────────┘ └─────────────────┘
│ │
└──────── etcd sync ─────────┘
Cluster Mesh Configuration
# cluster-mesh-config.yaml
# Cluster Mesh multi-cluster network configuration
# Cluster A: us-west
apiVersion: v1
kind: ConfigMap
metadata:
name: cilium-clustermesh
namespace: kube-system
data:
cluster-id: "1"
cluster-name: "us-west"
---
# Cluster B: eu-central
apiVersion: v1
kind: ConfigMap
metadata:
name: cilium-clustermesh
namespace: kube-system
data:
cluster-id: "2"
cluster-name: "eu-central"
---
# Global Service (cross-cluster load balancing)
apiVersion: v1
kind: Service
metadata:
name: global-api-server
namespace: production
annotations:
service.cilium.io/global: "true"
service.cilium.io/affinity: "local"
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
selector:
app: api-server
---
# Cross-cluster network policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: cross-cluster-policy
namespace: production
spec:
description: "Cross-cluster network policy: Allow us-west and eu-central mutual access"
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: api-server
io.cilium.k8s.policy.cluster: us-west
- matchLabels:
app: api-server
io.cilium.k8s.policy.cluster: eu-central
toPorts:
- ports:
- port: "8080"
protocol: TCP
#!/bin/bash
# setup-cluster-mesh.sh
# Cluster Mesh setup script
set -euo pipefail
CLUSTER_A="us-west"
CLUSTER_B="eu-central"
CONTEXT_A="kind-${CLUSTER_A}"
CONTEXT_B="kind-${CLUSTER_B}"
echo "=== Step 1: Enable Cluster Mesh on both clusters ==="
kubectl --context ${CONTEXT_A} -n kube-system exec ds/cilium -- \
cilium clustermesh enable --cluster-id 1 --cluster-name ${CLUSTER_A}
kubectl --context ${CONTEXT_B} -n kube-system exec ds/cilium -- \
cilium clustermesh enable --cluster-id 2 --cluster-name ${CLUSTER_B}
echo "=== Step 2: Wait for Cluster Mesh API readiness ==="
kubectl --context ${CONTEXT_A} -n kube-system rollout status deploy/clustermesh-apiserver --timeout=120s
kubectl --context ${CONTEXT_B} -n kube-system rollout status deploy/clustermesh-apiserver --timeout=120s
echo "=== Step 3: Connect the two clusters ==="
kubectl --context ${CONTEXT_A} -n kube-system exec ds/cilium -- \
cilium clustermesh connect --destination-context ${CONTEXT_B}
echo "=== Step 4: Verify cluster connection status ==="
kubectl --context ${CONTEXT_A} -n kube-system exec ds/cilium -- \
cilium clustermesh status
kubectl --context ${CONTEXT_B} -n kube-system exec ds/cilium -- \
cilium clustermesh status
echo "=== Step 5: Test cross-cluster service discovery ==="
kubectl --context ${CONTEXT_A} run test-cross-cluster \
--image=cilium/cilium:latest --restart=Never -- \
curl -s http://global-api-server.production.svc.cluster.local:8080/health
echo "=== Step 6: Verify global Service ==="
kubectl --context ${CONTEXT_A} get svc global-api-server -n production -o yaml
kubectl --context ${CONTEXT_B} get svc global-api-server -n production -o yaml
echo "✅ Cluster Mesh setup complete!"
Cross-Cluster Failover Testing
#!/bin/bash
# test-cross-cluster-failover.sh
# Cross-cluster failover testing
CLUSTER_A="us-west"
CLUSTER_B="eu-central"
CONTEXT_A="kind-${CLUSTER_A}"
CONTEXT_B="kind-${CLUSTER_B}"
echo "=== Baseline test: Normal cross-cluster access ==="
for i in $(seq 1 10); do
RESULT=$(kubectl --context ${CONTEXT_A} exec deploy/test-client -- \
curl -s http://global-api-server.production.svc.cluster.local:8080/cluster-name)
echo "Request ${i}: ${RESULT}"
done
echo ""
echo "=== Simulate cluster B failure ==="
kubectl --context ${CONTEXT_B} scale deploy api-server -n production --replicas=0
echo "=== Verify traffic auto-switches to cluster A ==="
for i in $(seq 1 10); do
RESULT=$(kubectl --context ${CONTEXT_A} exec deploy/test-client -- \
curl -s http://global-api-server.production.svc.cluster.local:8080/cluster-name)
echo "Failover Request ${i}: ${RESULT}"
done
echo "=== Restore cluster B ==="
kubectl --context ${CONTEXT_B} scale deploy api-server -n production --replicas=3
echo "✅ Failover testing complete!"
Pattern 5: Hubble Observability and Network Tracing
Hubble Deployment and Configuration
# hubble-values.yaml
# Hubble observability configuration
hubble:
enabled: true
listenAddress: ":4244"
metrics:
enabled:
- dns:query
- drop
- tcp
- flow
- port-distribution
- http:method;path;status
- icmp
serviceMonitor:
enabled: true
dashboards:
enabled: true
namespace: monitoring
relay:
enabled: true
replicas: 2
rollOutPods: true
ui:
enabled: true
replicas: 1
rollOutPods: true
ingress:
enabled: true
className: nginx
hosts:
- hubble.example.com
tls:
secretName: hubble-tls
Hubble CLI Network Tracing
#!/bin/bash
# hubble-observability.sh
# Hubble observability and network tracing
echo "=== Real-time traffic monitoring ==="
hubble observe --since 1m --output json | jq -r '
select(.source.namespace == "production") |
"\(.timestamp) \(.source.pod_name) → \(.destination.pod_name) \(.event.type) \(.l7.protocol // "L4") \(.l7.method // "") \(.l7.path // "") \(.response_status // "")"
'
echo ""
echo "=== Trace traffic for a specific Pod ==="
hubble observe --pod api-server-7d9f8b6c4-x2k1p --since 5m
echo ""
echo "=== Detect denied traffic ==="
hubble observe --since 10m --type trace --verdict DROPPED | head -50
echo ""
echo "=== HTTP traffic analysis ==="
hubble observe --since 5m --protocol http --output json | jq -r '
"\(.source.pod_name) → \(.destination.pod_name) [\(.l7.method)] \(.l7.path) → \(.l7.response_code)"
' | sort | uniq -c | sort -rn | head -20
echo ""
echo "=== DNS query monitoring ==="
hubble observe --since 5m --protocol dns --output json | jq -r '
"\(.source.pod_name) → \(.l7.dns.query) \(.l7.dns.rcode // "OK")"
' | sort | uniq -c | sort -rn | head -20
echo ""
echo "=== Network latency analysis ==="
hubble observe --since 5m --type trace --output json | jq -r '
select(.latency_ns != null) |
"\(.source.pod_name) → \(.destination.pod_name) latency: \(.latency_ns / 1000000)ms"
' | sort -t: -k2 -n | tail -20
echo "✅ Hubble observability analysis complete!"
Hubble Prometheus Metrics
# hubble-prometheus-rules.yaml
# Hubble alerting rules
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: hubble-alerts
namespace: monitoring
spec:
groups:
- name: hubble-network
rules:
# High drop rate alert
- alert: CiliumHighDropRate
expr: |
rate(hubble_drop_total{verdict="DROPPED"}[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "Cilium detected high drop rate"
description: "Pod {{ $labels.source_pod }} in namespace {{ $labels.namespace }} drop rate exceeds 10/s"
# DNS resolution failure alert
- alert: CiliumDNSFailures
expr: |
rate(hubble_dns_responses_total{rcode="NXDOMAIN"}[5m]) > 5
for: 5m
labels:
severity: warning
annotations:
summary: "Abnormal DNS resolution failure rate"
description: "DNS NXDOMAIN responses in namespace {{ $labels.namespace }} exceed 5/s"
# TCP connection reset alert
- alert: CiliumTCPResets
expr: |
rate(hubble_tcp_flags_total{flag="RST"}[5m]) > 50
for: 5m
labels:
severity: critical
annotations:
summary: "Abnormal TCP RST packets"
description: "TCP RST packets in namespace {{ $labels.namespace }} exceed 50/s"
# Cross-cluster latency alert
- alert: CiliumCrossClusterLatency
expr: |
histogram_quantile(0.99, rate(hubble_flows_processed_duration_seconds_bucket{source_cluster!=""}[5m])) > 0.5
for: 10m
labels:
severity: warning
annotations:
summary: "High cross-cluster network latency"
description: "P99 latency exceeds 500ms"
Pitfall Guide
Pitfall 1: Pods Cannot Communicate After Cilium Installation
# ❌ Wrong: Incorrect tunnel mode configuration, incompatible node networking
tunnel: disabled
autoDirectNodeRoutes: false
# ✅ Correct: Choose tunnel mode based on network environment
# Cloud environment (VPC supports routing)
tunnel: disabled
autoDirectNodeRoutes: true
directRoutingSkipUnreachable: true
# General environment (VXLAN overlay)
tunnel: vxlan
tunnelPort: 8473
Pitfall 2: L7 Policies Not Taking Effect
# ❌ Wrong: L7 policy missing toPorts definition, Cilium cannot inject proxy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: bad-l7-policy
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
rules:
http:
- method: GET
path: "/api/.*"
# ✅ Correct: L7 rules must be defined under toPorts
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: good-l7-policy
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/api/.*"
Pitfall 3: Cluster Mesh Connection Failure
# ❌ Wrong: etcd certificates not properly synced
cilium clustermesh connect --destination-context other-cluster
# ✅ Correct: Ensure etcd certificates are correct first, then connect
# Check Cluster Mesh API Server status
kubectl -n kube-system get deploy/clustermesh-apiserver
kubectl -n kube-system logs deploy/clustermesh-apiserver
# Ensure certificate Secrets exist
kubectl -n kube-system get secret clustermesh-apiserver-server-certs
kubectl -n kube-system get secret clustermesh-apiserver-remote-certs
# Use the correct connection method
cilium clustermesh connect \
--destination-context other-cluster \
--destination-name other-cluster
Pitfall 4: Hubble UI Not Showing Traffic
# ❌ Wrong: Hubble Relay cannot connect to Cilium Agent
hubble:
relay:
enabled: true
# Missing dialTimeout config causing timeout
# ✅ Correct: Configure Hubble Relay timeout and retry
hubble:
relay:
enabled: true
dialTimeout: "5s"
retryTimeout: "30s"
maxFlows: 10000
sortBufferLenMax: 1000
sortBufferFlushInterval: "1s"
port: 4245
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Pitfall 5: eBPF Program Loading Failure
# ❌ Wrong: Incompatible kernel version, installing directly
helm install cilium cilium/cilium
# ✅ Correct: Check kernel compatibility first
# Check kernel version (need >= 5.4, recommended >= 5.10)
uname -r
# Check eBPF feature support
kubectl -n kube-system exec ds/cilium -- cilium-dbg features
# If kernel version is low, enable compatibility mode
helm install cilium cilium/cilium \
--set bpf.preallocateMaps=false \
--set bpf.tproxy=false \
--set hostFirewall.enabled=false
# Check eBPF program loading status
kubectl -n kube-system exec ds/cilium -- cilium-dbg bpf lb list
kubectl -n kube-system exec ds/cilium -- cilium-dbg status
Error Troubleshooting Table
| Error Symptom | Possible Cause | Diagnostic Command | Solution |
|---|---|---|---|
| Pods cannot communicate cross-node | Tunnel misconfiguration | cilium bpf tunnel list |
Check tunnel mode, ensure VXLAN port 8473 is open |
| Cilium Pod CrashLoopBackOff | Kernel version incompatible | dmesg | grep -i bpf |
Upgrade kernel to 5.10+ or enable compatibility mode |
| L7 policies not effective | Missing toPorts definition | cilium policy get |
L7 rules must be nested under toPorts.ports.rules |
| Cluster Mesh connection timeout | etcd certificate expired | kubectl logs -n kube-system deploy/clustermesh-apiserver |
Regenerate certificates: cilium clustermesh enable |
| Hubble no traffic data | Relay cannot connect to Agent | kubectl logs -n kube-system deploy/hubble-relay |
Check dialTimeout and Agent port 4244 |
| DNS resolution failure | eBPF DNS proxy abnormal | cilium bpf ct list global | grep 53 |
Check DNS policy, ensure kube-dns labels are correct |
| Network latency spike | eBPF map full | cilium bpf ct list global | wc -l |
Increase ctMapMax, enable GC |
| Service unreachable | kube-proxy residual conflict | iptables -L -n | grep KUBE |
Thoroughly clean iptables rules, confirm kube-proxy removed |
| Identity allocation conflict | KVStore backend abnormal | cilium identity list |
Check etcd connection, restart cilium-operator |
| Cross-cluster Pod unreachable | Global Service not configured | kubectl get svc -o yaml | grep global |
Add service.cilium.io/global: "true" annotation |
Advanced Optimization
1. eBPF Map Tuning
# Large-scale cluster eBPF Map configuration
bpf:
mapDynamicSizeRatio: 0.0025
ctMapMax: 524288 # Connection tracking table
ctTcpMax: 262144 # TCP connection tracking
ctAnyMax: 262144 # Non-TCP connection tracking
lbMapMax: 65536 # Load balancing map
lbServiceMapMax: 65536
lbBackendMapMax: 65536
natMapMax: 524288 # NAT map
neighMapMax: 524288 # Neighbor table
policyMapMax: 16384 # Policy map
fragmentsMapMax: 8192 # Fragment map
2. Bandwidth Management (EDT)
# eBPF-based bandwidth management
bandwidthManager:
enabled: true
bbr: true # Enable BBR congestion control
# Set bandwidth limits for Pods
kubectl annotate pod api-server-xxx \
kubernetes.io/egress-bandwidth=100M \
kubernetes.io/ingress-bandwidth=100M
3. Big TCP Optimization
# Large-scale TCP optimization (kernel 5.19+)
bpf:
tcpRto: 100ms # TCP retransmission timeout
tproxy: true
kubeProxyReplacement:
true
hostPort:
enabled: true
externalIPs:
enabled: true
nodePort:
enabled: true
hostLegacyRouting:
enabled: false
4. eBPF Host Routing
# Host routing optimization
bpf:
hostLegacyRouting: false # Use eBPF instead of host routing
lbExternalClusterIP: true
autoDirectNodeRoutes: true
5. Security Hardening
# Cilium security hardening configuration
securityContext:
capabilities:
add:
- NET_ADMIN
- SYS_MODULE
drop:
- ALL
seccompProfile:
type: RuntimeDefault
readOnlyRootFilesystem: true
# Enable encryption
encryption:
enabled: true
type: wireguard
nodeEncryption: true
Comparison Table
| Feature | Cilium eBPF | Calico | Flannel | Weave |
|---|---|---|---|---|
| Dataplane | eBPF | iptables/eBPF | VXLAN | VXLAN |
| L3/L4 Policies | ✅ | ✅ | ❌ | ❌ |
| L7 Policies | ✅ HTTP/gRPC/Kafka | ❌ | ❌ | ❌ |
| Observability | ✅ Hubble | ❌ | ❌ | ❌ |
| Cluster Mesh | ✅ | ❌ | ❌ | ❌ |
| kube-proxy Replacement | ✅ | ❌ | ❌ | ❌ |
| Bandwidth Management | ✅ EDT/BBR | ❌ | ❌ | ❌ |
| WireGuard Encryption | ✅ | ✅ | ❌ | ✅ |
| FQDN Policies | ✅ | ❌ | ❌ | ❌ |
| Large-Scale Performance | O(1) | O(n) | O(n) | O(n) |
| Kernel Requirement | ≥5.4 | ≥4.9 | ≥3.10 | ≥3.10 |
💡 Summary: Cilium eBPF network policies represent the future direction of K8s network security. From L3/L4 identity labels to L7 application-layer filtering, from single-cluster zero-trust to Cluster Mesh multi-cluster interconnection, from Hubble real-time observability to eBPF performance optimization — 5 core patterns build a complete cloud-native network security system. Remember: Zero-trust is not a product, but an architectural philosophy, and Cilium is the best tool to implement it.
Online Tools Recommendation
- JSON Formatter — Format Cilium policy JSON output, troubleshoot policy configurations
- cURL to Code — Convert Hubble API queries to code, integrate observability
- Hash Calculator — Calculate policy signature hashes, verify configuration integrity
Try these browser-local tools — no sign-up required →