Free Ebook cover Cloud-Native Web Serving with Kubernetes Ingress and Service Mesh

Cloud-Native Web Serving with Kubernetes Ingress and Service Mesh

New course

20 pages

Ingress Controllers for HTTP Routing, Hostnames, and Path Rules

Capítulo 5

Estimated reading time: 0 minutes

+ Exercise

What an Ingress Controller Does (and What It Does Not)

Goal: route external HTTP/HTTPS traffic to the right Kubernetes Service based on hostnames and URL paths.

An Ingress is a Kubernetes API object that describes HTTP routing rules. An Ingress controller is the actual data-plane component (typically a reverse proxy like NGINX, HAProxy, or Envoy) that watches Ingress resources and programs itself to enforce those rules. The Ingress resource by itself does nothing until a controller is installed and selected to act on it.

It helps to separate responsibilities: the Ingress controller terminates connections, matches requests (host/path), and forwards them to Services; your application Pods still handle app logic. Ingress is not a general TCP/UDP load balancer (that is typically handled by other resources or controller-specific features). Also, Ingress does not replace internal service-to-service routing; it is primarily for north-south (client-to-cluster) HTTP(S) traffic.

Choosing and Targeting an Ingress Controller

Key idea: multiple Ingress controllers can coexist in one cluster, but each Ingress must be “claimed” by exactly one controller.

Modern Kubernetes uses IngressClass to select which controller should implement a given Ingress. A controller advertises a controller string (for example, k8s.io/ingress-nginx), and an IngressClass maps a friendly name (like nginx) to that controller. Then an Ingress references the class via spec.ingressClassName.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

When you create an Ingress, you target the controller like this:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
spec:
  ingressClassName: nginx
  rules: []

If you omit ingressClassName, behavior depends on cluster defaults and controller configuration (some controllers watch “unclassified” Ingresses; others require an explicit class). For predictable routing, always set ingressClassName.

HTTP Routing Model: Hostnames, Paths, and Backends

Mental model: an Ingress rule is a set of match conditions (host + path) and a backend (Service + port) to forward to.

At runtime, the controller evaluates each incoming request: it reads the Host header (or SNI for TLS), then compares the request path (like /api/v1/users) against the configured path rules. If a match is found, it proxies the request to the selected Service port.

In Kubernetes networking.k8s.io/v1, each rule has a host and an http.paths list. Each path entry has a path, a pathType, and a backend Service reference.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 80

Path Matching: Prefix vs Exact (and Why It Matters)

Practical impact: path matching determines which backend receives a request, especially when multiple routes overlap.

Kubernetes defines three path types: Exact, Prefix, and ImplementationSpecific. In practice, you should prefer Exact and Prefix because they are portable and predictable.

  • Exact: matches only the exact path string. /login matches /login but not /login/ or /login/reset.
  • Prefix: matches based on a URL path prefix, with path element boundaries. /api matches /api, /api/, and /api/v1.
  • ImplementationSpecific: controller-defined behavior. Some controllers treat it like a regex or like a prefix; portability suffers.

When multiple paths could match, controllers typically choose the “most specific” match (for example, the longest matching path). But the exact tie-breaking rules can vary by controller, especially when mixing ImplementationSpecific with other types. Keep your rules unambiguous: use Exact for single endpoints and Prefix for route trees.

Hostname Routing and Virtual Hosts

Use case: serve multiple domains (or subdomains) from one external IP / load balancer.

Ingress supports name-based virtual hosting: each rule can specify a different host. The controller uses the HTTP Host header (and for HTTPS, usually SNI during TLS negotiation) to select the correct virtual host configuration.

Example: route app.example.com to a frontend Service and api.example.com to an API Service.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: vhosts
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 80
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api
            port:
              number: 8080

For local testing, you can map these hostnames to the Ingress endpoint IP in your /etc/hosts (or Windows hosts file). In real environments, you create DNS records (A/AAAA or CNAME) pointing to the Ingress controller’s external address.

Path-Based Routing: One Host, Many Apps

Use case: serve multiple applications under one domain, such as example.com with / for frontend and /api for API.

This is common when you want a single public hostname but separate backends. The controller matches the path and forwards accordingly.

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

Notice the ordering in the YAML: Kubernetes does not guarantee evaluation order based on list position. Controllers generally pick the most specific match, which is why /api will win over /. Still, keep your paths clean and avoid ambiguous overlaps like /api and /api-v2 unless you are certain how your controller matches prefixes.

Step-by-Step: Create a Host + Path Ingress You Can Test

Objective: expose two Services behind one hostname using path rules, then verify routing with curl.

Step 1: Confirm the controller is running and has an address

List Ingress controller Pods and the Service that exposes them (names vary by installation):

kubectl get pods -n ingress-nginx
kubectl get svc  -n ingress-nginx

You are looking for an external endpoint. Depending on your environment, it may be an external IP, a node port, or a local address. Also check that your IngressClass exists:

kubectl get ingressclass

Step 2: Create (or identify) two backend Services

You need two Services that respond differently so you can see routing work. For example, frontend on port 80 and api on port 8080. Verify they exist:

kubectl get svc frontend api

If you are using a namespace for your app, remember that Ingress routes to Services in the same namespace as the Ingress object.

Step 3: Apply an Ingress with host and path rules

Create an Ingress like the following (adjust names and ports):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-routing
spec:
  ingressClassName: nginx
  rules:
  - host: demo.example.test
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api
            port:
              number: 8080
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 80

Apply it and inspect status:

kubectl apply -f ingress.yaml
kubectl get ingress example-routing
kubectl describe ingress example-routing

In the describe output, confirm that the rules are recognized and that the controller has assigned an address (or at least has processed the object without errors).

Step 4: Make the hostname resolve to the Ingress endpoint

For a quick test, map demo.example.test to the controller’s reachable IP. If you have an external IP, add a hosts entry. If you only have a node port, you can still test by sending the Host header explicitly with curl.

Example using curl with an explicit Host header (replace INGRESS_IP):

curl -i http://INGRESS_IP/ -H 'Host: demo.example.test'
curl -i http://INGRESS_IP/api -H 'Host: demo.example.test'

You should see different responses (or at least different upstream behavior) depending on whether you hit / or /api.

Default Backends and 404 Behavior

Expectation setting: if no host/path rule matches, you will typically get a 404 from the controller, not from your app.

Ingress controllers usually have a “default backend” that serves a generic 404 page. This is useful because it prevents accidental exposure of an unintended Service. If you want a custom default response, some controllers allow you to configure a default backend Service globally, but this is controller-specific and not part of the core Ingress API.

Within a single Ingress, you can approximate a “catch-all” by using a rule with no host (meaning it matches all hosts) and a / prefix path. Be careful: a catch-all can unintentionally route traffic for unknown hostnames to your app, which may be undesirable.

Rewrites, Trailing Slashes, and “/api” Gotchas

Common problem: your backend expects paths without the external prefix, but the Ingress forwards the full path.

Suppose your API service expects /v1/users, but externally you want /api/v1/users. With plain Ingress path routing, the backend receives /api/v1/users. Many controllers support path rewriting via annotations or custom resources, but the mechanism is not standardized in the Ingress spec.

Because rewrite configuration is controller-specific, treat it as an implementation detail: document it, test it, and keep it consistent across environments. If you need portability, consider designing your services to accept the external path structure (or use a dedicated API gateway layer that standardizes rewriting behavior).

Trailing slashes can also cause surprises. With Exact paths, /api and /api/ are different. With Prefix, both typically match. Decide on a canonical URL format and enforce it at the application or edge (redirect /api to /api/, for example) if consistency matters.

TLS Hosts and HTTPS Routing (Conceptual View)

What changes with HTTPS: the controller terminates TLS and selects the correct certificate based on the requested hostname.

Ingress supports TLS configuration via spec.tls, where you list hostnames and a Secret containing the certificate and key. The controller uses SNI to pick the right certificate for a given hostname, then applies the same host/path routing rules after decryption.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-example-com-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 80

Even if you are not ready to manage real certificates, it is important to understand that hostname routing and TLS are linked: for HTTPS, the hostname must be known early (SNI) to present the correct certificate, which is why accurate DNS and host configuration matters.

Operational Checks: Debugging Host and Path Rules

Approach: validate the Kubernetes objects, then validate the controller’s interpretation, then validate the request.

  • Check the Ingress object: kubectl describe ingress for events like “no IngressClass found” or “service not found”.
  • Check endpoints: if the Service has no ready endpoints, the controller may return 502/503. Inspect with kubectl get endpoints or kubectl get endpointSlice.
  • Check controller logs: most controllers log configuration reloads and routing decisions. Look for warnings about invalid paths, missing Services, or rejected annotations.
  • Test with explicit Host header: when DNS is not set up, use curl -H 'Host: ...' to ensure you are testing the correct virtual host.
  • Verify path matching: test both /api and /api/, and a deeper path like /api/health, to confirm prefix behavior.

Design Patterns for Clean Ingress Rules

Pattern 1: One Ingress per application boundary: keep a single Ingress resource for a domain like app.example.com and route only that app’s paths there. This simplifies ownership and reduces accidental coupling between teams.

Pattern 2: One Ingress per hostname: if you have many paths, group them under the same host in one Ingress so you can reason about the full routing table for that domain in one place.

Pattern 3: Separate “edge” and “internal” concerns: use Ingress only for edge routing (host/path). Keep authentication, rate limiting, and advanced traffic shaping in a dedicated gateway or mesh layer if you need consistent behavior across controllers and environments.

Pattern 4: Avoid ImplementationSpecific unless necessary: if you rely on regex paths or special matching, you may lock yourself into one controller. Prefer explicit Prefix/Exact and application-friendly URL structures.

Now answer the exercise about the content:

Why is it recommended to explicitly set spec.ingressClassName on an Ingress?

You are right! Congratulations, now go to the next page

You missed! Try again.

Ingress rules are enforced only by an Ingress controller. Setting spec.ingressClassName targets the intended controller via an IngressClass, avoiding unpredictable behavior when defaults differ or multiple controllers coexist.

Next chapter

TLS Termination and Certificate Automation with cert-manager

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.