Skip to the document
Madhuopen lab
The Kubernetes Ninja PathTrack 1 — Kubernetes from the ground up

Chapter 10

Ingress & Load Balancing — The Front Door to Your Cluster

6 min read read1,524 wordsIntermediate8 recall cards

Before you read, guess

What is Ingress and how does it manage traffic for multiple Services?

Take ten seconds and guess — even a wrong guess makes the answer stick. Tap to see where the chapter lands, or just read on.

Ingress is an API object describing HTTP(S) routing rules — host-based and path-based — sitting in front of multiple Services behind a single entry point.

Picture a mall where every store — the shoe shop, the electronics store, the food court stall — insisted on its own separate building, street entrance, and parking lot. You'd need twenty addresses memorized for one afternoon of errands. That's what you're doing right now exposing twenty microservices with twenty LoadBalancer Services. There's a saner way to run a mall, and a saner way to run a cluster. Let's fix it.

The problem: one cloud load balancer per Service gets expensive, fast

Rewind to Post 5. A LoadBalancer Service asks your cloud provider for a real, public-facing load balancer with its own external IP, sitting in front of one Service. That's the right tool for exposing one thing to the outside world.

The trouble starts when "one thing" becomes twenty things. Every LoadBalancer Service provisions its own cloud load balancer. Twenty microservices means twenty load balancers, twenty public IPs, twenty line items on your cloud bill — for traffic that could share one front door.

There's a second problem, and it's not just about cost. A LoadBalancer Service only understands L4 — Layer 4, meaning it reads IP addresses and ports, nothing else. It has no idea what an HTTP request actually says. It can't route "/api goes to the backend service" or "shoes.mall.com goes to the shoe service" — it just forwards whatever hits the port to whatever's behind it. Smart, content-aware routing — one address fanning requests out to many Services based on the URL — is simply out of reach for a plain Service.

Ingress: the rules for HTTP routing into your cluster

Ingress is the Kubernetes object built to solve exactly this. It's a set of HTTP(S) routing rules — "requests for this host go here," "requests for this path go there" — that sit in front of multiple Services, all reachable through one external entry point.

Here's the part that trips up almost everyone, so read it twice: an Ingress object, by itself, does nothing. It's YAML describing rules — intent, not running infrastructure. Nothing enforces those rules unless an Ingress Controller is running in your cluster.

The Ingress Controller — commonly ingress-nginx, though several exist — is the actual software that watches for Ingress objects, reads their rules, and does the routing. It runs as its own pods, usually fronted by one LoadBalancer Service for the whole controller. That single external IP becomes the door into your entire cluster's HTTP traffic. Write Ingress YAML with no controller installed, and you get a valid object sitting in etcd, doing precisely nothing.

Analogy: Back to the mall. A LoadBalancer per Service is every store getting its own building and street entrance. Ingress is the mall's better idea: one shared entrance, with a directory board just inside the door. Map it directly: Ingress is the directory board — it just lists rules, like "/electronics → second floor" or "shoes.mall.com → ground floor, shoe store." The Ingress Controller is the mall staff standing next to that board, actually walking each shopper down the right hallway. The board with no staff does nothing — a shopper can read "second floor" all day and never get there without someone directing them. That's an Ingress object with no controller: rules nobody enforces.

Path-based and host-based routing, in YAML

Here's one Ingress doing the two kinds of routing you'll see constantly: path-based (same domain, different URL paths) and host-based (different subdomains entirely).

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: mall.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: backend-service
            port:
              number: 80
      - path: /images
        pathType: Prefix
        backend:
          service:
            name: image-service
            port:
              number: 80
  - host: shoes.mall.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: shoe-service
            port:
              number: 80

Read it top to bottom: mall.example.com/api routes to backend-service, and mall.example.com/images routes to image-service — that's path-based routing, one domain split by URL. The separate hostname shoes.mall.example.com routes to shoe-service instead — that's host-based routing. One Ingress object, one Controller, one external IP, three backend Services fanned out to depending on what the request says.

pathType: Prefix means "match anything starting with this path" — the type you'll reach for most often. Each backend.service points at a normal ClusterIP Service, the same kind from Post 5. Ingress doesn't replace Services — it routes traffic to them.

TLS: letting Ingress handle HTTPS too

Ingress can also terminate HTTPS — meaning the Controller handles encryption, and your backend Services never have to worry about certificates at all. Add a tls section pointing at a Secret that holds the certificate and key:

spec:
  tls:
  - hosts:
    - mall.example.com
    secretName: mall-tls-secret
  rules:
  - host: mall.example.com
    ...

That Secret is a regular Kubernetes Secret (Post 6) of type kubernetes.io/tls, holding a cert and private key. In real setups, a separate tool called cert-manager usually creates and renews that Secret automatically — a topic for another day. For now, just know the tls block exists and roughly what it does.

On GKE specifically: Ingress means a real Google Cloud Load Balancer

Worth flagging early, since you'll hit this directly once the series gets you onto GCP: GKE ships with its own built-in Ingress Controller, based on GCE. Create an Ingress object on GKE with no extra setup, and GKE actually provisions a real Google Cloud Load Balancer for you behind the scenes. Same Ingress API — just know that on a real cloud, that YAML turns into real, billed infrastructure. More on this once we deploy there later in the series.

Trying it locally with minikube

If you're practicing on minikube, here's the one step people always forget: minikube doesn't ship with an Ingress Controller running by default. Turn it on explicitly:

$ minikube addons enable ingress
🔎  Verifying ingress addon...
🌟  The 'ingress' addon is enabled

That installs ingress-nginx into your minikube cluster. Once it's running, apply your Ingress object like any other resource:

$ kubectl apply -f ingress.yaml
ingress.networking.k8s.io/shop-ingress created

$ kubectl get ingress
NAME           CLASS   HOSTS                                    ADDRESS        PORTS   AGE
shop-ingress   nginx   mall.example.com,shoes.mall.example.com   192.168.49.2   80      45s

$ kubectl describe ingress shop-ingress
Name:             shop-ingress
Namespace:        default
Address:          192.168.49.2
Default backend:  <default>
Rules:
  Host                       Path  Backends
  ----                       ----  --------
  mall.example.com
                             /api     backend-service:80 (10.244.0.12:80)
                             /images  image-service:80 (10.244.0.13:80)
  shoes.mall.example.com
                             /        shoe-service:80 (10.244.0.14:80)

Check that ADDRESS field first — it's your quickest sanity check. Rules with no ADDRESS means something upstream is missing.

Try it yourself: On minikube, run minikube addons enable ingress, then create two small Deployments and ClusterIP Services (reuse the nginx pattern from Post 5). Write an Ingress with two path-based rules pointing at each, apply it, and check kubectl get ingress for an ADDRESS. Then add an /etc/hosts entry pointing a fake hostname at that address and confirm host-based routing works too by curling it.

The exam trap: no ingressClassName, no error, no routing

This one quietly wastes people's time, and it's exactly the kind of thing the CKA exam likes to probe: forget ingressClassName in your Ingress spec — or rely on a "default" IngressClass that doesn't actually exist in this cluster — and Kubernetes accepts your Ingress object anyway. kubectl apply succeeds. No error, nothing red. It just sits there forever, doing nothing, because no controller has claimed it.

Exam trap: If traffic through an Ingress isn't working, don't start by second-guessing your paths and hosts. Run kubectl describe ingress <name> first and check whether an ADDRESS was ever assigned — no address almost always means no controller picked up the object, usually because ingressClassName is missing or wrong. Then confirm a controller is actually running with something like kubectl get pods -n ingress-nginx. Only once a controller exists, is running, and has claimed your Ingress should you start doubting the routing rules themselves.

Key Takeaways

  • A LoadBalancer Service per microservice means one cloud load balancer per service — expensive at scale, and limited to L4 IP/port routing with no awareness of paths or hostnames.
  • Ingress is an API object describing HTTP(S) routing rules — host-based and path-based — sitting in front of multiple Services behind a single entry point.
  • Ingress does nothing on its own. An Ingress Controller (like ingress-nginx, or GKE's built-in GCE-based controller) must be running in the cluster to actually implement those rules.
  • Path-based routing splits traffic by URL on the same host; host-based routing splits by hostname entirely — both live in the same Ingress object's rules.
  • Ingress can terminate TLS via a tls block referencing a Secret holding your certificate, so backend Services never handle HTTPS themselves.
  • On GKE, creating an Ingress automatically provisions a real Google Cloud Load Balancer — directly relevant once you deploy there later.
  • On minikube, enable the controller explicitly with minikube addons enable ingress before anything will route.
  • If an Ingress isn't working, check kubectl describe ingress for a missing ADDRESS and confirm a controller is actually running before assuming your YAML is broken.

Next up: RBAC & Security Basics — controlling exactly who, and what, is allowed to do anything in your cluster.

Before you go

In one sentence, what was this chapter about?

From memory, without scrolling up. Writing it is what makes it yours; the grade is only to show you what you had.

How sure?