Set up Cilium as your Kubernetes CNI plugin with advanced eBPF networking, load balancing, and network security policies. Includes Hubble observability for complete network visibility.
Prerequisites
- Existing Kubernetes cluster with admin access
- kubectl configured and working
- Linux kernel 4.9+ with eBPF support
- At least 2 CPU cores and 4GB RAM per node
What this solves
Cilium provides advanced networking, security, and observability for Kubernetes clusters using eBPF technology. It replaces traditional iptables-based networking with high-performance eBPF programs that run in the Linux kernel, offering better scalability and security than standard CNI plugins.
Step-by-step installation
Update system packages
Start by updating your system packages to ensure you have the latest security patches and dependencies.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg2 software-properties-common
Install Cilium CLI
Download and install the official Cilium CLI tool for managing Cilium installations and configurations.
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{,.sha256sum}
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz{,.sha256sum}
Verify Kubernetes cluster prerequisites
Ensure your Kubernetes cluster is running and accessible, and that you have cluster-admin permissions.
kubectl cluster-info
kubectl get nodes
kubectl auth can-i '' '' --all-namespaces
Remove existing CNI plugin
If your cluster has an existing CNI plugin like Flannel or Calico, you need to remove it before installing Cilium.
# For Flannel
kubectl delete -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
For Calico
kubectl delete -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml
Remove CNI configuration files from all nodes
sudo rm -rf /etc/cni/net.d/*
sudo rm -rf /opt/cni/bin/*
Install Cilium CNI
Deploy Cilium to your Kubernetes cluster with eBPF networking enabled and optimized configuration for production use.
cilium install \
--version 1.15.1 \
--set kubeProxyReplacement=true \
--set k8sServiceHost=203.0.113.10 \
--set k8sServicePort=6443 \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set operator.replicas=2
Wait for Cilium deployment
Monitor the Cilium installation progress and wait for all components to become ready.
cilium status --wait
kubectl get pods -n kube-system -l k8s-app=cilium
kubectl get pods -n kube-system -l name=cilium-operator
Enable Hubble observability
Configure Hubble for network flow visibility and monitoring across your cluster.
cilium hubble enable --ui
cilium hubble port-forward &
Install Hubble CLI
Install the Hubble CLI for command-line network observability and troubleshooting.
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{,.sha256sum}
sha256sum --check hubble-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC hubble-linux-amd64.tar.gz /usr/local/bin
rm hubble-linux-amd64.tar.gz{,.sha256sum}
Configure eBPF networking and policies
Enable advanced eBPF features
Configure Cilium with advanced eBPF features including bandwidth management and socket-level load balancing.
apiVersion: v1
kind: ConfigMap
metadata:
name: cilium-config
namespace: kube-system
data:
enable-bpf-masquerade: "true"
enable-host-reachable-services: "true"
enable-session-affinity: "true"
enable-bandwidth-manager: "true"
kube-proxy-replacement: "true"
enable-health-check-nodeport: "true"
node-port-bind-protection: "true"
enable-auto-protect-node-port-range: "true"
bpf-lb-algorithm: "maglev"
kubectl apply -f cilium-config.yaml
kubectl rollout restart ds/cilium -n kube-system
Create network security policies
Implement Layer 3 and Layer 4 network policies to secure pod-to-pod communication.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
endpointSelector: {}
ingress: []
egress: []
---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
kubectl apply -f deny-all-policy.yaml
Configure Layer 7 HTTP policies
Set up application-layer security policies that can inspect and filter HTTP traffic.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: http-policy
namespace: default
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: web-frontend
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/.*"
- method: "POST"
path: "/api/users"
headers:
- "Content-Type: application/json"
kubectl apply -f http-policy.yaml
Enable cluster mesh for multi-cluster
Configure Cilium for multi-cluster networking if you have multiple Kubernetes clusters.
cilium clustermesh enable
cilium clustermesh status
Verify your setup
# Check Cilium status
cilium status
Verify connectivity test
cilium connectivity test
Check Hubble status
hubble status
List network flows
hubble observe --follow
Test policy enforcement
kubectl run test-pod --image=nginx --labels="app=test"
kubectl exec test-pod -- wget -qO- http://backend-service
Access Hubble UI
Open the Hubble UI for visual network observability and traffic analysis.
# Port forward to access Hubble UI
kubectl port-forward -n kube-system svc/hubble-ui 12000:80
Access the UI at http://localhost:12000
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Pods stuck in ContainerCreating | CNI plugin not ready | cilium status and restart cilium daemonset |
| Network policies not working | Missing policy labels | Verify pod labels match policy selectors |
| Hubble UI shows no flows | Hubble relay not enabled | cilium hubble enable and restart pods |
| High CPU usage on nodes | eBPF program compilation | Wait for compilation or use pre-compiled images |
| LoadBalancer services not working | kube-proxy replacement not enabled | Add --set kubeProxyReplacement=true to install |
| DNS resolution failures | CoreDNS not accessible | Check CoreDNS pods and create DNS policy exceptions |
Performance optimization
Tune eBPF map sizes
Optimize eBPF map sizes for large-scale deployments with many services and endpoints.
apiVersion: v1
kind: ConfigMap
metadata:
name: cilium-config
namespace: kube-system
data:
bpf-ct-global-tcp-max: "1000000"
bpf-ct-global-any-max: "250000"
bpf-nat-global-max: "524288"
bpf-neigh-global-max: "524288"
bpf-lb-map-max: "65536"
Enable direct server return
Configure direct server return for improved load balancing performance.
kubectl patch configmap cilium-config -n kube-system --patch='{"data":{"enable-dsr":"true"}}'
kubectl rollout restart ds/cilium -n kube-system
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Cilium CNI Installation Script for Kubernetes
# Supports Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS, RHEL, Fedora
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m' # No Color
# Default values
K8S_SERVICE_HOST=""
K8S_SERVICE_PORT="6443"
CILIUM_VERSION="1.15.1"
CLEANUP_EXISTING_CNI=false
# Usage function
usage() {
cat << EOF
Usage: $0 -a <api-server-ip> [OPTIONS]
Required:
-a, --api-server Kubernetes API server IP address
Options:
-p, --port Kubernetes API server port (default: 6443)
-v, --version Cilium version (default: 1.15.1)
-c, --cleanup Remove existing CNI plugins (default: false)
-h, --help Show this help message
Example:
$0 -a 192.168.1.100 -p 6443 -c
EOF
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Error handling and cleanup
cleanup_on_error() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
log_error "Installation failed. Cleaning up..."
rm -f /tmp/cilium-linux-amd64.tar.gz* /tmp/hubble-linux-amd64.tar.gz*
if command -v cilium >/dev/null 2>&1; then
cilium uninstall --wait >/dev/null 2>&1 || true
fi
fi
exit $exit_code
}
trap cleanup_on_error ERR
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-a|--api-server)
K8S_SERVICE_HOST="$2"
shift 2
;;
-p|--port)
K8S_SERVICE_PORT="$2"
shift 2
;;
-v|--version)
CILIUM_VERSION="$2"
shift 2
;;
-c|--cleanup)
CLEANUP_EXISTING_CNI=true
shift
;;
-h|--help)
usage
;;
*)
log_error "Unknown option $1"
usage
;;
esac
done
# Validate required arguments
if [[ -z "$K8S_SERVICE_HOST" ]]; then
log_error "Kubernetes API server IP is required"
usage
fi
# Check if running as root or with sudo
if [[ $EUID -eq 0 ]]; then
SUDO=""
else
SUDO="sudo"
if ! command -v sudo >/dev/null 2>&1; then
log_error "This script requires sudo privileges"
exit 1
fi
fi
# Auto-detect distribution
echo "[1/10] Detecting operating system..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
PKG_UPGRADE="apt upgrade -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf check-update || true"
PKG_INSTALL="dnf install -y"
PKG_UPGRADE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum check-update || true"
PKG_INSTALL="yum install -y"
PKG_UPGRADE="yum update -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected distribution: $PRETTY_NAME"
else
log_error "Cannot detect distribution - /etc/os-release not found"
exit 1
fi
# Update system packages
echo "[2/10] Updating system packages..."
$SUDO $PKG_UPDATE
$SUDO $PKG_UPGRADE
$SUDO $PKG_INSTALL curl wget gnupg2 tar
if [[ "$PKG_MGR" == "apt" ]]; then
$SUDO $PKG_INSTALL software-properties-common
fi
# Check prerequisites
echo "[3/10] Checking prerequisites..."
if ! command -v kubectl >/dev/null 2>&1; then
log_error "kubectl is not installed or not in PATH"
exit 1
fi
# Verify Kubernetes cluster access
if ! kubectl cluster-info >/dev/null 2>&1; then
log_error "Cannot connect to Kubernetes cluster"
exit 1
fi
if ! kubectl auth can-i '*' '*' --all-namespaces >/dev/null 2>&1; then
log_error "Insufficient permissions - cluster-admin access required"
exit 1
fi
log_info "Kubernetes cluster is accessible with proper permissions"
# Clean up existing CNI if requested
if [[ "$CLEANUP_EXISTING_CNI" == "true" ]]; then
echo "[4/10] Removing existing CNI plugins..."
log_warn "This will cause network connectivity loss for existing pods"
# Remove Flannel
kubectl delete -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml --ignore-not-found=true || true
# Remove Calico
kubectl delete -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml --ignore-not-found=true || true
# Remove CNI configuration files from local node
$SUDO rm -rf /etc/cni/net.d/* || true
$SUDO rm -rf /opt/cni/bin/* || true
log_info "Existing CNI plugins removed"
else
echo "[4/10] Skipping CNI cleanup (use -c flag to enable)"
fi
# Install Cilium CLI
echo "[5/10] Installing Cilium CLI..."
cd /tmp
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{,.sha256sum}"
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
$SUDO tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
$SUDO chmod 755 /usr/local/bin/cilium
rm -f cilium-linux-amd64.tar.gz{,.sha256sum}
log_info "Cilium CLI installed successfully"
# Install Cilium CNI
echo "[6/10] Installing Cilium CNI with eBPF networking..."
cilium install \
--version "$CILIUM_VERSION" \
--set kubeProxyReplacement=true \
--set k8sServiceHost="$K8S_SERVICE_HOST" \
--set k8sServicePort="$K8S_SERVICE_PORT" \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set operator.replicas=2
log_info "Cilium installation initiated"
# Wait for Cilium deployment
echo "[7/10] Waiting for Cilium deployment to complete..."
cilium status --wait
kubectl get pods -n kube-system -l k8s-app=cilium
kubectl get pods -n kube-system -l name=cilium-operator
log_info "Cilium deployment completed successfully"
# Enable Hubble observability
echo "[8/10] Enabling Hubble observability..."
cilium hubble enable --ui
log_info "Hubble observability enabled"
# Install Hubble CLI
echo "[9/10] Installing Hubble CLI..."
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{,.sha256sum}"
sha256sum --check hubble-linux-amd64.tar.gz.sha256sum
$SUDO tar xzvfC hubble-linux-amd64.tar.gz /usr/local/bin
$SUDO chmod 755 /usr/local/bin/hubble
rm -f hubble-linux-amd64.tar.gz{,.sha256sum}
log_info "Hubble CLI installed successfully"
# Verification
echo "[10/10] Verifying installation..."
if cilium status | grep -q "OK"; then
log_info "Cilium is running successfully"
else
log_error "Cilium installation verification failed"
exit 1
fi
if cilium connectivity test --test-concurrency=1 >/dev/null 2>&1; then
log_info "Cilium connectivity test passed"
else
log_warn "Cilium connectivity test failed - manual verification may be required"
fi
log_info "Installation completed successfully!"
echo ""
echo "Next steps:"
echo "1. Access Hubble UI: kubectl port-forward -n kube-system svc/hubble-ui --address 0.0.0.0 --address :: 12345:80"
echo "2. View network flows: hubble observe --follow"
echo "3. Check Cilium status: cilium status"
echo "4. Run connectivity tests: cilium connectivity test"
Review the script before running. Execute with: bash install.sh