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
kubectlconfigured 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:
| Type | Name | Value |
|---|---|---|
| A | app1 | <Ingress Controller EXTERNAL-IP> |
| A | app2 | <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.comandapp2.yourdomain.comwith 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.comhttps://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/cyclehttps://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.