The Blueprint: Migrating from Ingress NGINX Using ingress2gateway
There is a massive difference between reading a cloud-native architecture specification on a shiny marketing page and actually executing a migration inside a live production cluster at 2:00 AM.
As we established in our first two posts, the community’s retirement of ingress-nginx means your platform engineering team has a mandatory project on the horizon. The old monolithic, annotation-packed model is deprecated, and the Kubernetes Gateway API is the target state.
But knowing where you need to go doesn't solve the immediate operational headache: How do you actually translate hundreds of existing Ingress files and thousands of lines of fragile vendor annotations without breaking your current live production edge traffic?
You don't do it manually by copy-pasting YAML fields and guessing the syntax, and you certainly don't change parameters blindly in production. At ape factory, we value deterministic, predictable automation and zero-downtime cutovers. Today, we are going to walk through the exact engineering playbook to migrate your cluster infrastructure cleanly, leveraging parallel environments and the official Kubernetes SIG-Network tool: ingress2gateway.
Phase 1: Understand Your Public Traffic Topography
Before touching a single installation script, you must trace exactly how your external HTTP/HTTPS web traffic flows into your cluster from left to right.
When you originally deployed ingress-nginx, you created a Kubernetes Service of type LoadBalancer. Your cloud provider (AWS, GCP, Azure) intercepted that resource and provisioned a physical, external load balancer appliance with a public IP address or a CNAME record, which your external DNS provider points to.
When you deploy your new Gateway API controller, the exact same thing will happen: the controller will trigger the provisioning of a second, completely independent service of type LoadBalancer. This creates a parallel entry point with a brand-new public IP or CNAME.
This is your ultimate safety net. It means you can build, configure, and thoroughly test your entire Gateway API routing layer in the dark, side-by-side with your live production environment, without touching a single active user request.
Phase 2: The Ingress Class Sanitation Check
Before deploying a new controller, you must ensure that your legacy resources are fully isolated. Many modern Gateway API controllers have backward-compatibility features that allow them to automatically parse old Ingress resources. If you deploy a new controller into a messy cluster, it might try to hijack your existing production Ingress objects.
To prevent this, you need to run an audit to ensure that every single legacy Ingress explicitly declares its ingressClassName. Run this command:
kubectl get ingress -A -o custom-columns="NAMESPACE:.metadata.namespace,NAME:.metadata.name,CLASS:.spec.ingressClassName"
Look closely at the output. If any Ingress has a blank CLASS column, update its source YAML immediately to explicitly target your old controller:
spec:
ingressClassName: nginx
Explicitly declaring ingressClassName:nginx ensures your legacy rules stay bound strictly to the old NGINX controller and won't be interfered with when the new infrastructure comes online.
Phase 3: The Automated Translation Handshake
The Kubernetes SIG-Network subproject maintains ingress2gateway, a dedicated CLI tool purpose-built to consume old Ingress definitions, parse vendor-specific configuration structures, and output syntactically correct, role-oriented Gateway API resources (Gateway and HTTPRoute).
You can drop the compiled binary straight into your path:
go install github.com/kubernetes-sigs/ingress2gateway@v1.0.0
Let's look at a concrete example. Imagine your development team is running a legacy customer service backend. The file is a classic piece of "Annotation Hell"—it uses complex NGINX rewrite targets to shift URL parameters around:

To translate this asset automatically, run the tool using the dedicated provider engine parser:
ingress2gateway print --providers=ingress-nginx --input-file=legacy-customer-ingress.yaml
The tool acts as a pure compiler. It reads the source manifest, constructs an intermediate representation of your network rules, and outputs clean, decoupled Gateway API YAML straight to stdout:

Notice the massive structural upgrade here: the fragile string nginx.ingress.kubernetes.io/rewrite-target has been completely eliminated. It is replaced by a first-class, protocol-aware URLRewrite filter block that the Kubernetes API server can natively parse and validate.
If your inventory contains highly customized extensions, you have a clear path forward depending on your chosen data plane provider:
- If you use custom header manipulations or basic auth: Map them directly into Gateway API's native L7 filter spec or use the controller's extension reference patterns (like Traefik's
Middlewarecustom resources or Envoy Gateway'sBackendTrafficPolicy). - If you are running complex Lua blocks: Look into implementations like NGINX Gateway Fabric, which provides a native
SnippetsFilterto give you a soft landing for complex NGINX internal configuration blocks without breaking the new standard.
Phase 4: Parallel Validation & The Safe Cutover
Once your translated manifests are verified, you do not delete the old Ingress controller. You run both layers in parallel and use your terminal to cross-examine behavioral parity.
Execute the "Before" Test (Targeting Ingress NGINX)
Port-forward directly to your legacy controller's web port:
kubectl port-forward deployment/ingress-nginx-controller 8080:80 -n ingress-nginx
In a separate terminal, execute an explicit curl command to verify your routing logic, headers, and response payloads:
curl -v -H "Host: exampleapp.com" http://localhost:8080/api/customer/status
Take note of the exact HTTP headers, response codes, and backend payloads returned.
Execute the "After" Test (Targeting Gateway API)
Now, terminate that forward and open a pipeline straight into your new Gateway API routing engine:
kubectl port-forward service/traffic 8080:80 -n traffic
Run the exact same curl execution payload:
curl -v -H "Host: exampleapp.com" http://localhost:8080/api/customer/status
If the status codes, response headers (such as 301 Moved Permanently for redirects), and application data match exactly, your new routing layer is validated.
Shift the DNS Pointer
Once your test validations clear across all microservices, you can confidently update your corporate DNS server records. Change your A records or CNAME entries to point away from the legacy Ingress load balancer IP to the new Gateway API infrastructure entry point.
Monitor your access logs across both controllers. As global DNS propagation takes effect, traffic will smoothly drain out of ingress-nginx and stream into your clean, role-oriented Gateway layer. Once the old logs hit zero, execute a clean kubectl delete to purge your legacy controllers and wipe away years of accumulated annotation debt.
Selecting Your Concrete Production Engine
You now possess the exact mechanical playbook to extract, translate, and validate your routing infrastructure. But before you apply these manifests to a production system, you need to make a firm decision on which physical controller implementation will power the data plane under the hood.
In our next post, we are going to drop the marketing jargon and run a definitive, head-to-head architectural comparison of the top engines on the market: Envoy Gateway vs. Traefik vs. NGINX Fabric vs. Istio vs. Linkerd vs. Cilium vs. kgateway.
------
Beyond Annotation Hell: The Series Roadmap
This article is part of our comprehensive guide to mastering the modern Kubernetes traffic plane. Check out the rest of the series to fully stabilize your infrastructure:
-
Part 1: The Post-Ingress Era: Why the Kubernetes Gateway API is Taking Over
-
Part 2: Secure by Default: Setting Up Gateway API + Free SSL (Cert-Manager)
-
Part 3: The Blueprint: Migrating from Ingress NGINX Using ingress2gateway
-
Part 4: The Ultimate Gateway API Provider Comparison: Cutting Through the Marketing Fluff
-
Part 5: The Next Frontier: Elevating Gateway API to Handle LLMs, MCP, and AI Agents
Never miss an update.
Subscribe for spam-free updates and articles.