DEV Community

iapilgrim
iapilgrim

Posted on

Phase 4 - Exposing Multiple Services on AKS Using NGINX Ingress

In this lab, we moved beyond a simple LoadBalancer and implemented Layer 7 routing using NGINX Ingress on:

  • Azure Kubernetes Service (AKS)
  • NGINX Ingress Controller

By the end, we achieved:

http://<PUBLIC-IP>/hello
http://<PUBLIC-IP>/api
Enter fullscreen mode Exit fullscreen mode

Using:

  • One public IP
  • One Ingress controller
  • Multiple backend services

๐Ÿ— Why Use Ingress Instead of LoadBalancer?

With a normal Service:

type: LoadBalancer
Enter fullscreen mode Exit fullscreen mode

You get:

1 Service = 1 Public IP
Enter fullscreen mode Exit fullscreen mode

That becomes expensive and hard to manage.

With Ingress:

1 Public IP
   โ†’ Multiple routes
   โ†’ Multiple services
Enter fullscreen mode Exit fullscreen mode

This is how real microservices platforms operate.


๐Ÿงฑ Architecture


Internet
   โ†“
Azure LoadBalancer (created by ingress)
   โ†“
NGINX Ingress Controller
   โ†“
hello-service
api-service
Enter fullscreen mode Exit fullscreen mode

The LoadBalancer is automatically created when installing the Ingress controller.


1๏ธโƒฃ Install NGINX Ingress Controller

We deployed the official controller:

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

Check readiness:

kubectl get pods -n ingress-nginx
Enter fullscreen mode Exit fullscreen mode

Verify service:

kubectl get svc -n ingress-nginx
Enter fullscreen mode Exit fullscreen mode

Wait until:

ingress-nginx-controller   LoadBalancer   <EXTERNAL-IP>
Enter fullscreen mode Exit fullscreen mode

That IP becomes your single entry point.


2๏ธโƒฃ Deploy Two Applications

A. Hello App

Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: <ACR_LOGIN_SERVER>/hello-aks:v1
        ports:
        - containerPort: 3000
Enter fullscreen mode Exit fullscreen mode

Service:

apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 3000
Enter fullscreen mode Exit fullscreen mode

B. API App (NGINX Demo)

Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: nginx
        ports:
        - containerPort: 80
Enter fullscreen mode Exit fullscreen mode

Service:

apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:
    app: api
  ports:
  - port: 80
    targetPort: 80
Enter fullscreen mode Exit fullscreen mode

3๏ธโƒฃ Create the Ingress Resource

Hereโ€™s the initial Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /hello
        pathType: Prefix
        backend:
          service:
            name: hello-service
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode

Apply it:

kubectl apply -f app-ingress.yaml
Enter fullscreen mode Exit fullscreen mode

4๏ธโƒฃ Testing the Routes

Test:

curl http://<INGRESS-IP>/hello
curl http://<INGRESS-IP>/api
Enter fullscreen mode Exit fullscreen mode

Result:

/hello โ†’ โœ… Works
/api   โ†’ โŒ 404 Not Found
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”Ž Why Did /api Return 404?

Important lesson:

Ingress forwarded:

/api โ†’ api-service
Enter fullscreen mode Exit fullscreen mode

But the nginx container only serves /.

It does NOT serve /api.

So nginx tried to serve /api as a file โ†’ it didnโ€™t exist โ†’ 404.

This was NOT an Ingress failure.

It was backend path behavior.


5๏ธโƒฃ Fixing with Rewrite Annotation

We added:

annotations:
  nginx.ingress.kubernetes.io/rewrite-target: /
Enter fullscreen mode Exit fullscreen mode

Updated Ingress:

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: /hello
        pathType: Prefix
        backend:
          service:
            name: hello-service
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode

Now:

/api โ†’ rewritten to /
Enter fullscreen mode Exit fullscreen mode

Test again:

/hello โ†’ Hello from AKS + ACR ๐Ÿš€
/api   โ†’ nginx welcome page
Enter fullscreen mode Exit fullscreen mode

Success โœ…


๐Ÿง  What You Learned

Ingress Controls:

Feature Controlled By
Path matching pathType
Routing backend service
URL rewrite annotation
TLS ingress spec

Key Insight:

Ingress does NOT automatically rewrite URLs.

You must explicitly define it.


๐Ÿ’ก Real-World Pattern

Typical SaaS architecture:

/api  โ†’ backend-service
/     โ†’ frontend-service
Enter fullscreen mode Exit fullscreen mode

All behind:

  • One public IP
  • One Ingress
  • TLS termination at Ingress

๐Ÿš€ Current Architecture

Internet
   โ†“
LoadBalancer
   โ†“
NGINX Ingress
   โ†“
hello-service
api-service
Enter fullscreen mode Exit fullscreen mode

You now have:

  • Layer 7 routing
  • Single entry point
  • Microservice-ready architecture
  • Production-aligned pattern

๐Ÿ”ฎ Next Evolution Steps

To move toward production-grade architecture:

  • Add HTTPS with cert-manager
  • Use custom domain
  • Add rate limiting
  • Add canary deployments
  • Add autoscaling
  • Replace nginx API with real backend
  • Move to Application Gateway + WAF

๐ŸŽฏ Final Takeaway

Youโ€™ve moved from:

Basic Service Exposure
Enter fullscreen mode Exit fullscreen mode

To:

Production-Style Ingress Routing
Enter fullscreen mode Exit fullscreen mode

Thatโ€™s a major step in Kubernetes maturity.

Top comments (0)