Ingress-NGINX to Gateway API: A Cutover Acceptance Checklist

Yilia Lin

Yilia Lin

Published: August 18, 2026

Updated: November 2, 2026

Technology

An Ingress-to-Gateway API migration is complete only when the new controller reproduces the behavior your applications depend on. Converted YAML is a starting artifact, not acceptance evidence. The safe path is to inventory the current contract, classify every annotation, deploy the new controller beside the old one, test request behavior, shift a bounded slice of traffic, and keep a proven rollback path until the observation window closes.

This guide targets platform teams moving from Ingress-NGINX to Gateway API. The runnable path below is scoped to HTTP and HTTPS migration with Gateway API v1.6, Ingress2Gateway v1.2, and APISIX Ingress Controller 2.1 as pinned reference points. It does not establish L4 compatibility for TCPRoute or UDPRoute. The workflow also applies to other conformant controllers, but policy resources, supported fields, defaults, and status conditions remain implementation-specific.

The Acceptance Standard

A successful migration must prove all four conditions:

  1. The Kubernetes API accepts the target resources and the selected controller reports them as programmed.
  2. Requests produce the expected routing, TLS, authentication, transformation, timeout, and failure behavior.
  3. Operators can observe and troubleshoot the new path before the old path is removed.
  4. The team can return traffic to the previous controller within its recovery objective.

That standard is deliberately stricter than “the manifests applied.” The official Gateway API migration guide explains that it does not prepare a live migration or convert every implementation-specific feature. Treat that limit as a design input.

Before starting, prepare exported Ingress manifests, a non-production cluster or isolated entry point, the target controller's support matrix, request fixtures for every protocol the workload uses, and authority to move and roll back traffic. Replace the example namespaces, hostnames, addresses, and certificates below with test values for your environment.

Start with an Annotation Inventory

Export the source Ingress objects and group annotations by behavior. Do not translate an annotation solely because the target controller exposes a similarly named field.

Behavior to preserveTypical sourceTarget decisionAcceptance evidence
Host and path routingIngress rulesHTTPRoute matchesExpected backend for positive and negative paths
TLS termination and redirectTLS block and annotationsGateway listener plus route or policyCertificate chain, SNI, HTTP-to-HTTPS result
Rewrites and header changesNGINX annotationsCore filters or controller extensionBackend-observed path and headers
External authenticationauth annotations or snippetsController policy or external serviceAllowed, missing, invalid, and unavailable cases
Rate limitingannotations or snippetsGateway policy or pluginCounter scope, rejection status, reset behavior
Timeouts and retriesproxy annotationsStandard field or controller policyFailure timing and duplicate-side-effect check
Request buffering and body sizeNGINX settingsController-specific policyFile upload and large-body tests
Client IP and forwarded headerscontroller configurationListener and proxy trust settingsBackend-observed address from trusted and untrusted hops

The last three rows are common sources of false confidence. A new controller can accept a route while changing retry timing, upload streaming, or the meaning of a forwarded address. Those are application contracts, not cosmetic configuration.

Save three artifacts for each workload: the source manifest, the conversion output and warnings, and an owner-approved mapping table. An annotation with no owner is still a risk; it may encode a dependency that nobody remembers.

Generate Candidate Resources, Not Production Truth

Ingress2Gateway can convert core Ingress behavior and selected provider annotations. Pin the tool version and work from exported manifests or a non-production context:

ingress2gateway print \ --providers=ingress-nginx \ --input-file=source-ingress.yaml \ > candidate-gateway-api.yaml \ 2> conversion-warnings.log

This form converts the exact exported file instead of whatever the active Kubernetes context happens to expose. If you intentionally use cluster-context mode, pin and record the context and namespace first. Keep conversion-warnings.log: warnings about unsupported or ambiguous behavior are part of the migration record.

Review the output for:

  • the intended GatewayClass and parent references;
  • listener hostnames, ports, protocols, and certificate references;
  • namespace boundaries and any required ReferenceGrant;
  • route match precedence and default-backend behavior;
  • filters that replaced annotations;
  • features that moved to implementation-specific policies;
  • API versions supported by the installed controller.

Gateway API v1.6 makes TCPRoute and UDPRoute Standard v1 resources, but APISIX Ingress Controller 2.1 still reconciles those kinds through v1alpha2. The Gateway API v1.6 Standard CRDs do not serve that older version. Keep the pinned 2.1 path in this article to Gateway and HTTPRoute; for TCP or UDP workloads, select a controller release that explicitly supports the installed v1 resources and validate that controller/CRD pair as a separate cutover batch.

Choose the Runtime Before the Conversion

Gateway API defines a Kubernetes contract; a controller and data plane implement it. Choose that implementation before finalizing manifests.

For Apache APISIX, APISIX Ingress Controller translates Gateway API resources into Apache APISIX configuration. Its compatibility table lists controller 2.1 with APISIX 3.0 or later and recommends APISIX 3.13. The same page states that the Standalone API-driven mode in controller 2.0 and later requires APISIX 3.13 or later. Treat 3.13 as a requirement in that mode, not merely a recommendation, and verify the exact pair rather than mixing examples from different releases.

APISIX Ingress Controller also exposes extension policies for behavior outside core Gateway API. Those policies are not portable promises. If authentication, rate limiting, transformations, or upstream behavior depends on an APISIX policy, name that dependency in the workload contract and test it through the gateway.

Before proceeding, record:

Gateway API CRDs: v1.6.x Controller: name, image digest, and version Data plane: name, image digest, and version GatewayClass controllerName: exact value Supported route kinds: HTTPRoute for this pinned path; separately validated list for TCPRoute or UDPRoute Extension policies: name, version, and attachment target Rollback owner and maximum recovery time

Run a Three-Layer Validation

1. Validate the Objects

Use server-side dry run against the cluster that has the target CRDs and admission policies:

kubectl apply --server-side --dry-run=server -f candidate-gateway-api.yaml

This checks schema and admission. It does not prove that the controller will accept or program the objects.

2. Validate Controller Status

Apply the resources in staging, then inspect Gateway and route status:

kubectl get gateway,httproute -A kubectl describe gateway -n edge public-gateway kubectl describe httproute -n shop checkout

Require positive parent conditions for the intended controller. Investigate Accepted=False, Programmed=False, unresolved references, invalid listener attachment, and unsupported fields. A resource that exists but has no accepted parent is not serving traffic.

3. Validate Request Behavior

Send traffic directly to the new entry point before changing public DNS. Preserve the production hostname so host and TLS routing are exercised:

curl --resolve shop.example.com:443:NEW_GATEWAY_IP \ --cacert ./test-ca.pem \ -i https://shop.example.com/healthz

Repeat with a request matrix that covers:

  • allowed host and path;
  • unknown host and unmatched path;
  • HTTP redirect and HTTPS response;
  • valid, missing, expired, and wrong-audience credentials;
  • route rewrite and header behavior as observed by the backend;
  • request bodies at, below, and above the expected limit;
  • backend connection refusal, timeout, and partial failure;
  • gRPC, WebSocket, SSE, or large uploads when the workload uses them;
  • rate-limit identity, rejection response, and recovery window;
  • retry behavior for non-idempotent requests.

Record status, relevant headers, backend identity, duration, and a request correlation value. Do not treat a single 200 as proof that the old and new paths are equivalent.

Cut Over Without Hiding Rollback Risk

Run the old and new controllers side by side with distinct entry points. Avoid letting both controllers claim the same resource or load balancer unintentionally.

A controlled sequence is:

  1. Apply target resources and pass object, status, and request tests.
  2. Send internal or synthetic traffic to the new entry point.
  3. Move one low-risk hostname, route, or weighted traffic slice.
  4. Compare errors, latency, authentication denials, upstream failures, and application-level outcomes.
  5. Expand only after the agreed observation interval.
  6. Stop new changes on the old path, then retire it after rollback is no longer required.

DNS can support a cutover, but DNS rollback is bounded by resolver and CDN caching. A load balancer, CDN, or upstream routing layer may provide faster weighted switching. Document which control actually moves traffic and who can operate it.

Rollback criteria should be observable, for example:

  • authentication denial rate exceeds the approved baseline;
  • uploads or streaming requests fail their acceptance suite;
  • backend 5xx or gateway timeouts exceed the rollback threshold;
  • the new controller cannot reconcile a required route;
  • operators cannot correlate a failed request to a route and upstream.

Rollback means moving traffic, not merely reapplying old YAML. Test the move before production cutover.

Troubleshoot by Failure Layer

SymptomFirst checkLikely boundary
Resource applies but route is unreachableParent and listener conditionsKubernetes/controller reconciliation
TLS certificate is wrongListener hostname and certificate referenceGateway listener and secret access
404 only on new pathHost/path match and rewriteRoute selection or filter semantics
Authentication differsPolicy attachment, identity source, unavailable behaviorController extension or auth service
Upload becomes empty or rejectedBuffering, chunking, body limitsData-plane HTTP behavior and application server
Duplicate write after upstream errorRetry policy and method safetyGateway retry semantics
Client IP changesTrusted proxy chain and forwarded-header policyEntry point and proxy trust boundary

Fix the owning layer and rerun the complete affected test set. A route change can alter authentication attachment; a listener change can alter TLS and forwarded headers.

Completion Checklist

Do not decommission the old controller until every checked workload has:

  • pinned source and target versions;
  • an annotation-to-policy mapping with owners;
  • accepted and programmed Gateway API status;
  • positive and negative request evidence;
  • protocol-specific tests for the traffic it actually serves;
  • dashboards, logs, and request correlation on the new path;
  • a tested traffic rollback;
  • an agreed observation period and retirement decision.

Gateway API improves the configuration model, but it cannot make implementation-specific behavior portable by itself. Use Ingress2Gateway to reduce mechanical work, then prove the runtime contract on the controller you will operate.

For an APISIX target, begin with the APISIX Ingress Controller overview and verify the exact compatibility and Gateway API support for your release before converting a production workload.

Tags:
Share article link