The announcement of the retirement of Ingress NGINX at KubeCon NA 2025 sent ripples throughout the Cloud Native ecosystem. Originally developed as an example of how to implement the Ingress API, Ingress NGINX quickly became a popular choice due to its flexibility, features, and being platform agnostic. The retirement of Ingress NGINX leaves many users at a crossroads of what migration path to take. I am one of the 50% of users that uses Ingress NGINX, and my use case is pretty straightforward. I needed a way to access the Argo CD UI. But, regardless of the use case, I am faced with what most end users are faced with. The two paths off of Ingress NGINX: Move to another Ingress Controller Adopt Gateway API Since joining Isovalent, I’ve seen organizations turn to Isovalent Networking for Kubernetes as the need goes beyond just replacing a controller. They need a complete Networking platform for Kubernetes. And, it just so happens that Cilium (part of Isovalent Networking for Kubernetes) is a “batteries included” solution that comes with an Ingress controller. In this blog I will go over how you can replace Ingress NGINX by going over the two paths individually. First, I will use the Cillium Ingress controller and then I will also go over the replacement using Gateway API. For the purposes of a demo, I will be using Argo CD as an example workload. Kubernetes Environment For this example, I am using KIND for my Kubernetes environment since it’s easy to get up and running as all you need is Docker on your system. It’s easy to spin up and tear down, and you can emulate production environments to easily test out scenarios. For the purpose of the demo, I’m going to customize the KIND cluster to bind to ports 80 and 443 as I want to connect to the Argo CD UI via my browser. Here’s the configuration saved as a config.yaml file. A few things to note about this configuration: I’ve used disableDefaultCNI as KIND will deploy its own CNI, and I will be installing Cilium The port mappings will map my systems 80 and 443 ports to the containers respective ports. Since KIND uses kubeadm, I’ve used kubeadmConfigPatches to label my single node with ingresshost=cilium. This ensures (as you’ll see later) that Pods run on this node in case I want to add other nodes later. With that configuration in place, I can now create the KIND Kubernetes cluster on my system by running the following: Once created, If I run kubectl get pods --all-namespaces I will see some pods are in the Pending state: This is because there is no networking yet on the KIND cluster. I still need to install Cilium as the CNI provider. Choosing Your Path: Cilium Ingress or Cilium Gateway API As Dean said in his blog post, many organizations find themselves at a turning point with the retirement of Ingress NGINX. Moving to Cilium Ingress offers a familiar Ingress based experience with minimal changes. This path is ideal if you want a fast, low risk migration and already have applications and tooling built around the Ingress API. Cilium Ingress lets you keep your existing workflows while benefiting from Cilium’s performance, observability, and security, making it a practical choice for teams that want results quickly. The other option is to adopt Cilium with Gateway API, which represents where Kubernetes networking is headed. Gateway API expands beyond basic north south traffic and provides a more expressive and structured model for managing traffic. This approach makes sense if you are designing new platforms, standardizing traffic management across teams, or preparing for more advanced use cases over time. Both paths are valid, and in the next sections I will walk through each approach. You’ll see how to use Cilium Ingress as a straightforward replacement for Ingress NGINX, followed by an example using Gateway API. This should help you decide which option best fits your current needs and where you want to take your platform next. Installing Cilium with Ingress There are two primary ways of installing Cilium; using the cilium CLI (which is itself based on the Helm chart) or the Helm Chart itself directly. Since I will use Helm to install Argo CD, I will be using the Helm Chart for Cilium as well. For my system, I will be using the following values.yaml file. There are a few options that I’m using that I want to call out: Since I am running a single node, I set the operator replicas to 1 I am enabling Cilium’s Ingress controller in the ingressController section, which includes binding to the host network. I’m also enabling the node selector to the label I used for the cluster Since I’m using hostNetwork, I need to add the required security context capabilities in order for Envoy to bind to ports 80 and 443 I’ve already had the Helm repo added, but if it isn’t for you; this can be done by running helm repo add cilium https://helm.cilium.io and the running the helm repo update command. Using the values.yaml file I created earlier, I can install Cilium using the following: You can wait for the install by running cilium status --wait. Once finished I ran cilium status to ensure Cilium has been installed: Cilium Ingress Enabled Argo CD To show you how to actually take advantage of Cilium Ingress, we are going to install Argo CD as an example app. Argo CD, being part of the larger Argo Project ecosystem, is installed using the official Argo Project Helm charts. I also recommend doing it this way since you can have the Helm Chart automatically configure the Ingress resource for you. The values.yaml file I’ll be using looks like this: The main thing to note in this file is that I’m using the Helm chart to create the Ingress object for me. Which includes setting the hostname (Here I’m using a https://sslip.io/ hosted domain that just points back to my 127.0.01 address), choosing the cilium IngressClass, and setting the needed Cilium Ingress annotations. ingress.cilium.io/tls-passthrough Setting this to enabled will enable TLS Passthrough since, by default, Argo CD generates its own certificate. ingress.cilium.io/force-https Setting this to enabled will force connections to HTTPS ingress.cilium.io/host-listener-port This instructs the Envoy listener to listen on port 443 on the host network I’ve already ran helm repo add argo https://argoproj.github.io/argo-helm and helm repo update so I can proceed with installation by running the following: I can then verify that Argo CD has been installed by running the kubectl get pods -n argocd command which displayed the following: Taking a look at the Ingress object, the Helm chart created it with the right annotations, using kubectl get ing -n argocd argocd-server -o yaml | yq .metadata.annotations I see the annotations are set. I can now visit my Argo CD UI by using the hostname I set (my case it’s https://argocd.7f000001.nip.io) using admin as the username and using the generated password extract by running: Once logged in, I am greeted with the default page: This is great seeing this work with little effort, and this is a good path for those who want to keep using Ingress, and adopt Gateway API at a later time. If you want the quickest path away from Ingress NGINX, Cilium Ingress gets you there. Cilium with Gateway API While Cilium Ingress is great, the Kubernetes world is clearly moving towards Gateway API. As mentioned above, Gateway API is a SIG-Network sub-project that builds on the idea of Ingress and expands it by also handling north-south traffic, east-west traffic, and even service mesh entry points using a reliable and flexible model. Cilium supports all the core Gateway API resources plus most of the extended ones. You also get eBPF powered performance, deeper visibility, and tighter policy integration, which makes it a strong choice as you move into the Gateway API future. Let’s test how it looks to install Cilium with Gateway API. Let’s delete the cluster in order to see how the steps differ. Now, I will recreate the cluster using the same config.yaml file as before. Following the Getting Started Guide, I installed the CRDs for Gateway API. Here I’m using --server-side since the CRDs are quite large. I’ve updated the values.yaml file to configure the Cilium Helm chart to use Gateway API instead of Ingress. The configuration looks pretty much the same, except for the Gateway API section is now in place where the Ingress section was: Installing Cilium is the same as before using Helm: After running cilium status --wait, the cluster should be up and running and doing kubectl get pods -A shows the cluster is ready: Part of installing Cilium with Gateway API support is that it comes with a GatewayClass already installed and configured. I can see this by running the kubectl get gatewayclasses command after install, which showed me: A GatewayClass is a cluster level template that defines what kind of Gateways your infrastructure can create. Conceptually, it’s like a blueprint that tells Kubernetes how a Gateway should behave. Once the class exists, you can spin up actual Gateways based on it, which I’ll do in the next section. Gateway API Enabled Argo CD Installing Argo CD with Gateway API is a little bit more involved as Gateway API adoption is only starting to grow and other projects need some time to catch up. With Argo CD, more values are needed in the values.yaml file to account for the fact that I am using both HTTPRoute and GRPCRoute (which is needed for the argocd CLI). The first step is to define a Gateway, which is a Kubernetes resource that actually configures the load balancing infrastructure. When one is created, the GatewayClass controller builds the underlying infrastructure defined by that class. A few things I want to call out The spec includes the GatewayClass installed by Cilium to use The listeners I am using, which is 443 and hostname that it should claim I’m also setting it up to use TLS termination of a certificate that I will add later. I also only am allowing claims to this Gateway to come from the argocd namespace To read more about the Gateway object, you can find it on the Gateway API documentation page. Now that I have the Gateway setup, I can apply it to my cluster: Now it’s time to install Argo CD. I modified the values file to prepare to install Argo CD with Gateway API support: A few things I want to go over here: I’m going to offload TLS and use my own TLS Certificate, so I disabled Argo CD generating its own by setting configs.params.server\.insecure to true. I am using the Argo CD Helm chart to configure the HTTPRoute under the server.httproute section. Defining also the Gateway I’ve created earlier. Just like the HTTPRoute, I’m configuring the Argo CD Helm chart to also create the GRPCRoute for me as well. More information about the Argo CD specific configurations for Gateway API can be found on the official documentation page for Argo CD. Installing Argo CD with Helm is the same as before, but with an updated values.yaml file: The Helm Chart creates the HTTPRoute object as defined in the values file, which I can see by running the kubectl get httproutes -n argocd command The same goes for the GRPCRoute which I can see with the kubectl get grpcroutes -n argocd command: Once that is in place, I will load the TLS certificate I created for Argo CD, which the Gateway will use to offload TLS. For the purposes of this blog, I will use mkcert to create the certificate. Then, I created the the Secret in the argocd Namespace: I also need to restart the Argo CD pods in order for Argo CD to use the TLS certificate I just created on the cluster: Since I am providing a secret in the argocd namespace that will be used in my Gateway that’s in the default namespace, I will need to set up a ReferenceGrant to allow access. A ReferenceGrant enables cross namespace references for things like HTTPRoutes and, in my case, Secrets. Note that the ReferenceGrant is created in the argocd namespace as that is where my Secret TLS for Argo CD is located. I apply this configuration to Kubernetes: At the time of this writing, there is a known issue with the GRPCRoute the Argo CD Helm chart creates. It incorrectly sets the backend port to port 80 where it should be 443, which can be worked around by just patching the GRPCRoute resource: I can now visit my Argo CD UI, as before, by using the hostname I set (https://argocd.7f000001.nip.io) using admin as the username and using the generated password extract by running: Once logged in, I am greeted the same as before but now I’m using Gateway API: Setting up Gateway API for Argo CD takes a bit more work than using a simple Ingress, but it’s a great opportunity to learn how the new model fits together. The process is already improving, and it will continue to get smoother as Gateway API adoption grows. Summary With the retirement of Ingress NGINX, many Kubernetes users are looking for alternatives. In this blog, I walk through replacing Ingress NGINX with Cilium Ingress for a quick and easy path while also exploring Gateway API, the future of Kubernetes traffic management. Using a KIND cluster, I showed above how to install Cilium, enable Ingress, and deploy an application like Argo CD, then moved to Gateway API with GatewayClasses, Gateways, HTTPRoutes, and GRPCRoutes. Along the way, I highlighted how Cilium leads the way in networking and traffic management by providing both solutions with minimal complexity. I hope this really helped you and will enable you to make your own, informed decision on how to proceed with your own migrations. If you want to learn more, I recommend you to either take our Cilium Ingress or Cilium Gateway API lab, and also dive deeper into our observability lab to see how much more Cilium does offer you for your daily operations. And of course, we are also happy to support you in your migration journey, just reach out and contact us.