kadet-hub logokadet-hub

Migrate ingress-nginx to Gateway API with Kapitan

ingress-nginx is retired: best-effort maintenance ended in March 2026, and the project no longer ships releases or security fixes (announcement). Kubernetes recommends Gateway API as the successor. In a Kapitan project the move is an inventory change per target, and Ingress and Gateway can run side by side until DNS points at the new address.

Before and after

With the kubernetes generator, an Ingress lives under parameters.ingresses:

parameters:
  ingresses:
    web:
      namespace: shop
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
      hosts:
        - name: shop.example.com
          paths:
            - path: /
              path_type: Prefix
              backend_name: web
              port_name: http

The same host as a Gateway with the services shorthand renders an HTTPS listener, an HTTP to HTTPS redirect route and the backend route:

parameters:
  generators:
    kubernetes:
      gateways:
        public:
          namespace: gateway
          gateway_class: eg
          services:
            web:
              hostname: shop.example.com
              namespace: shop
              tls_secret: shop-example-com-tls
              cluster_issuer: letsencrypt
              redirect_status_code: 308
              backend:
                name: web
                port: 80

Keep both in the target while you test the Gateway on its own address, switch DNS, then delete the ingresses entry. Rules the shorthand cannot express go under gateways.<gw>.routes, and resources the generator does not model, such as implementation policies, under generators.kubernetes.manifests.

Annotations

Most annotations have a Gateway API field, some only an implementation extension. The kubernetes generator’s README maps the common ones to the Gateway API 1.6.3 standard channel and to the generator key that renders each: ingress-nginx annotations. ingress2gateway converts many of them for existing clusters and warns about the rest; its output is a useful cross-check for the inventory you write.

Defaults that differ

The migration is not a rename. These behave differently even when a field exists:

Body size limits, IP allowlists, external auth, session affinity and snippets have no standard field. They need a policy of your Gateway implementation, for example Envoy Gateway’s BackendTrafficPolicy and SecurityPolicy.

Checking the result

Compile, then validate the routes against the Gateway API CRDs before anything reaches a cluster. Server-side dry runs catch what the JSON Schemas do not; see Checking custom resources against their CRDs.