Skip to main content

Kubernetes Ingress on E2E Kubernetes

This document explains how NGINX Ingress and cert-manager work together on an E2E Kubernetes Cluster to provide secure HTTP/HTTPS access to applications using automatic TLS certificates from Let's Encrypt.

Overview

This document describes how to expose applications running on an E2E Kubernetes Cluster using Kubernetes Ingress. It covers:

  • The purpose and architecture of Ingress
  • Why Ingress is required in cloud environments
  • Host-based and path-based routing
  • Secure HTTPS access using cert-manager and Let's Encrypt
  • A complete, from-scratch implementation using separate YAML files

Features Implemented:

  • Host-based routing
  • Path-based routing
  • HTTPS using Let's Encrypt

What Is Kubernetes Ingress?

Ingress is a Kubernetes API object that manages external HTTP and HTTPS access to services within a cluster.

Ingress provides a single, centralized entry point for incoming traffic and routes requests to backend services based on:

  • Hostnames (for example, app1.example.com)
  • URL paths (for example, /api, /app)

Ingress does not handle traffic directly. It requires an Ingress Controller, such as NGINX Ingress, which:

  • Listens for external traffic
  • Applies routing rules
  • Terminates TLS (HTTPS)
  • Forwards traffic to Kubernetes Services

Why Ingress Is Required

Exposing applications using only LoadBalancer Services has several limitations:

  • Each service requires a separate public IP
  • No support for host-based or path-based routing
  • TLS certificates must be managed per service
  • Higher cost and operational overhead

Ingress addresses these challenges by:

  • Sharing a single LoadBalancer across multiple applications
  • Supporting advanced HTTP routing
  • Centralizing TLS configuration
  • Reducing infrastructure cost
  • Enabling consistent traffic management

On E2E Kubernetes:

  • The Ingress Controller Service is of type LoadBalancer
  • A public IP is assigned from the E2E Dashboard
  • DNS records point application domains to this IP

Prerequisites

  • An active E2E Kubernetes Cluster
  • kubectl configured with cluster access
  • Domain ownership
  • Public IP reserved and attached to the cluster

For steps to reserve and attach a LoadBalancer IP, see Kubernetes Services — Assigning an External IP.

Implementation Guide

Step 1: Deploy Backend Applications

Application 1 – Deployment

app1-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: app1
spec:
replicas: 2
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: praveen22233/cycle
ports:
- containerPort: 80

Apply:

kubectl apply -f app1-deployment.yaml

Application 1 – Service

app1-service.yaml

apiVersion: v1
kind: Service
metadata:
name: app1-service
spec:
type: ClusterIP
selector:
app: app1
ports:
- port: 80
targetPort: 80

Apply:

kubectl apply -f app1-service.yaml
kubectl get svc

Application 2 – Deployment

app2-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: app2
spec:
replicas: 2
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: app2
image: vijayarangan2002/myapp:8
ports:
- containerPort: 80

Apply:

kubectl apply -f app2-deployment.yaml
kubectl get pods

Application 2 – Service

app2-service.yaml

apiVersion: v1
kind: Service
metadata:
name: app2-service
spec:
type: ClusterIP
selector:
app: app2
ports:
- port: 80
targetPort: 80

Apply:

kubectl apply -f app2-service.yaml
kubectl get svc

Step 2: Install NGINX Ingress Controller

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

Verify:

kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Ensure the controller Service has an EXTERNAL-IP assigned. For steps to assign an IP, see LB IP Pool configuration.

Step 3: Configure DNS Records

Create DNS A records for your subdomains in the E2E DNS Management Portal, pointing to the Ingress Controller EXTERNAL-IP:

TypeNameValue
Aapp1<Ingress Controller EXTERNAL-IP>
Aapp2<Ingress Controller EXTERNAL-IP>

Step 4: Install cert-manager

kubectl create namespace cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml

Verify:

kubectl get pods -n cert-manager

For a more detailed guide on cert-manager configuration and certificate management, see Cert-Manager.

Step 5: Configure Let's Encrypt ClusterIssuer

clusterissuer.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: your-email@yourdomain.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx

Apply:

kubectl apply -f clusterissuer.yaml
kubectl get clusterissuer

Step 6: Create Ingress with Host-Based Routing and TLS

host-based-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: result-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- app1.yourdomain.com
secretName: app1-yourdomain-com-tls
- hosts:
- app2.yourdomain.com
secretName: app2-yourdomain-com-tls
rules:
- host: app1.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- host: app2.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80

Replace app1.yourdomain.com and app2.yourdomain.com with your actual domain names.

Apply:

kubectl apply -f host-based-ingress.yaml

Step 7: Verification

kubectl get ingress
kubectl get certificate

Access applications:

  • https://app1.yourdomain.com
  • https://app2.yourdomain.com

Path-Based Routing

To route traffic based on URL paths instead of subdomains, use the following Ingress configuration:

path-based-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: result-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- app1.yourdomain.com
secretName: app1-yourdomain-com-tls
- hosts:
- app2.yourdomain.com
secretName: app2-yourdomain-com-tls
rules:
- host: app1.yourdomain.com
http:
paths:
- path: /cycle
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- host: app2.yourdomain.com
http:
paths:
- path: /hotel
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80

Apply:

kubectl apply -f path-based-ingress.yaml

Access the applications:

  • https://app1.yourdomain.com/cycle
  • https://app2.yourdomain.com/hotel

Recommendation: Migrate to Gateway API

While Ingress remains functional today, Ingress NGINX is no longer recommended for new production deployments.

The Kubernetes community strongly recommends migrating to Gateway API, which is the modern and standardized replacement for Ingress.

Reference: https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/

Why Gateway API?

Gateway API provides:

  • Clear separation of responsibilities (infra vs application teams)
  • Standardized behavior across implementations
  • Native support for advanced traffic management
  • Better security and long-term support
  • First-class Kubernetes API design

For the recommended modern approach, see Kubernetes Gateway API.