The most surprising truth about choosing between EKS NGINX Ingress and ALB Ingress is that the "better" choice often depends more on your team’s existing operational expertise and cost tolerance than on inherent technical superiority.
Let’s see them in action. Imagine you’ve deployed a simple web application on EKS and you need to expose it to the internet.
Scenario 1: NGINX Ingress Controller
First, you’d deploy the NGINX Ingress Controller itself. This is often done via Helm:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.replicaCount=2 \
--set controller.nodeSelector."kubernetes\.io/os"=linux \
--set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux
Once the controller is running, you define an Ingress resource to route traffic to your application pods:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
In this setup, the NGINX Ingress Controller pods, running on your EKS worker nodes, receive the traffic. They inspect the Host header and path and forward the request to the appropriate Kubernetes Service, which then directs it to your application pods. You’re managing the load balancing, SSL termination, and routing logic directly within your Kubernetes cluster.
Scenario 2: AWS ALB Ingress Controller
For the ALB Ingress Controller, you first need to ensure it’s installed in your cluster. This is often managed by the aws-load-balancer-controller Helm chart.
helm repo add aws-load-balancer-controller https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller aws-load-balancer-controller/aws-load-balancer-controller \
-n kube-system \
--set clusterName=my-eks-cluster \
--set serviceAccount.create=true \
--set serviceAccount.name=aws-load-balancer-controller \
--set region=us-east-1 \
--set vpcId=vpc-0123456789abcdef0
Then, you define an Ingress resource. Crucially, you’ll use AWS-specific annotations to tell the controller how to provision and configure an Application Load Balancer (ALB):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:123456789012:certificate/your-certificate-id
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
When you apply this, the aws-load-balancer-controller detects the Ingress resource and makes API calls to AWS to provision a new ALB. This ALB then becomes the public endpoint for your application. Traffic hits the ALB, which then forwards it to your EKS worker nodes (via IP or instance) where your application pods are running.
The Core Problem Solved
Both NGINX Ingress and ALB Ingress solve the fundamental problem of exposing services running inside your Kubernetes cluster to external traffic in a controlled and scalable manner. They provide:
- Traffic Routing: Directing incoming requests to the correct backend services based on hostnames, paths, and other criteria.
- Load Balancing: Distributing traffic across multiple instances of your application.
- SSL Termination: Handling TLS/SSL encryption and decryption, offloading this from your application pods.
- Service Discovery: Integrating with Kubernetes Services to find and connect to your application pods.
Internal Workings: The Divergence
The key difference lies in where the intelligence and infrastructure for these functions reside.
NGINX Ingress Controller:
- Infrastructure: Runs as pods within your EKS cluster, consuming worker node CPU, memory, and network resources.
- Logic: The NGINX configuration is dynamically generated and reloaded by the controller based on your
Ingressresources. NGINX itself handles the HTTP routing, SSL termination, and load balancing. - Management: You are responsible for managing the NGINX Ingress Controller deployment, scaling its replicas, and ensuring the underlying worker nodes are healthy.
AWS ALB Ingress Controller:
- Infrastructure: Leverages AWS’s managed Application Load Balancer service. The ALB is an external AWS resource, separate from your EKS cluster’s worker nodes.
- Logic: The controller acts as a bridge, translating Kubernetes
Ingressresources into ALB configurations (target groups, listeners, rules). AWS manages the ALB’s availability, scaling, and underlying infrastructure. - Management: You manage the ALB via Kubernetes annotations, and AWS manages the ALB itself. You pay AWS for the ALB’s usage.
Pros, Cons, and Costs
NGINX Ingress Controller
- Pros:
- Flexibility & Customization: NGINX is incredibly powerful. You can leverage its vast array of directives and modules for advanced routing, custom error pages, WAF integration (via ModSecurity), and more, often through annotations.
- Cost Control (Potentially): If you have underutilized worker nodes, NGINX Ingress can be very cost-effective as it uses existing resources. You don’t pay for a separate AWS service.
- Portability: Less tied to a specific cloud provider’s managed service.
- Performance: Can offer very low latency for requests processed entirely within the cluster.
- Cons:
- Operational Overhead: You manage the NGINX pods, their scaling, updates, and the underlying worker nodes. This requires Kubernetes expertise.
- Resource Consumption: Consumes CPU, memory, and network bandwidth on your EKS worker nodes, potentially impacting application performance if not sized correctly.
- Scalability Complexity: Scaling the NGINX controller itself (adding replicas) and ensuring your worker nodes can handle the load requires careful planning.
- Limited AWS Integration: Doesn’t natively integrate with other AWS services like WAF or Shield without additional configuration.
- Costs: Primarily the cost of the EKS worker nodes (EC2 instances or Fargate) that run the NGINX Ingress Controller pods. Also, data transfer costs.
AWS ALB Ingress Controller
- Pros:
- Managed Service: AWS handles the availability, patching, and scaling of the ALB. Reduced operational burden.
- Deep AWS Integration: Seamless integration with AWS WAF, AWS Certificate Manager (ACM) for SSL certificates, AWS Shield for DDoS protection, and other AWS services.
- Scalability: ALBs scale automatically to handle varying traffic loads.
- Cost-Effective for High Traffic: For very high, spiky traffic, the pay-as-you-go model of ALB can be cheaper than over-provisioning worker nodes for NGINX.
- Simpler Kubernetes Configuration: Often requires fewer, more declarative annotations for common tasks.
- Cons:
- Vendor Lock-in: Tied to AWS’s ALB service.
- Less Customization: While ALB is feature-rich, it doesn’t offer the same level of deep, low-level configuration as NGINX. Advanced routing or request manipulation might be more challenging.
- Cost: You pay directly for the ALB’s hourly usage and LCU (Load Balancer Capacity Unit) consumption, which can become expensive for consistent, low-traffic applications or if not configured optimally.
- Latency (Potentially): Traffic might traverse an extra hop to the ALB before reaching your cluster, though this is often negligible.
- Costs: Direct AWS charges for the ALB (per hour, per LCU), data processed, and potentially associated costs for integrated services like WAF.
The "One Thing" Most People Don’t Know
The alb.ingress.kubernetes.io/target-type annotation is critical and often misunderstood. When set to ip, the ALB targets your pods directly using their IP addresses on the cluster network. This generally offers better performance and allows for more pods per node. When set to instance, the ALB targets the EC2 instances (worker nodes) themselves, and the traffic is then routed to the pods via kube-proxy or CNI. This instance mode is necessary if your pods don’t have unique, routable IPs within the VPC, or if you need to integrate with security groups at the instance level. Choosing the wrong type can lead to connectivity issues or suboptimal performance.
Ultimately, the choice often boils down to this: if your team is comfortable managing Kubernetes infrastructure and wants maximum control and potential cost savings on existing hardware, NGINX Ingress is a strong contender. If you prefer to offload infrastructure management, leverage deep AWS integrations, and are comfortable with AWS’s pricing model for managed services, ALB Ingress is likely the smoother path.
The next logical step after setting up ingress is often managing TLS certificates automatically for multiple domains.