Cilium can bypass traditional load balancers and directly manage ingress traffic, making it a more integrated and performant solution for Kubernetes ingress.
Let’s see Cilium’s ingress controller in action. Imagine we have a simple Nginx deployment and we want to expose it to the outside world via Cilium.
First, ensure Cilium is installed in your cluster with the ingressController.enabled=true helm option.
helm upgrade --install cilium cilium/cilium \
--version 1.14.2 \
--namespace kube-system \
--set ingressController.enabled=true \
--set ingressController.defaultIssuer.enabled=false \
--set k8sServiceHost=YOUR_K8S_API_SERVER_IP \
--set k8sServicePort=YOUR_K8S_API_SERVER_PORT \
--set ipam.mode=kubernetes
Next, deploy a sample application. We’ll use a simple Nginx deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Save this as nginx-deployment.yaml and apply it:
kubectl apply -f nginx-deployment.yaml
Now, we create a CiliumIngress resource. This is Cilium’s custom resource for managing ingress.
apiVersion: cilium.io/v2alpha1
kind: CiliumIngress
metadata:
name: nginx-ingress
spec:
rules:
- host: "nginx.example.com"
http:
paths:
- backend:
service:
name: nginx-service
port:
number: 80
path: /
pathType: Prefix
Save this as cilium-ingress.yaml. Before applying, we need a Kubernetes Service for our Nginx deployment.
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Save this as nginx-service.yaml and apply it:
kubectl apply -f nginx-service.yaml
Now, apply the CiliumIngress resource:
kubectl apply -f cilium-ingress.yaml
To make this accessible from outside your cluster, you’ll need to configure your external load balancer (or cloud provider’s load balancer) to point to the NodePort or LoadBalancer IP of the cilium-lb service, which Cilium creates.
kubectl get svc -n kube-system cilium-lb
You’ll see a service like this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-lb LoadBalancer 10.100.100.50 <pending> 80:31234/TCP 1m
Once EXTERNAL-IP is populated (this might take a minute or two depending on your cloud provider), you can update your DNS for nginx.example.com to point to this IP.
The core problem Cilium’s Ingress Controller solves is the overhead and complexity of traditional Ingress controllers that rely on separate load balancer components. Instead of a dedicated Ingress controller pod and a separate Service of type LoadBalancer, Cilium integrates ingress directly into its data plane. When you define a CiliumIngress resource, Cilium translates these rules into eBPF programs that are attached to your host network interfaces. Traffic destined for the configured host (nginx.example.com in our case) is intercepted by these eBPF programs. The eBPF program then inspects the incoming request, matches it against the rules defined in CiliumIngress, and forwards it directly to the appropriate Kubernetes Service and its backing pods. This bypasses the kube-proxy and traditional L4 load balancing, leading to lower latency and higher throughput because the traffic doesn’t need to traverse multiple network hops or software layers.
The CiliumIngress resource is key. It’s Cilium’s declarative way to define how external traffic should be routed to your internal Kubernetes services. It supports standard Kubernetes Ingress fields like host, path, and pathType, making it familiar if you’ve used other Ingress controllers. The backend section directly specifies the Kubernetes Service and port to which traffic matching the rule should be sent. Cilium’s agent, running on each node, watches for these CiliumIngress resources and dynamically programs the eBPF logic in the kernel.
A surprising detail is how Cilium handles TLS termination without needing a separate component. You can configure TLS directly within the CiliumIngress resource by referencing a Kubernetes Secret containing your TLS certificate and key. Cilium’s eBPF programs can then perform the TLS decryption at the network layer before forwarding the plaintext traffic to your backend service. This means your application pods don’t need to be TLS-aware, and the decryption happens efficiently in the kernel.
The cilium-lb Service is a special service that Cilium uses to expose the ingress functionality to the outside world. It typically creates a Service of type LoadBalancer (or uses NodePorts) that directs traffic to the Cilium agent’s ingress listener on each node. This listener is where the eBPF programs are active and ready to process incoming ingress traffic.
The next concept you’ll want to explore is advanced routing rules within CiliumIngress, such as traffic splitting and header-based routing.