skip to content

Ingress and Ingress Controllers

An Ingress only declares host and path rules; nothing happens until a controller such as ingress-nginx or Traefik watches them and programs a proxy, with TLS certificates read from Secrets. That resource-versus-controller split is what interviewers check.

part ofKubernetesoverview, primer and where to startread it →
on this pageshow

questions

6

What does a Kubernetes Ingress object actually do, and why does creating one have no effect until something else is installed in the cluster?

level: juniorimportance: must knowfreq 72%

answer

  1. Ingress = data, controller = the actor
  2. no ingress controller ships with Kubernetes
  3. empty ADDRESS = nobody claimed it
  4. controller watches Ingress + EndpointSlice + Secret
  5. DNS is your job, not the Ingress's

basics

~20 s

An Ingress is just declarative configuration: hostname and path rules mapping to Services, plus TLS. Kubernetes ships no code that acts on it. An ingress controller must be installed; it watches Ingress objects and programs a real proxy or load balancer to match.

solid answer

~50 s

An `Ingress` is a data object, not a running component. It says: for host `shop.example.com`, path prefix `/api`, send traffic to Service `api` on port 8080, and terminate TLS using this Secret. That is all it is — rules stored in etcd. Making it real requires an **ingress controller**: a separate deployment (NGINX, Traefik, HAProxy, Envoy-based, or a cloud controller like AWS ALB or GKE's) that watches Ingress objects through the API server and reprograms an actual data plane. Unlike most controllers, none is bundled with kube-controller-manager, so a fresh cluster has zero. Symptoms of the gap are distinctive: `kubectl get ingress` shows the object but `ADDRESS` stays empty, no events appear, and the hostname does not resolve or resolves to nothing listening. The same happens if a controller is installed but `ingressClassName` matches none of the installed classes. Traffic to the controller itself usually arrives via a Service of type LoadBalancer or NodePort.

code

yaml · 17 lines
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 8080

go deeper

for a junior

State clearly that Ingress is configuration and an ingress controller is the program that implements it, and that no controller ships with Kubernetes.

for a middle

Add the controller's reconcile loop, how class selection filters objects, and that in-cluster controllers usually route straight to pod IPs from EndpointSlices.

for a senior

Walk the full path client → DNS → external LB → controller → pod, and give an ordered diagnosis for an Ingress with no address.

for a principal

Discuss the edge as a platform choice: how many controllers, internal versus external classes, cost of load balancers, and the fact that Ingress is frozen so new capability requires a different API.

## The declarative object A `networking.k8s.io/v1` Ingress has a small spec: - `ingressClassName` — which controller should serve it. - `rules[]` — each optionally scoped to a `host`, containing `http.paths[]`, and each path has a `path` string, a required `pathType`, and a `backend` naming a Service and port. - `tls[]` — lists hostnames and the Secret holding the certificate for them. - `defaultBackend` — optional catch-all for requests matching no rule. Every one of those fields is a *statement of intent*. The API server validates the shape and stores it. Nothing in core Kubernetes reads it and does anything. ## Why no controller ships in the box Most built-in resources have a built-in controller: Deployments have the deployment controller, Services get endpoints from the endpoints controller, and kube-proxy programs Service routing on each node. Ingress is the exception. HTTP routing at the edge is where implementations differ enormously — in-cluster proxy pods versus cloud load balancers, NGINX versus Envoy versus HAProxy, different TLS and WAF stories — so the project standardised the object and left the implementation to the ecosystem. That is exactly why so much real behaviour ended up in per-controller annotations. ## What the controller actually does An ingress controller is an ordinary workload with elevated read permissions. Its loop: 1. Watch Ingress, Service, EndpointSlice, Secret and IngressClass objects via the API server. 2. Filter to Ingresses whose `ingressClassName` names an IngressClass whose `spec.controller` equals this controller's own identifier (plus any class marked default by the `ingressclass.kubernetes.io/is-default-class` annotation). 3. Compile them into a data-plane configuration — an nginx.conf, an Envoy xDS snapshot, or cloud API calls creating listeners and rules. 4. Load certificates from the referenced Secrets. 5. Reload or hot-update the proxy, and write the external address back into `status.loadBalancer`. In-cluster controllers usually resolve traffic straight to pod IPs from EndpointSlices, bypassing the Service's cluster IP; that is how they can do their own load balancing, retries, and sticky sessions. ## How traffic reaches the controller The controller's own pods need to be reachable from outside. The usual answers are a `Service` of type `LoadBalancer` (cloud provisions an external L4 load balancer), `NodePort` with something in front, or `hostNetwork` on dedicated nodes for bare metal. DNS for every hostname in your Ingress objects points at that address. So the path is: client → DNS → external LB → controller pod → backend pod. One external load balancer fronts many hostnames and paths, which is the main cost reason people use Ingress instead of a LoadBalancer Service per app. ## Diagnosing "my Ingress does nothing" Work through it in order: 1. `kubectl get ingress` — empty `ADDRESS` after a minute means no controller claimed it. 2. `kubectl get ingressclass` — is any class installed, and does `spec.controller` match a controller that is actually running? 3. `kubectl describe ingress <name>` — a serving controller emits events such as `Sync`; total silence means nobody is watching. 4. `kubectl get pods -n <controller namespace>` — is the controller running and its Service assigned an external address? 5. Does DNS for the hostname point at that address? An Ingress does not create DNS records; a separate tool such as external-dns does. ## Version note The stable API is `networking.k8s.io/v1`, GA since Kubernetes 1.19; the older `extensions/v1beta1` form was removed in 1.22. In v1 the backend shape changed to `service.name` / `service.port`, `pathType` became required, and controller selection moved from the `kubernetes.io/ingress.class` annotation to the `ingressClassName` field. Ingress is now feature-frozen — supported and maintained, but new routing capability lands in the Gateway API instead.

  • Why use an Ingress at all instead of giving each application a Service of type LoadBalancer?
    Each LoadBalancer Service usually provisions its own cloud load balancer with its own IP and its own bill, and it is layer 4, so it cannot route by hostname or path or terminate TLS centrally. An Ingress lets one external load balancer front many hostnames and paths with shared TLS termination, which is cheaper and gives you a single place for edge concerns.
  • Can two ingress controllers run in one cluster at the same time?
    Yes, and it is common — for example an internal-only controller and a public one. Each has its own IngressClass, and each Ingress selects one with `ingressClassName`. Take care with the default-class annotation: if two classes are marked default, objects without an explicit class become ambiguous and may be picked up twice or not at all.

An Ingress is a printed delivery instruction taped to a warehouse wall. Perfectly clear, completely inert, until you hire a dispatcher who reads the wall and actually routes the trucks.

saying these in an interview costs you the question

  • Believing Kubernetes routes HTTP by hostname on its own once an Ingress exists
  • Saying kube-proxy implements Ingress — kube-proxy handles Service routing, not L7 rules
  • Expecting the Ingress to create DNS records for its hostnames
  • Assuming any installed controller serves every Ingress regardless of ingressClassName
  • Thinking the Ingress object itself is the thing that receives traffic

context

open as a page

A Kubernetes Ingress rule requires a pathType. Explain the difference between Prefix, Exact and ImplementationSpecific, and how a request URL is matched against them.

level: middleimportance: must knowfreq 48%

basics

~20 s

Exact matches the whole URL path, case-sensitive, with no trailing-slash tolerance. Prefix matches on complete path segments split by /, so /foo matches /foo and /foo/bar but never /foobar. ImplementationSpecific hands matching to the controller, which may allow regexes. Exact wins over Prefix, longest prefix first.

open as a page

How do you terminate TLS for a hostname at a Kubernetes Ingress, and what exactly must the referenced Secret contain?

level: middleimportance: must knowfreq 52%

basics

~20 s

Add a spec.tls entry listing the hosts and a secretName. The Secret must be type kubernetes.io/tls in the same namespace as the Ingress, with keys tls.crt (leaf plus intermediate chain) and tls.key. The controller loads it and serves that certificate by SNI.

open as a page

Much real Kubernetes Ingress behaviour — path rewriting, timeouts, body-size limits, sticky sessions — is configured through controller-specific annotations rather than fields in the Ingress spec. Why is that, and what problems does it create in a shared cluster?

level: seniorimportance: should knowfreq 40%

basics

~20 s

The Ingress spec only models host and path routing plus TLS, so everything else had to go somewhere. Annotations are untyped metadata strings: unvalidated, undiscoverable, controller-specific, and in a shared proxy some of them let one tenant influence configuration affecting everyone.

open as a page

A cluster runs two ingress controllers, one internal and one internet-facing. How does a given Kubernetes Ingress object end up served by exactly one of them, and what goes wrong if that selection is left ambiguous?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Each controller installs an IngressClass whose spec.controller holds its own identifier. An Ingress selects one via spec.ingressClassName. If it is omitted, only a class annotated as default applies; with no default nothing serves the object, and with two defaults or a mismatch you get silent non-service or accidental public exposure.

open as a page

Requests to a hostname served by a Kubernetes ingress controller come back with 404 from the controller itself rather than from the application. Walk through how you would diagnose it.

level: seniorimportance: should knowfreq 44%

basics

~20 s

A 404 from the controller means no rule matched. Check that the Ingress has the right class and was claimed, that the Host header matches spec.rules[].host exactly, that the path and pathType actually cover the request, and that the backend Service and its EndpointSlices resolve. Confirm the request reached the expected controller.

open as a page