Ingress

4 minute read

So far, we’ve used Services (NodePort, LoadBalancer) to expose applications externally. But what if you have 10 microservices? You’d need 10 LoadBalancers — that’s expensive and hard to manage. Ingress solves this by providing a single entry point with HTTP/HTTPS routing to multiple Services.

What is Ingress?

Ingress is a Kubernetes resource that manages external HTTP/HTTPS access to Services. It provides:

  • Path-based routing — /api → API Service, /web → Web Service
  • Host-based routing — api.example.com → API Service, web.example.com → Web Service
  • TLS termination — HTTPS with certificates
  • Load balancing — Distribute traffic across backends
  • Single entry point — One IP/domain for all Services
                    Internet
                       │
               ┌───────▼───────┐
               │    Ingress     │
               │   Controller   │
               │   (nginx)      │
               └───┬───┬───┬───┘
                   │   │   │
          /api     │   │   │  /web
       ┌───────────┘   │   └───────────┐
       ▼               ▼               ▼
  ┌─────────┐   ┌─────────┐   ┌─────────┐
  │API Svc  │   │Auth Svc │   │Web Svc  │
  │         │   │         │   │         │
  └─────────┘   └─────────┘   └─────────┘

Ingress vs. Service Types

Feature NodePort LoadBalancer Ingress
Layer L4 (TCP/UDP) L4 (TCP/UDP) L7 (HTTP/HTTPS)
Cost Free $$$ per Service $ (one LB for all)
Path routing ❌ ❌ ✅
Host routing ❌ ❌ ✅
TLS termination ❌ Cloud-dependent ✅
Best for Development Single service Multiple HTTP services

Ingress Controller

Important: An Ingress resource alone does nothing. You need an Ingress Controller — a reverse proxy that reads Ingress resources and configures routing.

Popular Ingress controllers:

Controller Notes
NGINX Ingress Controller Most popular. Open source.
Traefik Auto-discovery. Great for microservices.
HAProxy High performance. Enterprise-ready.
Istio Gateway Service mesh integration.
AWS ALB Ingress Uses AWS Application Load Balancer.
GKE Ingress Uses Google Cloud Load Balancer.

Install NGINX Ingress Controller on Minikube

# Enable the Ingress addon in Minikube
minikube addons enable ingress

# Verify it's running
kubectl get pods -n ingress-nginx

Basic Ingress — Path-Based Routing

Route different URL paths to different Services:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80

Path Types

Type Behavior Example
Prefix Matches URL path prefix /api matches /api, /api/v1, /api/users
Exact Matches the exact path only /api matches only /api, not /api/v1
ImplementationSpecific Depends on the IngressClass Controller decides

Host-Based Routing

Route different domains to different Services:

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

TLS / HTTPS

Create a TLS Secret

# Generate a self-signed certificate (for testing)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key -out tls.crt \
  -subj "/CN=myapp.example.com"

# Create the Secret
kubectl create secret tls myapp-tls --cert=tls.crt --key=tls.key

Configure TLS in Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-service
            port:
              number: 80

Traffic to https://myapp.example.com is terminated at the Ingress Controller, and forwarded as HTTP to the backend Service.

Default Backend

Handle requests that don’t match any rule:

spec:
  defaultBackend:
    service:
      name: default-service
      port:
        number: 80
  rules:
  - host: api.example.com
    # ...

Useful Annotations (NGINX)

Annotation Purpose
nginx.ingress.kubernetes.io/rewrite-target: / Rewrite URL path
nginx.ingress.kubernetes.io/ssl-redirect: "true" Force HTTPS
nginx.ingress.kubernetes.io/proxy-body-size: "10m" Max upload size
nginx.ingress.kubernetes.io/rate-limit: "10" Rate limiting
nginx.ingress.kubernetes.io/cors-allow-origin: "*" CORS headers
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30" Backend timeout

Hands-On: Complete Example with Minikube

# demo-ingress.yaml
# Backend Services
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
      version: v1
  template:
    metadata:
      labels:
        app: hello
        version: v1
    spec:
      containers:
      - name: hello
        image: hashicorp/http-echo
        args: ["-text=Hello from V1!"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: hello-v1
spec:
  selector:
    app: hello
    version: v1
  ports:
  - port: 80
    targetPort: 5678
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-v2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
      version: v2
  template:
    metadata:
      labels:
        app: hello
        version: v2
    spec:
      containers:
      - name: hello
        image: hashicorp/http-echo
        args: ["-text=Hello from V2!"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: hello-v2
spec:
  selector:
    app: hello
    version: v2
  ports:
  - port: 80
    targetPort: 5678
---
# Ingress routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: hello-v1
            port:
              number: 80
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: hello-v2
            port:
              number: 80
# Apply everything
kubectl apply -f demo-ingress.yaml

# Get the Ingress IP
kubectl get ingress hello-ingress

# In Minikube, get the Ingress IP
minikube ip

# Test routing
curl http://$(minikube ip)/v1    # Hello from V1!
curl http://$(minikube ip)/v2    # Hello from V2!

Inspecting Ingress

# List Ingress resources
kubectl get ingress

# Detailed info
kubectl describe ingress hello-ingress

# Check Ingress Controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller

Summary

  • Ingress provides L7 (HTTP/HTTPS) routing to Services
  • Requires an Ingress Controller (NGINX, Traefik, etc.)
  • Supports path-based and host-based routing
  • Handles TLS termination for HTTPS
  • One Ingress can route to multiple Services — saves cost vs. multiple LoadBalancers
  • Use annotations to configure controller-specific behavior

What’s Next?

Now that traffic can reach your Pods, let’s learn how to control which Pods can communicate with each other using Network Policies — Kubernetes’ built-in firewall rules.

Next: Network Policies →

Updated: