Skip to content

AWS EKS Ingress Context Path Routing with Terraform

Step-01: Introduction

  • Discuss about the Architecture we are going to build as part of this Section
  • We are going to deploy all these 3 apps in kubernetes with context path based routing enabled in Ingress Controller
  • /app1/* - should go to app1-nginx-nodeport-service
  • /app2/* - should go to app1-nginx-nodeport-service
  • /* - should go to app3-nginx-nodeport-service
  • As part of this process, this respective annotation alb.ingress.kubernetes.io/healthcheck-path: will be moved to respective application NodePort Service.
  • Only generic settings will be present in Ingress manifest annotations area 04-ALB-Ingress-ContextPath-Based-Routing.yml

Step-02: Review Nginx App1, App2 & App3 Deployment & Service

  • Differences for all 3 apps will be only two fields from kubernetes manifests perspective and their naming conventions
  • Kubernetes Deployment: Container Image name
  • Kubernetes Node Port Service: Health check URL path
  • App1 Nginx: 01-Nginx-App1-Deployment-and-NodePortService.yml
  • image: stacksimplify/kube-nginxapp1:1.0.0
  • Annotation: alb.ingress.kubernetes.io/healthcheck-path: /app1/index.html
  • App2 Nginx: 02-Nginx-App2-Deployment-and-NodePortService.yml
  • image: stacksimplify/kube-nginxapp2:1.0.0
  • Annotation: alb.ingress.kubernetes.io/healthcheck-path: /app2/index.html
  • App3 Nginx: 03-Nginx-App3-Deployment-and-NodePortService.yml
  • image: stacksimplify/kubenginx:1.0.0
  • Annotation: alb.ingress.kubernetes.io/healthcheck-path: /index.html

Step-03: Create ALB Ingress Context path based Routing Kubernetes manifest

  • 04-ALB-Ingress-ContextPath-Based-Routing.yml
    # Annotations Reference: https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/ingress/annotations/
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-cpr-demo
      annotations:
        # Load Balancer Name
        alb.ingress.kubernetes.io/load-balancer-name: cpr-ingress
        # Ingress Core Settings
        #kubernetes.io/ingress.class: "alb" (OLD INGRESS CLASS NOTATION - STILL WORKS BUT RECOMMENDED TO USE IngressClass Resource)
        alb.ingress.kubernetes.io/scheme: internet-facing
        # Health Check Settings
        alb.ingress.kubernetes.io/healthcheck-protocol: HTTP 
        alb.ingress.kubernetes.io/healthcheck-port: traffic-port
        #Important Note:  Need to add health check path annotations in service level if we are planning to use multiple targets in a load balancer    
        alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'
        alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5'
        alb.ingress.kubernetes.io/success-codes: '200'
        alb.ingress.kubernetes.io/healthy-threshold-count: '2'
        alb.ingress.kubernetes.io/unhealthy-threshold-count: '2'   
    spec:
      ingressClassName: my-aws-ingress-class   # Ingress Class                  
      rules:
        - http:
            paths:      
              - path: /app1
                pathType: Prefix
                backend:
                  service:
                    name: app1-nginx-nodeport-service
                    port: 
                      number: 80
              - path: /app2
                pathType: Prefix
                backend:
                  service:
                    name: app2-nginx-nodeport-service
                    port: 
                      number: 80
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: app3-nginx-nodeport-service
                    port: 
                      number: 80              
    
    # Important Note-1: In path based routing order is very important, if we are going to use  "/*", try to use it at the end of all rules.                                        
    
    # 1. If  "spec.ingressClassName: my-aws-ingress-class" not specified, will reference default ingress class on this kubernetes cluster
    # 2. Default Ingress class is nothing but for which ingress class we have the annotation `ingressclass.kubernetes.io/is-default-class: "true"`                      
    

Step-04: Deploy all manifests and test

# Change Directory
cd 28-EKS-Ingress-Context-Path-Routing

# Deploy Kubernetes manifests
kubectl apply -f 03-kube-manifests-ingress-cpr

# List Pods
kubectl get pods

# List Services
kubectl get svc

# List Ingress Load Balancers
kubectl get ingress

# Describe Ingress and view Rules
kubectl describe ingress ingress-cpr-demo

# Verify AWS Load Balancer Controller logs
kubectl -n kube-system  get pods 
kubectl -n kube-system logs -f aws-load-balancer-controller-794b7844dd-8hk7n 

Step-05: Verify Application Load Balancer on AWS Management Console**

  • Verify Load Balancer
    • In Listeners Tab, click on View/Edit Rules under Rules
  • Verify Target Groups
    • GroupD Details
    • Targets: Ensure they are healthy
    • Verify Health check path
    • Verify all 3 targets are healthy)
      # Access Application
      http://<ALB-DNS-URL>/app1/index.html
      http://<ALB-DNS-URL>/app2/index.html
      http://<ALB-DNS-URL>/
      

Step-06: Clean Up

# Delete Kubernetes Resources
kubectl delete -f 03-kube-manifests-ingress-cpr

Step-07: c1-versions.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
  • Create DynamoDB Table dev-aws-lbc-ingress
  • Create S3 Bucket Key as dev/aws-lbc-ingress/terraform.tfstate
    # Terraform Settings Block
    terraform {
      required_version = ">= 1.0.0"
      required_providers {
        aws = {
          source = "hashicorp/aws"
          version = "~> 4.12"
        }
        kubernetes = {
          source = "hashicorp/kubernetes"
          version = "~> 2.11"
        }    
      }
      # Adding Backend as S3 for Remote State Storage
      backend "s3" {
        bucket = "terraform-on-aws-eks"
        key    = "dev/aws-lbc-ingress/terraform.tfstate"
        region = "us-east-1" 
    
        # For State Locking
        dynamodb_table = "dev-aws-lbc-ingress"    
      }    
    }
    

Step-08: c2-remote-state-datasource.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Terraform Remote State Datasource - Remote Backend AWS S3
    data "terraform_remote_state" "eks" {
      backend = "s3"
      config = {
        bucket = "terraform-on-aws-eks"
        key    = "dev/eks-cluster/terraform.tfstate"
        region = "us-east-1"
      }
    }
    

Step-09: c3-providers.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Terraform AWS Provider Block
    provider "aws" {
      region = "us-east-1"
    }
    
    data "aws_eks_cluster" "cluster" {
      name = data.terraform_remote_state.eks.outputs.cluster_id
    }
    
    data "aws_eks_cluster_auth" "cluster" {
      name = data.terraform_remote_state.eks.outputs.cluster_id
    }
    
    # Terraform Kubernetes Provider
    provider "kubernetes" {
      host = data.terraform_remote_state.eks.outputs.cluster_endpoint 
      cluster_ca_certificate = base64decode(data.terraform_remote_state.eks.outputs.cluster_certificate_authority_data)
      token = data.aws_eks_cluster_auth.cluster.token
    }
    

Step-10: c4-kubernetes-app1-deployment.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Deployment Manifest
    resource "kubernetes_deployment_v1" "myapp1" {
      metadata {
        name = "app1-nginx-deployment"
        labels = {
          app = "app1-nginx"
        }
      } 
    
      spec {
        replicas = 1
    
        selector {
          match_labels = {
            app = "app1-nginx"
          }
        }
    
        template {
          metadata {
            labels = {
              app = "app1-nginx"
            }
          }
    
          spec {
            container {
              image = "stacksimplify/kube-nginxapp1:1.0.0"
              name  = "app1-nginx"
              port {
                container_port = 80
              }
              }
            }
          }
        }
    }
    

Step-11: c5-kubernetes-app2-deployment.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Deployment Manifest
    resource "kubernetes_deployment_v1" "myapp2" {
      metadata {
        name = "app2-nginx-deployment"
        labels = {
          app = "app2-nginx"
        }
      } 
    
      spec {
        replicas = 1
    
        selector {
          match_labels = {
            app = "app2-nginx"
          }
        }
    
        template {
          metadata {
            labels = {
              app = "app2-nginx"
            }
          }
    
          spec {
            container {
              image = "stacksimplify/kube-nginxapp2:1.0.0"
              name  = "app2-nginx"
              port {
                container_port = 80
              }
              }
            }
          }
        }
    }
    

Step-12: c6-kubernetes-app3-deployment.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Deployment Manifest
    resource "kubernetes_deployment_v1" "myapp3" {
      metadata {
        name = "app3-nginx-deployment"
        labels = {
          app = "app3-nginx"
        }
      } 
    
      spec {
        replicas = 1
    
        selector {
          match_labels = {
            app = "app3-nginx"
          }
        }
    
        template {
          metadata {
            labels = {
              app = "app3-nginx"
            }
          }
    
          spec {
            container {
              image = "stacksimplify/kubenginx:1.0.0"
              name  = "app3-nginx"
              port {
                container_port = 80
              }
              }
            }
          }
        }
    }
    

Step-13: c7-kubernetes-app1-nodeport-service.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Service Manifest (Type: Node Port Service)
    resource "kubernetes_service_v1" "myapp1_np_service" {
      metadata {
        name = "app1-nginx-nodeport-service"
        annotations = {
          "alb.ingress.kubernetes.io/healthcheck-path" = "/app1/index.html"
        }
      }
      spec {
        selector = {
          app = kubernetes_deployment_v1.myapp1.spec.0.selector.0.match_labels.app
        }
        port {
          name        = "http"
          port        = 80
          target_port = 80
        }
        type = "NodePort"
      }
    }
    

Step-14: c8-kubernetes-app2-nodeport-service.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Service Manifest (Type: Node Port Service)
    resource "kubernetes_service_v1" "myapp2_np_service" {
      metadata {
        name = "app2-nginx-nodeport-service"
        annotations = {
          "alb.ingress.kubernetes.io/healthcheck-path" = "/app2/index.html"
        }    
      }
      spec {
        selector = {
          app = kubernetes_deployment_v1.myapp2.spec.0.selector.0.match_labels.app
        }
        port {
          name        = "http"
          port        = 80
          target_port = 80
        }
        type = "NodePort"
      }
    }
    

Step-15: c9-kubernetes-app3-nodeport-service.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Service Manifest (Type: Node Port Service)
    resource "kubernetes_service_v1" "myapp3_np_service" {
      metadata {
        name = "app3-nginx-nodeport-service"
        annotations = {
          "alb.ingress.kubernetes.io/healthcheck-path" = "/index.html"
        }    
      }
      spec {
        selector = {
          app = kubernetes_deployment_v1.myapp3.spec.0.selector.0.match_labels.app
        }
        port {
          name        = "http"
          port        = 80
          target_port = 80
        }
        type = "NodePort"
      }
    }
    

Step-16: c10-kubernetes-ingress-service.tf

  • Project Folder: 04-ingress-cpr-terraform-manifests
    # Kubernetes Service Manifest (Type: Load Balancer)
    resource "kubernetes_ingress_v1" "ingress" {
      metadata {
        name = "ingress-cpr"
        annotations = {
          # Load Balancer Name
          "alb.ingress.kubernetes.io/load-balancer-name" = "ingress-cpr"
          # Ingress Core Settings
          "alb.ingress.kubernetes.io/scheme" = "internet-facing"
          # Health Check Settings
          "alb.ingress.kubernetes.io/healthcheck-protocol" =  "HTTP"
          "alb.ingress.kubernetes.io/healthcheck-port" = "traffic-port"
          #Important Note:  Need to add health check path annotations in service level if we are planning to use multiple targets in a load balancer    
          "alb.ingress.kubernetes.io/healthcheck-interval-seconds" = 15
          "alb.ingress.kubernetes.io/healthcheck-timeout-seconds" = 5
          "alb.ingress.kubernetes.io/success-codes" = 200
          "alb.ingress.kubernetes.io/healthy-threshold-count" = 2
          "alb.ingress.kubernetes.io/unhealthy-threshold-count" = 2
        }    
      }
    
      spec {
        ingress_class_name = "my-aws-ingress-class" # Ingress Class            
        default_backend {
          service {
            name = kubernetes_service_v1.myapp3_np_service.metadata[0].name
            port {
              number = 80
            }
          }
        }
    
        rule {
          http {
            path {
              backend {
                service {
                  name = kubernetes_service_v1.myapp1_np_service.metadata[0].name
                  port {
                    number = 80
                  }
                }
              }
              path = "/app1"
              path_type = "Prefix"
            }
    
            path {
              backend {
                service {
                  name = kubernetes_service_v1.myapp2_np_service.metadata[0].name
                  port {
                    number = 80
                  }
                }
              }
              path = "/app2"
              path_type = "Prefix"
            }
          }
        }
      }
    }
    

Step-17: Execute Terraform Commands

# Change Directory 
cd 04-ingress-basics-terraform-manifests

# Terraform Initialize
terraform init

# Terraform Validate
terraform validate

# Terraform Plan
terraform plan

# Terraform Apply
terraform apply -auto-approve

Step-18: Verify Ingress Service

# List Pods
kubectl get pods

# List Services
kubectl get svc

# List Ingress Load Balancers
kubectl get ingress

# Describe Ingress and view Rules
kubectl describe ingress ingress-cpr-demo

# Verify AWS Load Balancer Controller logs
kubectl -n kube-system  get pods 
kubectl -n kube-system logs -f aws-load-balancer-controller-794b7844dd-8hk7n 

# Access Application
http://<ALB-DNS-URL>/app1/index.html
http://<ALB-DNS-URL>/app2/index.html
http://<ALB-DNS-URL>/

Step-19: Clean-Up Ingress

# Change Directory 
cd 04-ingress-cpr-terraform-manifests

# Terraform Destroy
terraform apply -destroy -auto-approve
rm -rf .terraform*

Step-20: Don't Clean-Up LBC Controller & EKS Cluster

  • Dont destroy the Terraform Projects in below two folders
  • Terraform Project Folder: 01-ekscluster-terraform-manifests
  • Terraform Project Folder: 02-lbc-install-terraform-manifests
  • We are going to use them for all upcoming Usecases.
🎉 New Course
Ultimate DevOps Real-World Project Implementation on AWS
$15.99 $84.99 81% OFF
DEVOPS2026FEB
Enroll Now on Udemy →
🎉 Offer