2026
Kubernetes Ingress: HTTP Routing into the Cluster
LoadBalancer Services get expensive fast. Ingress puts a single entry point in front of all your HTTP workloads, handles TLS in one place and routes by hostname and path without provisioning a separate load balancer for every Service.
Getting traffic into a Kubernetes cluster is not as straightforward as it looks at first. Services of type LoadBalancer work, but they provision a separate external load balancer for every Service you expose. In a cloud environment that adds up quickly, both in cost and in the number of IP addresses you end up managing. ClusterIP Services are not reachable from outside the cluster at all. NodePort works but exposes a high-numbered port directly on every node, which is not something you want to hand to end users.
Ingress solves this by putting a single entry point in front of multiple Services. One external IP address. One TLS certificate to manage. One place where HTTP routing rules live. Traffic arrives at the Ingress controller and gets forwarded to whichever backend Service the rules say should handle it.
The tradeoff is that Ingress is specifically an HTTP construct. It understands hostnames and URL paths. If you need to route TCP traffic that is not HTTP, Ingress is not the right tool. For plain HTTP workloads though, it is almost always the first thing worth reaching for.
How it works
Ingress has two distinct parts and understanding both matters. The resource is the configuration. The controller is the process that acts on it. They are separate and the controller is not included with Kubernetes itself.
Ingress resource
An Ingress is a Kubernetes object you write in YAML. It declares rules: which hostnames to accept, which URL paths to match and which Service should receive traffic for each match. The object itself does nothing on its own. It is a set of instructions waiting to be read.
Ingress controller
The controller is the running software that reads Ingress objects and turns them into actual proxy configuration. It watches the Kubernetes API for Ingress resources and reconciles its internal state to match. Without a controller installed in the cluster, Ingress objects are ignored.
Load balancer or NodePort
The controller itself needs a way to receive traffic from outside the cluster. It typically runs as a Deployment with a Service of type LoadBalancer in front of it. On cloud providers that support it, this provisions an external load balancer automatically. The Ingress controller then handles routing from there inward.
What a basic Ingress looks like
The manifest declares which hostnames and paths should map to which Services. The controller reads this and keeps its proxy configuration in sync. Every time you apply a change to the Ingress object, the controller picks it up without a restart.
Ingress — host and path routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: production
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls-cert
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-v2
port:
number: 80
The ingressClassName field tells the cluster which controller should pick up this resource. If you have multiple controllers installed, each one watches only for Ingress objects that reference its class. The tls block references a Secret containing a TLS certificate. The controller reads that Secret and serves the certificate for connections to the listed hostnames.
Routing patterns
The rules inside an Ingress can be combined in different ways depending on what you are trying to accomplish. Most real deployments use host-based routing, path-based routing or both at the same time.
Host-based routing
Traffic for api.example.com goes to the API service. Traffic for www.example.com goes to the frontend. Both hostnames share the same external IP address and the same controller. The controller reads the Host header on each request to decide where to send it.
Path-based routing
A single hostname can route to different backends depending on the URL path. Requests to /api go to the backend service. Requests to /static go to a content service. The paths are matched in order, so more specific rules should appear before broader ones.
Default backend
When no rule matches a request, the controller falls back to a default backend. This is usually a simple service that returns a 404. Configuring a sensible default prevents the controller from returning a raw error to clients when a path is not covered by any rule.
TLS termination
One of the most useful things an Ingress controller does is handle TLS in a single place. HTTPS connections terminate at the controller. Traffic between the controller and the backend Services travels over plain HTTP inside the cluster. The backends do not need to know anything about certificates.
Certificates are stored as Kubernetes Secrets of type kubernetes.io/tls. The Secret contains a certificate and a private key. The Ingress references the Secret by name. Most teams use cert-manager to automate the full lifecycle: it requests certificates from Let's Encrypt, stores them as Secrets and renews them before they expire. Once cert-manager is running, you add an annotation to the Ingress and the certificate appears without any manual steps.
cert-manager annotation for automatic certificate issuance
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
cert-manager watches for Ingress objects with that annotation, reads the hostname from the tls block, issues a certificate request and stores the result in the referenced Secret. From that point on, renewals happen automatically. The Ingress object does not change. The Secret gets updated in place.
Ingress controllers
Kubernetes does not ship with a default Ingress controller. You choose one and install it. The choice affects which annotations are available, what features are supported and how the controller integrates with your cloud provider. Most clusters use one of a small number of well-established options.
ingress-nginx
The most widely deployed controller. Uses nginx as the underlying proxy. Configuration happens through annotations on Ingress objects. Maintained by the Kubernetes community and available for almost every cluster environment.
Traefik
Native Kubernetes support with its own custom resource definitions alongside standard Ingress. Supports automatic TLS through Let's Encrypt without extra tooling. Popular with teams that want the gateway and ingress roles handled by the same component.
HAProxy Ingress
Built on HAProxy. Valued for its performance characteristics under high connection load. Common in environments that were already running HAProxy before moving workloads to Kubernetes.
AWS Load Balancer Controller
Provisions AWS Application Load Balancers directly from Ingress objects. Traffic terminates at the ALB before reaching the cluster, which means the controller does not run in the data path itself. Used almost exclusively on EKS.
Annotations
The Ingress spec covers the basics. For anything beyond path routing and TLS, controllers use annotations. Annotations are key-value pairs in the Ingress metadata that the controller reads to apply controller-specific behaviour. They are how you configure things the spec has no field for.
nginx.ingress.kubernetes.io/rewrite-targetRewrites the URL path before forwarding to the backend. Used when the backend expects a different path than what the client sends.
nginx.ingress.kubernetes.io/ssl-redirectForces HTTP requests to redirect to HTTPS. Usually set to true in production environments.
nginx.ingress.kubernetes.io/proxy-body-sizeSets the maximum allowed size for the request body. The default in nginx is 1MB. File upload endpoints need this raised.
nginx.ingress.kubernetes.io/rate-limitEnables per-client rate limiting at the ingress layer. Requests over the limit receive a 429 response before reaching any backend pod.
nginx.ingress.kubernetes.io/auth-urlForwards each request to an external authentication service before passing it to the backend. Useful for centralising auth without modifying backend code.
Annotations are controller-specific. An annotation that works on ingress-nginx has no effect on Traefik unless Traefik happens to define the same key with the same meaning. When switching controllers, every annotation needs to be reviewed against the new controller's documentation.
Things that go wrong
Ingress problems tend to be quiet. Traffic stops working without any error surfacing in the resources themselves. The controller logs are usually where the real story is.
Forgetting to install a controller
Ingress objects look valid in kubectl and show no errors, but nothing happens. The Ingress API is always present in the cluster, but it only does something when a controller is running to act on it. New clusters with no controller installed will silently ignore every Ingress you create.
Conflicting rules across namespaces
Two teams define Ingress resources for the same hostname in different namespaces. The controller picks one and ignores the other, often without making it obvious which one won. Hostname ownership should be coordinated explicitly, especially in shared clusters.
TLS misconfiguration
The TLS section references a Secret that does not exist, is in the wrong namespace or contains a certificate that has expired. The controller falls back to a self-signed certificate and browsers start rejecting connections. Certificate expiry alerts should cover the Secrets that back Ingress TLS.
Path prefix versus exact matching
A path of /api matches /api, /api/users and /apilegacy. When the controller uses prefix matching by default and exact matching is what you actually need, traffic ends up at the wrong backend. Check which path type the controller uses and set it explicitly in the Ingress spec.
Where it fits
Ingress sits above the Service layer in the Kubernetes networking model. Services handle east-west traffic between workloads inside the cluster. Ingress handles north-south traffic coming in from outside. The two are complementary. An Ingress always routes to a Service, not directly to pods.
The relationship between Ingress and an API gateway is worth understanding because the line between them has blurred over time. A basic Ingress controller does path routing and TLS. A more capable controller like Traefik or Kong extends that to include rate limiting, authentication forwarding and circuit breaking. At that point the controller is doing what an API gateway does. Many teams use the same component for both roles without needing a separate gateway deployment.
For clusters that need more than Ingress can express, the Kubernetes Gateway API is the newer standard. It uses a richer set of resources that separate infrastructure concerns from application routing concerns, allow multiple teams to share a gateway without stepping on each other and support traffic protocols beyond HTTP. Ingress is not going away, but new controller development increasingly targets the Gateway API first.