Skip to main content

Command Palette

Search for a command to run...

πŸš€ Kubernetes Ingress Explained: Enterprise Routing, Cost Optimization & Practical Setup

Updated
β€’8 min read

When people start learning Kubernetes, Services look powerful.

They provide:

  • Service discovery

  • Internal load balancing

  • External exposure (NodePort / LoadBalancer)

So naturally, the question arises:

If Services already expose applications, why do we need Ingress?

This blog will answer that β€” clearly, practically, and professionally.


πŸ“Œ 1. The Real Problem: Why Ingress Was Introduced

Before Kubernetes v1.1, Ingress did not exist.

Organizations used only:

  • Deployment

  • Service (ClusterIP / NodePort / LoadBalancer)

At first, everything looked good.

But as enterprises migrated from Virtual Machines β†’ Kubernetes, they started facing serious limitations.


🚨 Problem 1: Services Lack Enterprise Load Balancing Features

Kubernetes Services provide simple Round Robin load balancing via kube-proxy.

But enterprise load balancers like:

  • NGINX

  • F5

  • HAProxy

  • Traefik

Support advanced features such as:

  • βœ… Sticky Sessions

  • βœ… Path-based routing (/app1, /app2)

  • βœ… Host-based routing (amazon.com, amazon.in)

  • βœ… TLS/SSL termination

  • βœ… IP whitelisting / blacklisting

  • βœ… Ratio-based load balancing

  • βœ… Web Application Firewall

Kubernetes Services do NOT support these features natively.

This was a major gap.


πŸ’° Problem 2: Cost Explosion with LoadBalancer Services

If you create:

type: LoadBalancer

Kubernetes asks the cloud provider for a static public IP.

Now imagine:

  • 200 microservices

  • 200 LoadBalancer services

  • 200 public static IPs

Cloud providers charge for each static IP.

This becomes expensive very quickly.

In traditional VM architecture:

πŸ‘‰ One Load Balancer

πŸ‘‰ One Public IP

πŸ‘‰ Routes traffic internally

But in Kubernetes without Ingress:

πŸ‘‰ One Service = One IP

πŸ‘‰ High cost


🎯 Enter Kubernetes Ingress

Ingress solves BOTH problems:

Problem Ingress Solution
Missing enterprise routing Supports path, host, TLS, security
Too many public IPs One Ingress, one IP, many services

🧠 2. Understanding Ingress Architecture (Very Important)

This is where many people get confused.

Ingress has two parts:


1️⃣ Ingress Resource (YAML)

This is just a configuration file.

Example:

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

🧠 What Is This YAML Actually Doing?

This YAML file is creating a routing rule inside Kubernetes.

It tells Kubernetes:

  • Watch for requests coming to the domain foo.bar.com

  • If the request path starts with /

  • Forward that traffic to the Service named flask-service

  • The Service will then send the request to one of the running Pods

In simple terms:

This file does not expose your application directly.
It only defines how traffic should be routed once an Ingress Controller is available.


2️⃣ Ingress Controller (The Brain)

Ingress Controller is:

The actual load balancer implementation.

Kubernetes does NOT ship with one by default.

You must install it.

Examples:

  • NGINX Ingress Controller

  • HAProxy Ingress

  • Traefik

  • F5

  • Ambassador

The controller:

  • Watches Ingress resources

  • Updates load balancer configuration

  • Applies routing logic

Without controller:

πŸ‘‰ Ingress resource is ignored.


πŸ— 3. Practical Demo: Setting Up Ingress on Minikube

Now let's move to hands-on.

🧱 Prerequisite: Service Setup

If you have not created a Deployment and Service yet, you can use the complete setup from my previous blog.

πŸ”— Previous Blog (Service Practical Walkthrough):
https://codeops-labshashnodedev.hashnode.dev/kubernetes-services-deep-dive-service-discovery-nodeport-load-balancing-practical-walkthrough

πŸ”— GitHub Repository:
https://github.com/Kunja-Ravikiran/k8s-service-deep-dive

This repository includes:

Deployment YAML

Service YAML

NodePort setup

Working example used in this blog

Simply clone the repository and apply the manifests:

git clone https://github.com/Kunja-Ravikiran/k8s-service-deep-dive
cd k8s-service-deep-dive
cd k8s
kubectl apply -f deployment.yaml
kubectl apply -f service-nodeport.yaml

Once your service is running, continue with the Ingress setup explained below.


Step 1️⃣ Verify Existing Service

From your previous setup:

kubectl get svc

Example output:

NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
flask-service   LoadBalancer   10.109.52.192   <pending>     80:32697/TCP   2m58s
kubernetes      ClusterIP      10.96.0.1       <none>        443/TCP        11h

(Your service is of type LoadBalancer. In Minikube, since no real cloud load balancer exists, we access it using the allocated NodePort.)

You can access it using the Minikube IP and the NodePort:

minikube ip

Example:

192.168.49.2

Now access using the NodePort shown in the PORT(S) column (32697 in this case):

curl http://192.168.49.2:32697

Output:

<h1>Kubernetes Service Deep Dive πŸš€</h1>
<p><strong>Pod Name:</strong> flask-app-f4646f58c-w6vz7</p>
<p>This response helps demonstrate load balancing.</p>

⚠️ Note: If you try a different port (for example 30007), it will fail because Kubernetes dynamically assigns the NodePort unless explicitly defined.


Step 2️⃣ Create Ingress Resource

Create:

vim ingress.yaml

Paste:

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

🧠 What Are We Doing Here?

Here we are creating an Ingress resource and defining how external traffic should be routed inside the cluster.

In simple terms, we are saying:

  • If a request comes to foo.bar.com

  • And the path is /

  • Then forward that traffic to the flask-service on port 80

This is called host-based + path-based routing.

At this point, we are only defining the rule in Kubernetes.
The actual routing will happen only when an Ingress Controller reads this configuration and applies it.

Apply:

kubectl apply -f ingress.yaml

Check:

kubectl get ingress

Output:

NAME              CLASS    HOSTS         ADDRESS   PORTS   AGE
ingress-example   <none>   foo.bar.com             80      7s

You will notice:

πŸ‘‰ The ADDRESS field is empty
πŸ‘‰ The Ingress is created, but it is not working yet

Why?

Because the Ingress Controller is not installed.


πŸš€ Step 3️⃣ Install Ingress Controller (Minikube)

Enable addon:

minikube addons enable ingress

Output:

πŸ’‘  ingress is an addon maintained by Kubernetes.
    β–ͺ Using image registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.6.5
    β–ͺ Using image registry.k8s.io/ingress-nginx/controller:v1.14.1
πŸ”Ž  Verifying ingress addon...
🌟  The 'ingress' addon is enabled

Now verify:

kubectl get pods -A | grep nginx

Output:

ingress-nginx   ingress-nginx-admission-create-65cqx        0/1     Completed   0              82s
ingress-nginx   ingress-nginx-admission-patch-4bx6h         0/1     Completed   1              82s
ingress-nginx   ingress-nginx-controller-8675c6b56f-4nds5   1/1     Running     0              82s

Notice:

πŸ‘‰ ingress-nginx-controller is in Running state

This confirms the Ingress Controller is successfully installed.


Now check:

kubectl get ingress

Output:

NAME              CLASS    HOSTS         ADDRESS        PORTS   AGE
ingress-example   <none>   foo.bar.com   192.168.49.2   80      6m27s

You will now see:

πŸ‘‰ The ADDRESS field is populated (192.168.49.2)

This means:

The Ingress Controller has picked up your routing rules and assigned an IP address.


πŸ–₯ Step 4️⃣ Local Testing (Important Trick)

Since foo.bar.com is not a real domain:

You must update:

sudo vim /etc/hosts

Add:

<ingress-ip> foo.bar.com

Now test:

curl http://foo.bar.com/

Boom πŸ’₯

It works.


πŸ” Bonus: TLS with Ingress

Ingress also supports:

tls:
  - hosts:
    - foo.bar.com
    secretName: tls-secret

This allows:

  • HTTPS traffic

  • SSL termination

  • Secure routing

Enterprise-grade setup.


🧩 4. Visual Flow of Ingress

Here’s the traffic flow:

User β†’ Ingress Controller β†’ Service β†’ Pod

Instead of:

User β†’ Service (LoadBalancer)

Now:

  • One Ingress

  • One IP

  • Multiple services

  • Advanced routing


LoadBalancer Service vs Ingress

Feature LoadBalancer Ingress
IP per service Yes No
Cost High Low
Path routing No Yes
Host routing No Yes
TLS termination Limited Yes
Enterprise features No Yes

🏭 Production Reality

In production:

  • You don’t edit /etc/hosts

  • DNS maps domain to Ingress IP

  • Ingress controller runs in dedicated namespace

  • Often deployed via Helm

  • Can integrate with API Gateway

Common real-world controllers:

  • NGINX

  • Traefik

  • AWS ALB Ingress Controller

  • HAProxy


πŸ“Œ Key Takeaways

  • Kubernetes Services are basic load balancers.

  • Ingress adds enterprise routing features.

  • Ingress reduces cloud cost significantly.

  • Ingress requires an Ingress Controller.

  • One Ingress can manage hundreds of services.

Kubernetes Deep Dive – From Basics to Production

Part 5 of 8

A hands-on Kubernetes series covering core concepts like Pods, ReplicaSets, and Deployments, progressing toward real-world application deployments with kubectl commands, YAML examples, and practical DevOps insights.

Up next

Kubernetes ConfigMaps & Secrets Explained (With Practical Examples)

Modern applications rarely run with fixed configuration. A typical application needs values like: Database host Port number API endpoints Feature flags Authentication credentials If these value