Gateway API is the future of ingress in Kubernetes, and Cilium is a powerful implementation that offers a lot more than just basic L4 load balancing.

Let’s see it in action.

Imagine we have a simple web application running in Kubernetes, exposed via a Service of type ClusterIP.

apiVersion: v1
kind: Namespace
metadata:
  name: my-app
---
apiVersion: v1
kind: Service
metadata:
  name: my-web-app
  namespace: my-app
spec:
  selector:
    app: my-web-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

And a Deployment to back it:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web-app-deployment
  namespace: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-web-app
  template:
    metadata:
      labels:
        app: my-web-app
    spec:
      containers:
      - name: web
        image: nginxdemos/hello:plain-text
        ports:
        - containerPort: 8080

Now, to expose this to the outside world using Gateway API with Cilium, we need three main resources: GatewayClass, Gateway, and HTTPRoute.

First, the GatewayClass. This defines how Gateways are provisioned. For Cilium, we’ll reference its specific GatewayClass.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
  name: cilium
spec:
  controllerName: io.cilium.gateway-controller # This is the key identifier for Cilium

Once the GatewayClass is applied, we can create a Gateway resource. This is the actual load balancer instance.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: my-gateway
  namespace: gateway-api # Cilium typically manages Gateways in a dedicated namespace
spec:
  gatewayClassName: cilium
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: Same # Or All, or Selector

When Cilium’s gateway controller sees this Gateway resource, it provisions an Envoy proxy (by default) to act as the gateway. This Envoy instance will be listening on port 80. The Gateway resource itself doesn’t directly get an IP address; instead, Cilium configures its underlying network infrastructure to route external traffic to the Envoy instance that is serving this Gateway.

Finally, we create an HTTPRoute to define how traffic should be routed to our Service.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: my-web-app-route
  namespace: my-app
spec:
  parentRefs:
  - name: my-gateway
    namespace: gateway-api # Must match the namespace of the Gateway
  hostnames:
  - "myapp.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: "/"
    backendRefs:
    - name: my-web-app
      port: 80

This HTTPRoute tells Cilium: "When traffic arrives at my-gateway destined for myapp.example.com, forward it to the my-web-app service on port 80."

To actually test this, you’d need to ensure:

  1. Cilium is installed in your cluster with the Gateway API and Envoy support enabled.
  2. You have DNS configured for myapp.example.com to point to the IP address of your Kubernetes node (if using NodePort for the gateway, or the LoadBalancer IP if you’ve configured that).
  3. You can access the cluster externally.

With this setup, a request to http://myapp.example.com from outside the cluster would be intercepted by the Envoy proxy managed by Cilium, which then routes it to the my-web-app Service.

The true power of Cilium as a Gateway API implementation lies in its ability to leverage eBPF for highly efficient packet processing, bypassing much of the traditional kernel networking stack. This means that for many routing and load balancing decisions, the data path is entirely within eBPF, leading to significantly lower latency and higher throughput compared to userspace proxies alone. Cilium can also integrate with other Cilium features, like Network Policies, to apply granular security controls directly at the network layer, even for traffic managed by the Gateway API. Furthermore, Cilium’s implementation can handle advanced scenarios like traffic splitting for canary deployments, request/response modification, and integration with external authorization services, all managed through the Gateway API CRDs.

What most people don’t realize is that Cilium’s Gateway API implementation is not just a wrapper around Envoy. While Envoy is often used as the L7 proxy, Cilium’s eBPF data plane can directly handle much of the routing and load balancing logic before traffic even reaches Envoy for more complex L7 processing. This means that for simple L4 routing or even basic L7 routing, the performance benefits of eBPF are realized without necessarily incurring the overhead of a full Envoy request. Cilium intelligently decides when to leverage eBPF for acceleration and when to punt to Envoy for features it can’t handle natively.

The next step is to explore advanced routing rules, such as traffic splitting for canary deployments or integrating external authorization services with your HTTPRoute.

Want structured learning?

Take the full Cilium course →