Skip to main content

Command Palette

Search for a command to run...

AWS Load Balancer Controller QnA

Updated
•13 min read•View as Markdown

what is aws load balancer controller.

This is just another application running inside your EKS cluster.

Its use and need. When do we use it. How it helps.

Is eks aws lb controller same as load balancer service in k8s.

NO.

Imagine you have an application running in Kubernetes
For example:
Pod 1 (frontend)
Pod 2 (frontend)
Pod 3 (frontend)
Now you want people on the internet to access your application.
Question:
How does someone on the internet reach these pods?
Pods have private IPs and those IPs change whenever pods restart.
So Kubernetes needs something in front of the pods.

Option 1: Kubernetes Service (LoadBalancer)
Suppose you create:
kind: Service
spec:
  type: LoadBalancer

You are simply telling Kubernetes:
"Please expose these pods to the outside world."
You are not saying:
"Create an AWS Network Load Balancer."
You're only expressing your requirement.

The Service itself doesn't create anything in AWS.

Then who creates the AWS Load Balancer?
That's where the AWS Load Balancer Controller comes in.

AWS Load Balancer Controller
This is just another application running inside your EKS cluster.
It keeps watching Kubernetes.
Imagine it is constantly asking:
Did someone create a new Service?
Did someone create an Ingress?

The moment it sees:
type: LoadBalancer
it says:
"Oh, Kubernetes wants a load balancer.
I'll go create one in AWS."

So it calls AWS APIs and creates:
Network Load Balancer (NLB)
or
Application Load Balancer (ALB)

Real Kubernetes flow
You run :
kubectl apply -f service.yaml

k8s creates :
Service

Now inside EKS:
Service
      │
      ▼
AWS Load Balancer Controller notices it
      │
      ▼
Calls AWS
      │
      ▼
Creates NLB
      │
      ▼
NLB sends traffic to your pods

So why do we need both?
Because they do completely different jobs.

Kubernetes Service
Its job is only to say:
"Expose these pods."
-It doesn't know AWS.
-It doesn't know ALB.
-It doesn't know NLB.

AWS Load Balancer Controller
Its job is:
"I know AWS."
It knows how to create:
-ALB
-NLB
-Target Groups
-Listeners
-Security Groups

so if "aws lb controller" reads k8s api and creates alb/nlb based on what it observes then what does ingress does ? As I was thinking ingress creates alb/nlb as well as the listners/path both together is handled by ingress itself as in service type load balancer it just creates service nothing related to aws infra.

ingress just creates the yaml of what needs to be created in infra a and shared with k8s api.
Then aws lb controller comes into picture, reads the yaml and then contacts aws api and creates related infra needed.

Sequence is - 
Helm Install
      │
      ▼
Ingress resource created in Kubernetes
      │
      ▼
AWS Load Balancer Controller noticed the new Ingress
      │
      ▼
Created an ALB in AWS
      │
      ▼
Created Listeners (80/443)
      │
      ▼
Created Listener Rules (/api, /web, etc.)
      │
      ▼
Created Target Groups
      │
      ▼
Registered your Kubernetes Service as targets

Think of ingress yaml file this:
kind: Ingress

rules:
- host: example.com
  http:
    paths:
    - path: /api
      backend:
        service:
          name: api-service
    - path: /web
      backend:
        service:
          name: web-service

This YAML only says:
"I want /api to go to api-service and /web to go to web-service."
It doesn't contain any AWS API calls. It has no code to create an ALB.
Instead, the AWS Load Balancer Controller reads this Ingress and translates it into AWS resources.

what does controller creates:
suppose your ingress is - 
kind: Ingress

/api  -> api-service
/web  -> web-service

controller creates all of this in aws : 
Application Load Balancer
        │
        ├── Listener :80
        │      │
        │      ├── Rule: /api
        │      └── Rule: /web
        │
        ├── Target Group (api-service)
        └── Target Group (web-service)

So yes, when you created an Ingress, you ended up with:
✅ ALB
✅ Listeners
✅ Listener Rules (paths)
✅ Target Groups
But all of those AWS resources were created by the AWS Load Balancer Controller, based on the Ingress definition.

The same idea applies to a Service of type LoadBalancer
when you create:
kind: Service
spec:
  type: LoadBalancer

the controller (or cloud provider integration, depending on your cluster setup) creates the AWS load balancer.
Typically it looks like:
Service (LoadBalancer)
          │
          ▼
AWS Load Balancer Controller
          │
          ▼
NLB
          │
          ▼
Target Group
          │
          ▼
Pods

Notice there are no path rules here because an NLB operates at Layer 4 (TCP/UDP), not Layer 7 (HTTP).

Suppose I am new to the team and am creating the setup. I don't know about aws lb controller and just went ahead and created ingress.yaml file and ran kubectl apply then what happens?

Scenario 1: You only create an Ingress
You write:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: my-service
            port:
              number: 80

then run:
kubectl apply -f ingress.yaml

what happens?
Step1:
k8s accepts it
ingress.networking.k8s.io/my-app created
No error

Step2:
you check -
kubectl get ingress

output:
NAME      CLASS   HOSTS            ADDRESS   AGE
my-app    alb     app.example.com            2m

Address is empty. No ALB

Step3: you wait 5..10..15..20 mins address is still empty.

Why?
Because nothing is watching the Ingress.
Your Ingress is just sitting inside Kubernetes.
Nobody is reading it.
Nobody is creating AWS resources.

when you'll run :
kubectl describe ingress my-app

you'll see - 
Warning
No IngressClass found

or

Waiting for controller

or simply no events indicating a controller processed it.

In the ingress file,the service "my-service" is it created by the aws load balancer controller itself..or we need another service.yaml file defining what type of service it is and ingress file just refers it , aws lb does not create it. How is it.

No. The AWS Load Balancer Controller does NOT create the Kubernetes Service.
You create the Service yourself, and the Ingress simply refers to it

Step1:
Create the pod.This creates pod-1, pod-2
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: nginx

Step2:
Create a service -
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 80

notice the selector:
selector:
  app: my-app

k8s looks for pods with:
labels:
  app: my-app

and automatically connects them

Step3:
Now create ingress:
backend:
  service:
    name: my-service
    port:
      number: 80

The Ingress is saying:
"When traffic comes for /, send it to the Kubernetes Service named my-service."
Notice it's not pointing directly to the pods.
It's pointing to the Service.

Step4:
Now controller sees the ingress file
Then it asks Kubernetes:
"What is my-service?"
Kubernetes replies:
"my-service routes to Pod-1 and Pod-2."
Now the controller creates in AWS:
-ALB
-Listener
-Listener Rule
-Target Group
and configures the Target Group to send traffic to the endpoints behind my-service.

Who creates what?
Resource	    Created by
Pods	        Deployment
Service	        You (service.yaml)
Ingress	        You (ingress.yaml)
ALB	            AWS Load Balancer Controller
Listener	    AWS Load Balancer Controller
Listener Rules	AWS Load Balancer Controller
Target Groups	AWS Load Balancer Controller

Notice that the controller never creates Kubernetes resources like Services or Deployments. It creates AWS infrastructure.

so ingress or loadbalancer service in k8s are not exactly an alernative of aws lb controller..?
---->

AWS Load Balancer Controller watches Ingress and Service resources and provisions/manages the required AWS load balancer infrastructure for them

Does aws lb controller gets installed by default or we need to install them
--->
we need to install them in eks cluster.Its not setup/installed by default when we create the eks cluster.

how to decide when to use ingress and when to use loadbalancer service in k8s
--->

Use Ingress when you need ALB behavior
Use Ingress when traffic is HTTP/HTTPS and you need things like:
/api  → api-service
/web  → web-service
host1.example.com → service-a
host2.example.com → service-b

that usually creates an alb

Use Service type: LoadBalancer when you need NLB behavior
Use LoadBalancer Service when you want TCP/UDP/TLS pass-through style exposure:
NLB → one Kubernetes Service → pods

we choose ingress when we know we need one load balancer to pass traffic to multiple paths of same dns, as if we go with service loadbalancer we'll need to create separate load balancers for each path.

for only 1 path we can go with service loadbalancer

why use ingress when you need alb...like does ingress only supports http/https no nlb type of protocol like tcp/udp..? and same for service loadbalncer why only when nlb needed, doe sit not support alb protocol type..?

The answer is not that Ingress "likes ALB" or Service "likes NLB".
The answer is that they solve different networking problems.

First, what is an ALB?
An ALB (Application Load Balancer) understands HTTP and HTTPS.
When an HTTP request arrives, it can inspect things like:

GET /api/users HTTP/1.1
Host: app.example.com

It can read:
Host header
URL path
HTTP method
Cookies
Headers
Because it understands HTTP.
So an ALB can make decisions like:

If path = /api
    → Service A

If path = /admin
    → Service B

If host = api.company.com
    → Service C

This is called layer 7 routing

What is an NLB?
An NLB does not understand HTTP.
Suppose this packet arrives:

TCP Packet
Destination Port: 7233
Payload: <binary data>

The NLB says:
I don't know what's inside.
I don't care.
It simply forwards it.
This is Layer 4 routing.
It only knows:
TCP
UDP
TLS
It does not know:
URL paths
HTTP headers
Cookies

Now lets look at k8s ingress -
rules:
- host: app.example.com
  http:
    paths:
    - path: /api
      backend:
        service:
          name: api-service

    - path: /admin
      backend:
        service:
          name: admin-service

notice, the entire object resolves around -
host
http
path
Those are HTTP concepts

There is no [lace for TCP port or UDP port
because ingress is designed for HTTP/HTTPS routing
This is why it naturally maps to ALB.

Now look at service:
spec:
  type: LoadBalancer

  ports:
  - port: 7233
    protocol: TCP

It only says TCP port 7233
There is no path, no hostname, no HTTP
This maps naturally to NLB.

Can aws lb controller create both alb and nlb's.?
--->
Yes!
The AWS Load Balancer Controller understands both resource types.It chooses what to create based on the Kubernetes resource and its annotations.

do we have the flexibility to mention path in case of service type load balancer..? like in that case aws lb controller creates nlb in aws, but what to give in listner how to know that..?

No. A Service of type LoadBalancer does not support paths.
Suppose you have this service:
apiVersion: v1
kind: Service
metadata:
  name: temporal
spec:
  type: LoadBalancer
  ports:
  - port: 7233
    targetPort: 7233
    protocol: TCP

only port, protocol defined, no path: /api or host: example.com
because a service is layer 4 object.

Then what does the NLB listener look like?
Suppose AWS Load Balancer Controller creates an NLB.
The listener will simply be:
Listener
---------
Protocol : TCP
Port     : 7233

That's it.
No rules.
No paths.
No hostnames.
No priorities.

Traffic flow:
Client
   │
TCP:7233
   │
   ▼
NLB Listener
(TCP 7233)
   │
   ▼
Target Group
   │
   ▼
Pods

Compare with alb.
Now the listner looks like this:
Listener : HTTPS 443

Rule 1
IF path == /api
→ api-service

Rule 2
IF path == /admin
→ admin-service

ALB listeners have rules.
NLB listeners do not.

does aws lb controller only watches service/ingress k8s resources or other resources too..?

Primarily yes, but not only those two.
The AWS Load Balancer Controller watches a few Kubernetes resource types because it needs them to do its job.

1. Ingress ⭐ (Primary)
This is the main resource it watches for creating ALBs.
When it sees:
new Ingress
Ingress updated
Ingress deleted
it creates/updates/deletes:
ALB
Listeners
Listener Rules
Target Groups

2. Service ⭐ (Primary)
Especially:
type: LoadBalancer
When it sees one, it creates or updates:
NLB (typically)
Target Groups
Target registration

3. Endpoints / EndpointSlices ⭐ (Very important)
Suppose your Service currently points to:
Pod A → 10.0.1.10
Pod B → 10.0.1.20
The AWS Target Group contains:
10.0.1.10
10.0.1.20
Now Pod A dies.

New Pod: 10.0.5.15
How does AWS know?
Because Kubernetes updates the Service's Endpoints/EndpointSlices, and the controller notices that change. It then updates the AWS Target Group:
Remove:
10.0.1.10

Add:
10.0.5.15
This is how pod IP changes are handled automatically.

4. Nodes (Sometimes)
If you're using:
Target Type = Instance
the controller needs to know:
which worker nodes exist
which are Ready
their instance IDs
because those nodes become the NLB targets.

Its entire responsibility is to keep Kubernetes networking resources (Ingress/LoadBalancer Services) and AWS load balancer resources (ALB/NLB) in sync.

so then in case where aws lb controller sends traffic to pod ip instead of nodeport in alb/nlb target group then will the pod need any service.? like we usually see we cannot directly interact with pods we need service in front of it to interact with pod.

Yes, the pod Service is still needed — and it does exist (created by the Helm chart). Here's why:
The TargetGroupBinding references the Service, not pods directly:

spec:
  serviceRef:
    name: temporal-frontend   # ← points to a Service
    port: 7233
  targetGroupARN: ...
  targetType: ip

The AWS LB Controller uses the Service to discover pod IPs. The flow is:
┌──────────────────────────────────────────────────────────────┐
│ Helm chart creates:                                          │
│                                                              │
│   Service: temporal-frontend (ClusterIP)                     │
│     selector: app.kubernetes.io/component = frontend         │
│     port: 7233                                               │
│         │                                                    │
│         ▼                                                    │
│   EndpointSlices (auto-generated by Kubernetes)              │
│     → pod IP: 10.0.5.12:7233                                │
│     → pod IP: 10.0.6.45:7233                                │
└──────────────────────────────────────────────────────────────┘
                         │
                         │  AWS LB Controller watches EndpointSlices
                         ▼
┌──────────────────────────────────────────────────────────────┐
│ TargetGroupBinding                                           │
│   "Register 10.0.5.12 and 10.0.6.45 in NLB Target Group"    │
└──────────────────────────────────────────────────────────────┘

So the Service serves TWO purposes here:

For the AWS LB Controller — It's the source of truth for "which pod IPs should be in the NLB target group." The controller watches the Service's EndpointSlices, not pods directly.

For internal cluster traffic — Other Temporal components (history, matching, worker) communicate with the frontend via temporal-frontend.temporal.svc.cluster.local:7233 using the ClusterIP. This is normal in-cluster east-west traffic that doesn't go through the NLB at all.

even pods within the same namespace use Services to talk to each other. Here's why:

Pods get random, ephemeral IPs — every time a pod restarts, it gets a new IP. If pod A hardcoded pod B's IP, it would break on every restart.

The Service provides a stable DNS name and IP that never changes, regardless of how many pods are behind it or what their current IPs are.

EKS

Part 1 of 1

This series will contain blogs of projects related to EKS