Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Ingress & Ingress Controller

Learn how Ingress and Ingress Controllers route external traffic to Kubernetes services. This lesson covers the core concepts, compares options, provides a hands-on walkthrough, and prepares you for next steps.

Focus: understand ingress and ingress controller

Sponsored

Imagine you have a dozen microservices running inside your Kubernetes cluster, each with its own ClusterIP Service. You want the whole world to reach them on yourapp.com/api and yourapp.com/dashboard — but the only way in so far is a clunky NodePort or a per-service LoadBalancer. Every new service burns a new cloud load balancer (cha-ching 💸) and you have to manually juggle hostnames and TLS certificates. There’s a smarter, unified way: Kubernetes Ingress combined with an Ingress Controller. This lesson will replace your port-forwarding cobwebs with a clean, scalable external routing layer.

The problem this lesson solves

Without Ingress, exposing services to the outside world is messy:

  • NodePort uses high ephemeral ports like 30080 — ugly for users.
  • LoadBalancer per service creates one cloud load balancer each (costly, slow).
  • No built-in support for host‑based routing (api.example.com vs app.example.com).
  • TLS termination must be handled per Service or offloaded to a reverse proxy.

An Ingress resource alone does nothing — it’s just a declarative wish. The real magic happens when an Ingress Controller (a reverse-proxy pod) reads that wish and configures the underlying proxy (like Nginx, Traefik, or HAProxy). The problem: new learners often confuse the resource with the controller and then wonder why nothing works.

Core concept / mental model

Think of Ingress as a router configuration file and the Ingress Controller as the router daemon that makes it real.

Layer Analogy Kubernetes component
Ingress (resource) A floor plan for the router YAML with rules, paths, TLS
Ingress Controller The router itself A Pod running Nginx/Traefik/HAProxy
Service A door to an apartment ClusterIP service pointing to Pods

Key definitions

  • Ingress resource: A Kubernetes API object (apiVersion: networking.k8s.io/v1, kind: Ingress) that defines rules for routing external HTTP/S traffic to Services based on hostnames and paths.
  • Ingress Controller: A running process (Pod) that watches the Kubernetes API for Ingress resources and configures its backend (e.g., Nginx) accordingly. Common controllers: ingress-nginx, traefik, haproxy-ingress, contour.

💡 Pro tip: If you create an Ingress resource without a controller installed, your Service stays unreachable from outside the cluster. The resource is just a declaration; the controller is the execution.

How it works step by step

  1. A user sends a request — e.g., curl https://api.example.com/users.
  2. DNS resolves the hostname to the IP of whichever load balancer fronts the cluster (cloud LB or node port).
  3. The load balancer forwards traffic to an Ingress Controller Pod (often running as a Deployment with hostNetwork or a Service of type LoadBalancer).
  4. The Ingress Controller matches the request against its internal routing table (built from Ingress resources).
  5. The request is proxied to the correct Kubernetes Service (e.g., api-service:8080).
  6. The Service load‑balances to one of its backing Pods.

Anatomy of an Ingress YAML

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx   # selects which controller handles this
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-svc
            port:
              number: 8080
  • ingressClassName: ties this resource to a specific controller (requires --watch-ingress-without-class or you set the class).
  • pathType: Prefix or Exact — determines path matching.
  • backend: which Service and port to route to.

Hands-on walkthrough

We’ll install the ingress-nginx controller (most common) and create an Ingress resource to route traffic to a simple hello-world Service.

Step 1: Install an Ingress Controller

Use Helm or plain manifests. Here’s with Helm:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx

Wait for the controller Pod to become ready:

kubectl get pods -n default -l app.kubernetes.io/name=ingress-nginx
# NAME                                        READY   STATUS    RESTARTS   AGE
# ingress-nginx-controller-7b8b6b7b9c-abcde   1/1     Running   0          2m

Check the Service type (it will be LoadBalancer if your cluster supports it):

kubectl get svc ingress-nginx-controller

If you’re using minikube, you can expose the controller with:

minikube service ingress-nginx-controller

Or tunnel to get a LoadBalancer IP:

minikube tunnel

Step 2: Deploy the backend Service and Pods

# hello.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: hello
  name: hello-pod
spec:
  containers:
  - image: hashicorp/http-echo:latest
    name: hello
    args: ["-text", "Hello from k8s!"]
---
apiVersion: v1
kind: Service
metadata:
  name: hello-svc
spec:
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 5678   # http-echo listens on 5678

Apply:

kubectl apply -f hello.yaml

Step 3: Create an Ingress resource

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

Apply:

kubectl apply -f ingress-hello.yaml

Step 4: Test the routing

Add a local /etc/hosts entry (or use the cluster’s external IP and a Host header):

curl -H "Host: hello.example.com" http://<EXTERNAL-IP>
# Hello from k8s!

💡 If you’re using minikube, run minikube ip to get the IP, then minikube tunnel in a separate terminal, and use the cluster IP from kubectl get svc ingress-nginx-controller.

Compare options / when to choose what

Controller Strengths Best for
ingress-nginx Huge community, flexible, supports TCP/UDP, Lua plugins General‑purpose, production
Traefik Auto‑discovery, nice dashboard, Let’s Encrypt built‑in Microservices heavy, edge routers
HAProxy Ingress Battle‑tested, low latency, advanced ACLs High‑traffic, security‑conscious
Contour Envoy proxy, gRPC support, dynamic config Envoy users, gRPC heavy
AWS ALB Ingress Controller Native AWS ALB, supports WebSocket EKS users with ALB integration

When to choose what: - Use ingress-nginx for most workloads — it’s the default choice. - Use Traefik if you want automatic Let’s Encrypt and a management dashboard. - Use HAProxy if you need extreme throughput or have complex access rules. - Use cloud‑native controllers (AWS ALB, GCE) if you want to offload load balancing to the cloud provider.

Troubleshooting & edge cases

Ingress resource created but no route works

  • Problem: kubectl get ingress shows the resource, but curl returns 502 or connection refused.
  • Check: Is the Ingress Controller running?

bash kubectl get pods -n ingress-nginx

  • Check: Does the controller’s Service have an external IP? If it’s pending, you may need metallb or minikube tunnel.

Wrong pathType causing 404

  • Exact matches only the literal path (e.g., /foo won’t match /foo/bar).
  • Prefix matches any subpath (e.g., /foo/bar matches /foo).
curl -H "Host: hello.example.com" http://<IP>/something
# 404 if pathType: Exact and path: /

Host header mismatch

  • If your Ingress rule has host: hello.example.com but you don’t send that Host header, the controller doesn’t match the rule.
  • Fix: curl -H "Host: hello.example.com" or use --resolve flags.

Multiple Ingress Controllers in the same cluster

  • You must use ingressClassName and each controller must be configured with a different --ingress-class flag (e.g., nginx vs traefik).
  • Omission of ingressClassName may default to the cluster’s default controller (if one is set).

TLS certificate not working

  • Certificates must be stored in a Secret in the same namespace as the Ingress resource.
spec:
  tls:
  - hosts:
    - hello.example.com
    secretName: hello-tls

What you learned & what's next

You now understand: - The difference between an Ingress resource and an Ingress Controller. - How to install an Ingress Controller (ingress-nginx via Helm). - How to create an Ingress resource with host‑based routing. - How to test the route end‑to‑end. - How to compare controller options (nginx, Traefik, HAProxy). - How to troubleshoot common issues (no controller, path matching, host headers).

Next lesson: Secure your Ingress with TLS/HTTPS — learn how to manage certificates using cert-manager.

Practice recap

Install the ingress-nginx controller (or another of your choice) into your cluster. Deploy a simple echo Pod and Service, then create an Ingress resource with a rule for echo.local and path /*. Add the IP and Host header to your /etc/hosts and test with curl. Once that works, try adding a second rule with a different hostname and path.

Common mistakes

  • Creating an Ingress resource without installing an Ingress Controller — the resource will be accepted but no traffic will be routed.
  • Using pathType: Exact expecting subpaths to match — / only matches the root; use Prefix for wildcard matching.
  • Forgetting to set the Host header in curl when testing local Ingress — without it the rule won’t match.
  • Leaving ingressClassName empty when multiple controllers exist — the wrong controller may pick it up or none at all.

Variations

  1. Use Traefik as a lightweight alternative — it supports automatic Let's Encrypt and a built-in dashboard.
  2. For cloud‑native environments, use the AWS Load Balancer Controller or GKE Ingress to offload to managed LBs.
  3. Run the Ingress Controller on hostNetwork mode instead of behind a LoadBalancer Service for bare‑metal setups.

Real-world use cases

  • Route api.example.com to an API Service and app.example.com to a frontend Service using the same Ingress.
  • Expose multiple microservices like orders, payments, and inventory on different paths under a single domain.
  • Terminate TLS at the Ingress Controller and forward unencrypted traffic to backend Services inside the cluster.

Key takeaways

  • Ingress is a routing resource; the Ingress Controller is the actual proxy that implements the rules.
  • Without an Ingress Controller, an Ingress resource does nothing — install one before creating rules.
  • Use ingressClassName to bind rules to a specific controller, especially in multi‑controller clusters.
  • Path types (Prefix vs Exact) determine how URL paths are matched — choose wisely.
  • Always verify routing with explicit Host headers during development to avoid mismatches.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.