# 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. {/* TODO: Add Kubernetes Ingress Traffic Flow Architecture diagram */} ## 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](/docs/myaccount/kubernetes/kubernetes_services/#assigning-an-external-ip-for-loadbalancer-service-on-e2e-kubernetes). ## Implementation Guide ### Step 1: Deploy Backend Applications #### Application 1 – Deployment `app1-deployment.yaml` ```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: ```bash kubectl apply -f app1-deployment.yaml ``` {/* TODO: Add screenshot of kubectl get pods showing app1 pods Running */} #### Application 1 – Service `app1-service.yaml` ```yaml apiVersion: v1 kind: Service metadata: name: app1-service spec: type: ClusterIP selector: app: app1 ports: - port: 80 targetPort: 80 ``` Apply: ```bash kubectl apply -f app1-service.yaml kubectl get svc ``` {/* TODO: Add screenshot of kubectl get svc showing app1-service ClusterIP */} #### Application 2 – Deployment `app2-deployment.yaml` ```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: ```bash kubectl apply -f app2-deployment.yaml kubectl get pods ``` {/* TODO: Add screenshot of kubectl get pods showing all app1 and app2 pods Running */} #### Application 2 – Service `app2-service.yaml` ```yaml apiVersion: v1 kind: Service metadata: name: app2-service spec: type: ClusterIP selector: app: app2 ports: - port: 80 targetPort: 80 ``` Apply: ```bash kubectl apply -f app2-service.yaml kubectl get svc ``` {/* TODO: Add screenshot of kubectl get svc showing both app1-service and app2-service */} ### Step 2: Install NGINX Ingress Controller ```bash kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.6/deploy/static/provider/cloud/deploy.yaml ``` {/* TODO: Add screenshot of kubectl apply output showing ingress-nginx resources created */} Verify: ```bash kubectl get pods -n ingress-nginx kubectl get svc -n ingress-nginx ``` {/* TODO: Add screenshot of kubectl get pods and svc -n ingress-nginx showing controller Running with EXTERNAL-IP */} Ensure the controller Service has an `EXTERNAL-IP` assigned. For steps to assign an IP, see [LB IP Pool configuration](/docs/myaccount/kubernetes/kubernetes_services/#assigning-an-external-ip-for-loadbalancer-service-on-e2e-kubernetes). ### Step 3: Configure DNS Records Create DNS A records for your subdomains in the [E2E DNS Management Portal](https://myaccount.e2enetworks.com/networking/dns), pointing to the Ingress Controller `EXTERNAL-IP`: | Type | Name | Value | |------|------|-------| | A | app1 | `` | | A | app2 | `` | {/* TODO: Add screenshot of DNS A records configured in E2E DNS Management Portal */} ### Step 4: Install cert-manager ```bash kubectl create namespace cert-manager kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml ``` Verify: ```bash kubectl get pods -n cert-manager ``` {/* TODO: Add screenshot of kubectl get pods -n cert-manager showing all pods Running */} > For a more detailed guide on cert-manager configuration and certificate management, see [Cert-Manager](/docs/myaccount/kubernetes/cert_manager/). ### Step 5: Configure Let's Encrypt ClusterIssuer `clusterissuer.yaml` ```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: ```bash kubectl apply -f clusterissuer.yaml kubectl get clusterissuer ``` {/* TODO: Add screenshot of kubectl get clusterissuer showing letsencrypt-prod Ready=True */} ### Step 6: Create Ingress with Host-Based Routing and TLS `host-based-ingress.yaml` ```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: ```bash kubectl apply -f host-based-ingress.yaml ``` {/* TODO: Add screenshot of kubectl apply output and kubectl get ingress showing result-ingress created */} ### Step 7: Verification ```bash kubectl get ingress kubectl get certificate ``` {/* TODO: Add screenshot of kubectl get ingress and certificate showing ADDRESS and READY=True */} Access applications: - `https://app1.yourdomain.com` - `https://app2.yourdomain.com` {/* TODO: Add screenshot of applications accessible via HTTPS in browser with padlock icon */} ## Path-Based Routing To route traffic based on URL paths instead of subdomains, use the following Ingress configuration: `path-based-ingress.yaml` ```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: ```bash kubectl apply -f path-based-ingress.yaml ``` Access the applications: - `https://app1.yourdomain.com/cycle` - `https://app2.yourdomain.com/hotel` {/* TODO: Add screenshot of path-based routing working in browser */} ## 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/](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](/docs/myaccount/kubernetes/kubernetes_gateway_api/). ---