To migrate Ingress to Gateway API without freezing releases, treat the work as a traffic-system migration rather than a YAML conversion. An Ingress object hides several decisions behind its class and controller-specific annotations: load-balancer ownership, TLS termination, route precedence, redirects, authentication, timeouts, health checks, source addresses, and observability. Gateway API separates those concerns across GatewayClass, Gateway, Route, and policy resources. That role-oriented model is the benefit, but it also means a mechanically translated HTTPRoute can be syntactically valid while behaving differently at the edge.
The upstream migration guide maps core concepts and explicitly warns that implementation-specific features still require controller documentation. Build the new path beside the old one, compare real requests, then move authority in small units such as one hostname or listener. The old path remains a rollback target until DNS, load-balancer, certificates, telemetry, and application behavior have all survived a defined observation period.
Build a six-stage Gateway API migration plan
Start with an executable inventory. Export every Ingress, IngressClass, Service, TLS Secret, controller ConfigMap, admission policy, DNS record, firewall rule, and external load-balancer setting. Parse annotations by controller and count where each is used. Then send representative requests through the existing endpoint and preserve status, headers, redirect location, certificate chain, protocol, backend identity, timeout behavior, and access-log fields. That evidence becomes the acceptance contract for translation; a list of Kubernetes objects alone cannot describe the current traffic behavior.
| Existing concern | Gateway API home | Primary owner | Migration test |
|---|---|---|---|
| Ingress class and controller | GatewayClass plus implementation | Platform team | Accepted GatewayClass and controller status |
| Load balancer and listeners | Gateway | Infrastructure or network team | Address, ports, protocols and listener conditions |
| Hosts, paths and backends | HTTPRoute | Application team | Matched and unmatched request matrix |
| TLS termination | Gateway listener certificateRefs | Platform and certificate owners | Chain, SNI, renewal and HTTP redirect |
| Controller annotations | Core filters, policies or extensions | Joint ownership | Behavioral parity and portability exception |
Choose a controller by conformance, not familiarity
Gateway API is an API contract, not a data plane. A GatewayClass points to an implementation whose supported resources, features, and extension policies determine actual behavior. Review the project's implementation inventory and obtain the conformance report for the exact release under consideration. Confirm Standard versus Experimental channel support, supported Route types, TLS modes, cross-namespace references, traffic splitting, header modification, timeouts, backend protocol handling, and the vendor policy objects needed for authentication or rate limiting.
Run a disposable conformance cluster before production. Install the same controller configuration, network plugin, certificate mechanism, service annotations, and cloud integration used in the target cluster. A controller that passes core HTTPRoute tests may still lack a feature your current annotations provide. Record every dependency as portable core API, implementation-specific policy, or unresolved gap. Gaps need an explicit choice: redesign the behavior, keep that hostname on Ingress, or accept a controlled extension with an owner and upgrade test.
Translate routes semantically and inspect status
Map the Ingress class to a GatewayClass, the edge endpoint and TLS settings to Gateway listeners, and application routing to HTTPRoutes. The HTTPRoute reference defines parentRefs, hostnames, rules, matches, filters, and backendRefs. Preserve path semantics carefully: Exact and PathPrefix are explicit, while regular expressions are implementation-specific. An Ingress default backend has no direct special field; model unmatched traffic with an explicit catch-all rule and verify conflict precedence.
Do not equate kubectl apply with acceptance. Inspect Gateway.status.listeners and each Route's parent status for Accepted, Programmed, ResolvedRefs, and implementation messages. A Route can exist but remain unattached because the listener rejects its namespace, hostname intersection is empty, a backend port is wrong, or a cross-namespace reference lacks permission. Use allowedRoutes intentionally. When a Route in one namespace references a backend in another, require the appropriate ReferenceGrant in the target namespace instead of widening access casually.
| Layer | Evidence before promotion | Stop condition | Rollback action |
|---|---|---|---|
| Control plane | Accepted and Programmed conditions | Rejected or unresolved references | Remove new parent or restore prior manifest |
| Edge | Expected address, listeners and certificates | Wrong IP, SNI or certificate chain | Return DNS or load-balancer target |
| Routing | Golden request matrix matches | Status, header, redirect or backend differs | Restore hostname to Ingress |
| Reliability | Error and latency within approved bounds | Sustained regression or saturation | Shift weight to old path |
| Operations | Logs, metrics and alerts identify route | Missing attribution or alert coverage | Pause promotion and repair telemetry |
Dual-run without creating ambiguous ownership
Provision a separate Gateway endpoint and keep the Ingress endpoint unchanged. Validate with a test hostname or direct address plus the correct Host header and SNI. Replay a sanitized request corpus that includes ordinary paths, encoded characters, large headers, uploads, WebSockets or streaming where relevant, redirects, invalid methods, and unavailable backends. Compare both responses and application traces. Synthetic probes should traverse public DNS, firewall, load balancer, controller, Service, and pod, because an in-cluster curl misses edge behavior.
For production exposure, select one unambiguous steering mechanism. Weighted DNS is simple but affected by resolver caching; load-balancer weighting is faster where both data planes can be backends; a temporary upstream proxy provides precise control but adds another failure point. Lower DNS TTL before, not during, the change. Avoid having two controllers reconcile the same external address or certificate without a documented ownership model. Promote one low-risk hostname, observe full business cycles, then proceed by cohort.
Control cutover, rollback, and cleanup
Define rollback as a rehearsed state transition. Keep old manifests, controller capacity, certificates, DNS records, firewall paths, and backend compatibility intact. State who can reverse traffic, the threshold that triggers reversal, and how long propagation may take. During each wave, freeze only the specific route being changed, not the entire application portfolio. Track edge error rate, latency by route, backend selection, connection resets, certificate errors, controller reconciliation errors, and saturation on both old and new data planes.
Cleanup is a later change. Once the observation window closes, remove traffic from Ingress first, verify no requests arrive, then delete objects and eventually the controller. Search again for legacy annotations, admission dependencies, dashboards, firewall rules, DNS records, public addresses, and certificate issuers. Update platform templates so new services cannot silently recreate the legacy pattern. The Kubernetes Gateway API overview is useful training material because it explains the intended separation between infrastructure provider, cluster operator, and application developer.
Release Gateway configuration as a governed API
Update delivery pipelines to validate Gateway API schemas, organization policy, hostname ownership, reference permissions, certificate references, and backend ports before merge. Render implementation-specific policy CRDs in the same review as the Route they affect. In a staging cluster, wait for status acceptance and run the golden request matrix as a deployment gate. In production, promote Gateway and shared listener changes separately from application-owned HTTPRoutes because their blast radii and approvers differ. A malformed shared listener can affect many teams even when each Route remains unchanged.
Version the capability contract for application teams. It should list supported core and extended features, allowed namespaces, listener names, policy attachments, timeout ranges, observability fields, escalation paths, and examples that have passed controller conformance. Add policy that prevents new legacy Ingress resources after the migration reaches an agreed threshold, with a time-bound exception mechanism for unmapped features. Track attached Route count, rejected references, legacy annotation count, and traffic remaining on Ingress so program completion is measured from live behavior rather than object conversion.
Exercise shared-Gateway failure before declaring the platform complete. Test controller restart, invalid policy, expired certificate, unavailable backend, dropped status updates, load-balancer replacement, and rollback of a Gateway change while independent Routes continue to reconcile. Confirm that alerts identify whether the responsible object is infrastructure-owned or application-owned. The new API's separation of roles should improve incident routing as well as configuration design; otherwise the organization has changed resources without realizing the operational value.
Key takeaways
- Inventory observed edge behavior and controller annotations before translating resources.
- Select an implementation by exact-version conformance and required extensions.
- Require accepted status conditions and a golden request matrix before traffic promotion.
- Run old and new data planes in parallel with one explicit steering authority.
- Keep rollback infrastructure alive until the agreed observation period and cleanup audit finish.
Frequently asked questions
Does Gateway API immediately replace every Ingress use case?
No. Core HTTP routing maps well, but authentication, specialized health checks, connection behavior, or other annotation-driven features may need implementation policies or redesign. Migrate only after the target controller proves the required behavior.
Can Ingress and Gateway controllers run together?
Yes, if their classes, external addresses, certificates, and reconciliation scope are distinct. Shared ownership of the same load balancer or DNS name must be designed rather than assumed.
Is automatic conversion enough?
Conversion tools accelerate inventory and core mappings, but they cannot prove application behavior or infer the intent of every implementation-specific annotation. Treat generated resources as a reviewed starting point.
Conclusion
A successful Gateway API migration changes authority without making users discover the difference. Inventory current behavior, establish a controller capability contract, translate resources with status-based acceptance, and compare both paths under real requests. Small cutover waves and a live rollback path remove the need for a traffic freeze while giving the new role model room to become the durable platform standard.