Ingress & Gateway API
L7 routing — exposing services to the outside world
The Ingress Resource
Ingress provides L7 (HTTP/HTTPS) routing into the cluster. Instead of one LoadBalancer per Service (expensive, wasteful), a single Ingress controller handles routing for many services based on hostname and path.
Internet
Client request
Cloud LB / NodePort
L4 entry point
Ingress Controller
L7 routing (nginx, envoy, etc.)
ClusterIP Service
Backend service
Pod
App container
Host-Based and Path-Based Routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls-cert # K8s Secret with tls.crt + tls.key
rules:
# Host-based routing
- host: app.example.com
http:
paths:
# Path-based routing
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80pathType Values
| pathType | Behavior | Example |
|---|---|---|
Exact |
URL path must match exactly | /api matches only /api, not /api/v1 |
Prefix |
Matches URL path prefix split by / |
/api matches /api, /api/v1, /api/v1/users |
ImplementationSpecific |
Up to the IngressClass | Regex matching in nginx, etc. |
Ingress Controllers
Warning
Critical: The Ingress resource does nothing without an Ingress controller. It's just a spec stored in etcd. You must deploy a controller that watches Ingress resources and configures the actual proxy.
| Controller | Proxy | Key Strengths | Notes |
|---|---|---|---|
| ingress-nginx | NGINX | Most popular, rich annotation set, battle-tested | Community-maintained; different from NGINX Inc's controller |
| Traefik | Traefik | Auto-discovery, built-in Let's Encrypt, dashboard | Popular in smaller clusters; CRD-based config too |
| Contour | Envoy | HTTPProxy CRD for advanced routing, multi-team support | VMware/Tanzu project |
| Emissary (Ambassador) | Envoy | API gateway features, rate limiting, auth, gRPC | CRD-based; Ingress support is secondary |
| AWS ALB Controller | AWS ALB | Native ALB integration, WAF, Cognito auth | Provisions actual AWS ALBs from Ingress resources |
| GCE Ingress | Google Cloud LB | Native GCP LB, Cloud CDN, Cloud Armor | Default in GKE |
TLS Termination with cert-manager
cert-manager automates certificate provisioning. It watches Ingress resources for annotations and automatically provisions TLS certificates.
Ingress created
Has cert-manager annotation
cert-manager sees it
Creates Certificate CR
ACME challenge
HTTP-01 or DNS-01
Cert issued
Stored in K8s Secret
Ingress uses cert
TLS termination active
# ClusterIssuer — cluster-wide certificate authority
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx
---
# Ingress with cert-manager annotation
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls # cert-manager creates this Secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80cert-manager Issuers
| Issuer Type | Source | Use Case |
|---|---|---|
| ACME (Let's Encrypt) | Let's Encrypt, ZeroSSL | Public-facing services, free certs, auto-renewal |
| Vault | HashiCorp Vault PKI | Internal PKI, enterprise CA |
| SelfSigned | Self-signed | Dev/testing, bootstrapping internal CA |
| CA | K8s Secret with CA cert/key | Internal services, mTLS |
Gateway API — The Ingress Successor
Why Replace Ingress?
The Ingress resource has fundamental design problems that annotations cannot fix:
Ingress Limitations
- Too simple: Only supports host + path matching. Need header-based routing? Annotation. Need traffic splitting? Annotation. Need redirects? Annotation.
- Annotation hell: Every advanced feature is a controller-specific annotation.
nginx.ingress.kubernetes.io/...won't work on Traefik, and vice versa. Zero portability. - Single resource does too much: Infrastructure config (TLS, listeners) and routing rules (paths, backends) are mixed in one Ingress object. Infra team and app team both edit it.
- No role separation: There's no way to give the app team control over their routes while restricting who manages the gateway/TLS config.
- L4 is bolted on: TCP/UDP routing requires controller-specific CRDs. Ingress is HTTP-only.
Gateway API: Role-Oriented Design
GatewayClass
Defines which controller implements the Gateway. Like StorageClass for volumes or IngressClass for Ingress.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: istio
spec:
controllerName: istio.io/gateway-controllerGateway
Declares the actual infrastructure: listeners, ports, TLS config. Managed by the platform team.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: infra
spec:
gatewayClassName: istio
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: wildcard-cert
allowedRoutes:
namespaces:
from: All # or Selector / Same
- name: http
protocol: HTTP
port: 80HTTPRoute
Defines L7 routing rules. Created by application teams, attached to a Gateway.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-routes
namespace: my-app
spec:
parentRefs:
- name: production-gateway
namespace: infra
hostnames:
- app.example.com
rules:
# Header-based routing (not possible with Ingress!)
- matches:
- headers:
- name: x-canary
value: true
backendRefs:
- name: app-v2
port: 80
# Traffic splitting — built-in canary!
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-v1
port: 80
weight: 90
- name: app-v2
port: 80
weight: 10
# HTTP redirect
- matches:
- path:
type: PathPrefix
value: /old-path
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplaceFullPath
replaceFullPath: /new-path
statusCode: 301Ingress vs Gateway API
- Resources: 1 (Ingress)
- Matching: Host + path only
- Traffic splitting: Annotation (non-portable)
- Header routing: Annotation (non-portable)
- Redirects/rewrites: Annotation
- Protocols: HTTP/HTTPS only
- Role separation: None — one resource
- Portability: Basic fields only; annotations break
- Status: GA, widely deployed, being superseded
- Resources: GatewayClass, Gateway, *Route
- Matching: Host, path, headers, query params, method
- Traffic splitting: Built-in (weight field)
- Header routing: Native (matches.headers)
- Redirects/rewrites: Native (filters)
- Protocols: HTTP, HTTPS, TCP, gRPC, TLS
- Role separation: Infra owns Gateway, apps own Routes
- Portability: All features are spec-level, not annotations
- Status: GA (v1.0+), the future standard
Gateway API Route Types
| Route Type | Protocol | Layer | Use Case |
|---|---|---|---|
HTTPRoute |
HTTP/HTTPS | L7 | Web apps, APIs, most services |
GRPCRoute |
gRPC | L7 | gRPC services with method-level routing |
TCPRoute |
TCP | L4 | Databases, message brokers, non-HTTP |
TLSRoute |
TLS (SNI) | L4+ | TLS passthrough based on SNI hostname |
UDPRoute |
UDP | L4 | DNS, gaming, VoIP |
Tip
Migration path: Gateway API is the clear successor. New projects should use it. Existing Ingress resources continue to work — there's no rush to migrate. Most controllers (nginx, envoy, istio) already support both. The ingress2gateway tool can help convert Ingress YAML to Gateway API resources.
Key Takeaways
Ingress
- L7 routing: host + path -> Service
- Requires a controller (nginx, traefik, envoy)
- TLS via Secrets, automated with cert-manager
- Advanced config trapped in controller-specific annotations
- Still works, but being superseded
Gateway API
- Role-oriented: GatewayClass -> Gateway -> Routes
- Native traffic splitting, header matching, redirects
- Multi-protocol: HTTP, gRPC, TCP, TLS, UDP
- Portable across implementations
- GA since v1.0 — the future standard