Skip to main content

Command Palette

Search for a command to run...

Demystifying Kubernetes Ingress: The Ultimate Traffic Cop for Your Apps

Updated
10 min read
Demystifying Kubernetes Ingress: The Ultimate Traffic Cop for Your Apps
J
IT Professional with 4+ years of combined experience across Software Engineering, DevOps, Cloud, Technical Writing, and AI-assisted Development. Passionate about building things, simplifying complex technology, and continuously learning while sharing knowledge through hands-on experimentation and technical writing.

As applications grow and need to be accessed from outside the cluster, Kubernetes introduces another important concept: Ingress.

Ingress is designed to manage external traffic and provide advanced routing capabilities that go beyond what a standard Service can offer.

Common questions include:

If Kubernetes Services already provide load balancing, why do we need Ingress? What problem does Ingress solve? What is an Ingress Controller? How is it used in real projects?

In this article, we'll explore these concepts step by step using simple examples and practical scenarios so you can clearly understand why Ingress is an essential part of modern Kubernetes deployments.


Before Ingress: How Applications Were Exposed

Let's imagine you have deployed an application inside a Kubernetes cluster.

For example:

  • Frontend Application

  • Backend API

  • Authentication Service

Each application runs inside Pods.

Since Pods can be created and destroyed dynamically, users cannot directly access them. Kubernetes solves this problem using Services.

A Service provides:

  • Service discovery

  • Stable networking

  • Basic load balancing

For example:

User → Service → Pod 

If there are multiple Pods:

 
User → Service →Pod-1 
                    Pod-2 
                     Pod-3

The Service distributes requests among the Pods using a simple round-robin mechanism.

This works well for many situations.


The Problem: Why Can't We Just Use Services?

Suppose a company is running multiple application services:

user-service 
order-service 
payment-service 
inventory-service 
notification-service

Making each service publicly accessible through its own LoadBalancer would create several challenges:

For every application, Kubernetes requests a separate cloud load balancer.

So, the architecture becomes:

LoadBalancer-1 → user-service 
LoadBalancer-2 → order-service 
LoadBalancer-3 → payment-service 
LoadBalancer-4 → inventory-service 
LoadBalancer-5 → notification-service

This creates two major problems.


Problem 1: Increased Cost

Cloud providers charge for Load Balancers and public IP addresses.

If you have:

5 applications
50 applications
500 microservices

You may end up creating many Load Balancers.

More Load Balancers means:

  • More public IPs

  • More cloud costs

  • More management overhead

For organizations running hundreds of services, this becomes expensive.


Problem 2: Missing Enterprise Features

Kubernetes Services provide basic load balancing.

However, enterprise environments often need advanced features such as:

  • Path-based routing

  • Host-based routing

  • SSL/TLS termination

  • Sticky sessions

  • Traffic filtering

  • Advanced routing rules

Traditional load balancers like:

  • NGINX

  • F5

  • HAProxy

already provided these features.

When companies migrated from virtual machines to Kubernetes, they realized these capabilities were missing from standard Services.


The Solution: Kubernetes Ingress

To solve these problems, Kubernetes introduced Ingress.

Ingress is a Kubernetes resource that manages external access to services inside the cluster.

Instead of exposing every application through a separate Load Balancer, Ingress allows multiple applications to share a single-entry point.

Real-World Example

Suppose you have:

* Frontend Service 
* Backend Service 
* Admin Service 

With Ingress:

Now a single external endpoint can route traffic to different services.

This is called Path-Based Routing.


Host-Based Routing

Ingress can also route traffic based on domain names.

Example:

Different domains can point to different services while using the same Ingress infrastructure.

This is known as Host-Based Routing.


The Two Parts of Ingress

To make Ingress work in your cluster, you need to understand two key concepts:

Ingress Controller (The Engine):

  • Think of this as the actual physical front desk and the person sitting there. Kubernetes doesn't install this by default. You have to install an Ingress Controller software into your cluster. The most popular one used in the community is the NGINX Ingress Controller.

Ingress Resources (The Rule Book):

  • This is a simple YAML configuration file that you write. It is the set of instructions you hand to the Ingress Controller saying: "Hey, if a user types /billing, send them to the billing service!"

What Is an Ingress Controller?

A common misconception is that creating an Ingress resource (YAML manifest) automatically starts routing traffic.

It does not.

Ingress is only a set of rules. Something must read those rules and implement them. That component is called an Ingress Controller.

The controller is the actual component that:

  • Watches Ingress resources

  • Reads routing rules

  • Configures the underlying proxy (NGINX, Traefik, HAProxy, etc.)

  • Routes traffic to Services

There are multiple Ingress Controllers available, such as:

  • NGINX Ingress Controller

  • Traefik

  • HAProxy Ingress

  • F5 Ingress Controller

  • Ambassador

  • AWS ALB Ingress Controller (cloud-native)

Among these, NGINX Ingress Controller is one of the most commonly used in learning and production environments.

You can explore different options here:

👉 https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/


Installing an Ingress Controller

An Ingress resource only defines routing rules. To make those rules work, you must install an Ingress Controller in your cluster. You can go through the official documentation of any ingress controller you want to install.

One of the most common choices is the NGINX Ingress Controller.

Using Helm:

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

Using kubectl with the official manifests:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml 

After installation, verify that the controller is running:

kubectl get pods -n ingress-nginx 

You should see the controller Pods in a Running state. Once the controller is installed, any Ingress resources you create can be processed and used for routing traffic to Kubernetes Services.


Kubernetes Configuration Flow


Minikube Ingress Setup (Local Development Example)

For local Kubernetes setups like Minikube, Kubernetes provides a simple way to enable Ingress:

👉 https://v1-32.docs.kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/

Step 1: Enable Ingress Controller in Minikube

minikube addons enable ingress 

This installs the NGINX Ingress Controller inside the cluster.

Application Setup

In this demo, a simple application (Mongo Express) is deployed with:

1. Pod (Application Layer)

  • Mongo Express runs inside Kubernetes Pods.

2. Service (Internal Exposure)

  • A Service exposes the Pods internally:

    apiVersion: v1
    kind: Service
    metadata:
      name: mongo-express-service
      namespace: test
    spec:
      selector:
        app: mongo-express              
      type: NodePort # Exposes the web UI outside cluster                    
      ports:
        - protocol: TCP
          port: 8081                   
          targetPort: 8081              
          nodePort: 30001    
    

This ensures stable internal access to Pods.


Ingress Resource Configuration

We then define an Ingress rule:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-host 
  namespace: test # Must be in the same namespace as the mongo-express Service.
spec:
  ingressClassName: nginx # Uses the NGINX Ingress Controller
  rules:
    - host: mongo.express.example # This hostname must resolve
      http:
        paths:
          - path: / # Route every request for this host to the mongo-express Service.
            pathType: Prefix
            backend:
              service:
                name: mongo-express-service
                port:
                  number: 8081

Then apply the Ingress manifest:

kubectl apply -f ingress.yml

Check that the Ingress was created:

kubectl get ingress -n test

Expected host:

mongo.express.example

How the Request Flows

Once everything is deployed, the traffic flow looks like this:


Local Testing with Minikube

Since local clusters do not have public DNS, we simulate it using /etc/hosts:

192.168.49.2 mongo.express.example

Then we test:

curl http://mongo.express.example

Or validate routing explicitly:

curl --resolve "mongo.express.example:80:$(minikube ip)" \
     http://mongo.express.example

Troubleshooting Insights (Real-World Learning)

During setup, several issues may appear that are not actually Ingress problems:

1. Wrong Service Port

Ingress must point to the correct Service port (8081 vs 8080 mismatch can break routing).

2. DNS vs Network Confusion

Even if DNS resolves correctly, the system may still fail if the machine cannot reach the cluster network.

3. Minikube Driver Networking

When using Docker/WSL drivers:

  • WSL can access Minikube network

  • Windows may not directly access Minikube IP

This leads to situations where:

  • Ingress works internally

  • But browser access fails externally


Enterprise Perspective: How Ingress Works in Real-World Kubernetes Environments

The Minikube example helps us understand the fundamentals of Ingress, but production environments typically introduce additional networking layers and traffic management requirements.

In real production environments, the same architecture is used but scaled:

  • Ingress Controller runs on dedicated nodes or cloud load balancers

  • DNS is managed via Route53 / Cloud DNS / corporate DNS

  • TLS is configured using cert-manager or cloud providers

  • Multiple services are routed using host-based rules


A common enterprise architecture looks like this:

User / Client
    │
    ▼
DNS
    │
    ▼
External Load Balancer
    │
    ▼
NGINX Ingress Controller
    │
    ▼
Kubernetes Services
    │
    ▼
Application Pods

For example, in AWS:

app.company.com
    │
    ▼
AWS Application Load Balancer
    │
    ▼
NGINX Ingress Controller Pods
    │
    ▼
app-service
    │
    ▼
Application Pods

At first glance, this may seem similar to the Minikube setup, but each layer has a specific responsibility.


Layer 1: External Load Balancer

The cloud or infrastructure load balancer acts as the public entry point to the Kubernetes cluster.

Its responsibilities include:

  • Receiving internet traffic

  • Distributing requests to healthy ingress controller instances

  • Health checking

  • High availability across nodes or availability zones

Internet
    │
    ▼
Load Balancer
    │
    ▼
NGINX Ingress Controller Pods

Layer 2: NGINX Ingress Controller

The Ingress Controller operates at the HTTP/HTTPS layer and provides application-aware routing.

Typical enterprise features include:

Host-based routing                Rate limiting
Path-based routing                Request size limits
TLS/SSL termination               CORS handling
HTTP to HTTPS redirection         Authentication integration
Header manipulation               WebSocket support
Canary deployments                Blue/Green deployments
Centralized ingress logging

Example routing rules:

api.company.com/users → user-service 
api.company.com/orders → order-service 
admin.company.com → admin-service

This allows many applications to share a single public entry point.


Layer 3: Kubernetes Services

After the Ingress Controller determines the destination, traffic is forwarded to a Kubernetes Service.

The Service then distributes traffic across available Pods.

payment-service
    ├── payment-pod-1
    ├── payment-pod-2
    └── payment-pod-3

This means load balancing occurs at multiple layers:

External Load Balancer
        │
        ▼
Ingress Controller Replicas
        │
        ▼
Kubernetes Services
        │
        ▼
Application Pods

Most organizations follow this pattern:

Few External Load Balancers
            │
            ▼
One or More Ingress Controllers
            │
            ▼
Many Internal ClusterIP Services

This provides a centralized and scalable traffic management architecture.


Typical Production Setup

A common Kubernetes deployment looks like this:

The individual application services usually remain internal:

spec:
  type: ClusterIP

while the Ingress Controller itself is typically exposed through a:

spec:
  type: LoadBalancer

service.


Scaling in Enterprise Environments

Scaling happens at several layers simultaneously.

External Load Balancer
        │
        ▼
Multiple Ingress Controller Replicas
        │
        ▼
Kubernetes Services
        │
        ▼
Multiple Application Pods

For example:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment
spec:
  replicas: 5

The Ingress Controller routes traffic to the Service, and the Service distributes requests across all available Pod replicas


Conclusion

Kubernetes Services are excellent for service discovery and basic load balancing, but they have limitations when applications need advanced routing and enterprise-grade traffic management.

Ingress solves these problems by:

  • Reducing cloud costs

  • Supporting path-based routing/host-based routing

  • Enabling SSL/TLS termination

Providing a single-entry point for multiple applications

However, an Ingress resource alone is not enough. You also need an Ingress Controller such as NGINX to enforce the routing rules.

If Services are the roads connecting applications inside Kubernetes, then Ingress is the smart traffic controller that decides where external requests should go.

More from this blog

D

Demystifying Tech with Jasai

104 posts

Demystifying Tech with Jasai is a blog dedicated to breaking down complex tech concepts into clear, beginner-friendly explanations. Covering DevOps, Docker, Git, AWS, CI/CD, Networking, and core programming fundamentals, it emphasizes strong foundations before advanced topics. Through step-by-step walkthroughs and real-world analogies, it simplifies the why behind the how — making technology approachable, structured, and built for long-term growth.