Cilium
Cilium is an open-source networking, observability, and security solution for Kubernetes that uses eBPF (extended Berkeley Packet Filter) to provide high-performance networking and deep visibility into application behavior without requiring application changes.
Installation
Prerequisites
# Check kernel version (5.4+ recommended, 4.19+ minimum)
uname -r
# Install Cilium CLI
CILIUM_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.gz
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
# macOS
brew install cilium-cli
Install via Helm
# Add Helm repository
helm repo add cilium https://helm.cilium.io/
helm repo update
# Install Cilium (replace <K8S_API_SERVER_IP> with your API server IP)
helm install cilium cilium/cilium --version 1.16.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost=<K8S_API_SERVER_IP> \
--set k8sServicePort=6443
# Install with Hubble observability enabled
helm install cilium cilium/cilium --version 1.16.0 \
--namespace kube-system \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
# Verify installation
cilium status --wait
cilium connectivity test
Install Hubble CLI
# Linux
HUBBLE_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.gz
sudo tar xzvfC hubble-linux-amd64.tar.gz /usr/local/bin
# macOS
brew install hubble
# Verify
hubble version
Configuration
Helm Values Reference
# values.yaml — common configuration options
kubeProxyReplacement: true # Replace kube-proxy with Cilium
tunnel: vxlan # Encapsulation mode: vxlan, geneve, or disabled
ipv4:
enabled: true
ipv6:
enabled: false
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
metrics:
enabled:
- dns
- drop
- tcp
- flow
- icmp
- http
encryption:
enabled: true
type: wireguard # wireguard or ipsec
loadBalancer:
algorithm: maglev # maglev or random
bandwidthManager:
enabled: true # BBR-based bandwidth management
bpf:
masquerade: true
lbMapMax: 65536
operator:
replicas: 2
ConfigMap Patching
# Edit Cilium ConfigMap directly
kubectl edit configmap -n kube-system cilium-config
# Common config keys
# enable-policy: default
# tunnel: vxlan
# auto-direct-node-routes: "true"
# enable-bandwidth-manager: "true"
Core Commands
| Command | Description |
|---|---|
cilium status | Show Cilium status across all nodes |
cilium status --wait | Wait until Cilium is fully ready |
cilium connectivity test | Run connectivity test suite |
cilium config view | View current Cilium configuration |
cilium config set <key> <val> | Update a configuration value |
cilium hubble enable | Enable Hubble observability |
cilium hubble port-forward & | Forward Hubble relay port locally |
hubble observe | Stream live network flows |
hubble observe --pod <name> | Filter flows by pod name |
hubble observe --namespace <ns> | Filter flows by namespace |
hubble observe --verdict DROPPED | Show only dropped packets |
hubble status | Show Hubble status |
cilium node list | List Cilium-managed nodes |
cilium endpoint list | List all Cilium endpoints |
cilium endpoint get <id> | Get details for an endpoint |
cilium policy get | Show active network policies |
cilium bpf lb list | List eBPF load balancer entries |
cilium bpf nat list | List eBPF NAT table entries |
cilium monitor | Monitor eBPF events in real time |
cilium debuginfo | Collect debug information |
Advanced Usage
Network Policies (L3/L4)
# Allow only frontend pods to reach backend on port 8080
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
L7 HTTP Policy
# Allow only GET /api requests from frontend
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: l7-http-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: GET
path: /api/.*
DNS-Based Policy
# Allow pods to reach external APIs by domain name
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: allow-external-api
spec:
endpointSelector:
matchLabels:
app: worker
egress:
- toFQDNs:
- matchName: "api.stripe.com"
- matchPattern: "*.amazonaws.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
Cluster Mesh
# Enable cluster mesh on cluster 1
cilium clustermesh enable --context cluster1
cilium clustermesh status --context cluster1
# Enable on cluster 2
cilium clustermesh enable --context cluster2
# Connect clusters
cilium clustermesh connect \
--context cluster1 \
--destination-context cluster2
# Verify mesh connectivity
cilium clustermesh status
WireGuard Encryption
# Enable transparent encryption
helm upgrade cilium cilium/cilium \
--reuse-values \
--set encryption.enabled=true \
--set encryption.type=wireguard \
--set encryption.nodeEncryption=true
# Verify encryption
cilium encrypt status
Observability with Hubble
# Forward Hubble relay
cilium hubble port-forward &
# Watch all flows in namespace
hubble observe --namespace production --follow
# Show HTTP flows
hubble observe -t l7 --protocol http --follow
# Count flows by source/destination
hubble observe --last 1000 --output json | \
jq -r '.flow | "\(.source.namespace)/\(.source.pod_name) -> \(.destination.namespace)/\(.destination.pod_name)"' | \
sort | uniq -c | sort -rn | head -20
# Open Hubble UI
cilium hubble ui
Common Workflows
Diagnose Network Policy Drop
# See dropped packets in real time
hubble observe --verdict DROPPED --follow
# Check endpoint policy
cilium endpoint list
cilium endpoint get <ENDPOINT_ID>
# View policy for a specific pod
kubectl exec -n kube-system ds/cilium -- \
cilium endpoint get $(cilium endpoint list | grep <POD_IP> | awk '{print $1}')
Debugging Connectivity
# Run built-in connectivity tests
cilium connectivity test
# Test specific pod-to-pod path
cilium connectivity test \
--test pod-to-pod \
--namespace connectivity-check
# Check BPF datapath for a service
cilium bpf lb list | grep <SERVICE_CLUSTER_IP>
# Trace packet path
cilium monitor --type trace --from-pod <namespace/pod-name>
Upgrading Cilium
# Check current version
cilium version
# Upgrade via Helm (rolling restart)
helm upgrade cilium cilium/cilium \
--version 1.16.1 \
--namespace kube-system \
--reuse-values
# Monitor rollout
kubectl -n kube-system rollout status daemonset/cilium
cilium status --wait
Bandwidth Management
# Enable bandwidth manager with BBR
helm upgrade cilium cilium/cilium \
--reuse-values \
--set bandwidthManager.enabled=true \
--set bandwidthManager.bbr=true
# Set egress bandwidth limit via annotation
kubectl annotate pod my-pod \
kubernetes.io/egress-bandwidth=100M \
kubernetes.io/ingress-bandwidth=100M
Tips and Best Practices
- Use
kubeProxyReplacement=truefor best performance — Cilium fully replaces kube-proxy using eBPF, reducing latency and CPU overhead. - Enable Hubble from the start — retrofitting observability is harder; deploy Hubble relay and UI with your initial install.
- Prefer CiliumNetworkPolicy over standard NetworkPolicy — it supports L7 rules, DNS-based egress, and richer selectors.
- Start with audit/default-allow mode — before enforcing L7 policies, watch Hubble flows to understand traffic patterns.
- Use cluster mesh for multi-cluster service discovery — combine with
ServiceExportsto share services across clusters without extra ingress. - Pin the kernel version — eBPF features vary by kernel; lock your node image to a tested kernel for reproducible behavior.
- Monitor
cilium_drop_count_totalin Prometheus — unexpected drops surface policy misconfigurations early. - Run
cilium connectivity testafter every upgrade — it validates datapath correctness end-to-end. - Use
--set bpf.lbMapMaxcarefully — the default 65536 handles most clusters; increase for very large service counts. - Label your namespaces — Cilium policies match on
k8s:io.kubernetes.pod.namespace; consistent labeling simplifies policy authoring.