Ingress API
Ingress is Kubernetes’ original HTTP and HTTPS entry point. It is still supported and still useful, but Kubernetes now recommends Gateway API for new work. The Ingress API is stable and not planned for removal, but it is frozen and no longer receives new features.
The reason is simple: Ingress solved the common case well, but implementations quickly diverged. Anything beyond basic
host and path routing often depended on controller-specific annotations or custom resources, so the same manifest could
behave differently on NGINX, Traefik, cloud load balancers, or other controllers. Gateway API keeps the same purpose,
but splits the model into role-oriented resources such as GatewayClass, Gateway, and HTTPRoute. That gives
controllers a shared vocabulary and makes common routing configuration more portable, while still leaving room for
implementation-specific extensions.
Ingress is still a good fit when you want the classic, minimal model and the controller you run is already the one you intend to target. Gateway API is the better default when you want a common API across implementations, cleaner separation between platform owner and application owner, and standard support for features such as header matching and traffic weighting. It does not remove implementation-specific behavior entirely; for example, a controller may still use its own CRDs for middleware, policy, or advanced proxy features.
A small comparison
An old-style Ingress keeps the routing rule in one resource, and controller-specific behavior is often expressed through annotations:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sampleapp
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: hello.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: sampleapp
port:
number: 8080That works, but this particular rewrite annotation is understood by NGINX Ingress, not by every controller. Custom
resources make the controller dependency even more explicit. For example, Traefik has an IngressRoute kind in its own
API group, identified by apiVersion: traefik.io/v1alpha1:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: sampleapp
spec:
entryPoints:
- web
routes:
- match: Host(`hello.example.com`)
kind: Rule
services:
- name: sampleapp
port: 8080The important detail is the full apiVersion plus kind, not just the kind name. Other projects may define resources
with similar names, or even the same kind name in a different API group, and those resources are not interchangeable.
That is powerful, but it also means manifests are controller-specific by design.
Gateway API keeps the same routing intent, but the routing resources belong to the shared
gateway.networking.k8s.io API group. The GatewayClass selects the controller implementation, while the route
itself can stay closer to a controller-neutral shape for common HTTP routing:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: sampleapp
spec:
gatewayClassName: traefik
listeners:
- name: web
protocol: HTTP
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: sampleapp
spec:
parentRefs:
- name: sampleapp
hostnames:
- hello.example.com
rules:
- backendRefs:
- name: sampleapp
port: 8080That last example is close to the shape used in the Gateway API exercise chapter.
Info
Gateway API is the newer default in this training because it improves portability for common routing use cases and has a clearer extension model than classic Ingress. Controller-specific features still exist, but they are easier to spot when they live in their own API groups or policy resources instead of being hidden in annotations.