The AWS Load Balancer Controller doesn’t actually create load balancers; it translates Kubernetes Ingress resources into AWS Application Load Balancers (ALBs) and Network Load Balancers (NLBs) behind the scenes.

Let’s see it in action. Imagine you have a simple web application running in EKS. You’ve deployed your pods and exposed them via a Kubernetes Service of type ClusterIP. Now, you want to make this application accessible from the internet.

Here’s a minimal Ingress resource that tells the controller to provision an ALB:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
  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-west-2:123456789012:certificate/my-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 Ingress, the AWS Load Balancer Controller, running as a deployment within your EKS cluster, detects the Ingress object. It then makes API calls to AWS to provision an ALB. This involves:

  1. Creating an ALB: The controller requests an ALB in your specified VPC and Availability Zones.
  2. Configuring Listeners: It sets up listeners for HTTP (port 80) and HTTPS (port 443), using the provided ACM certificate ARN for SSL termination.
  3. Defining Target Groups: For each backend service defined in the Ingress, it creates a target group.
  4. Registering Targets: The controller dynamically registers the IP addresses of your application pods (or the node IPs if target-type is instance) with the target groups.
  5. Setting up Rules: It configures rules on the ALB’s listener to forward traffic based on the host and path specified in your Ingress.

The magic here is that you never directly interact with the AWS console to create the ALB. The controller bridges the Kubernetes declarative API with the AWS infrastructure API. The kubernetes.io/ingress.class: alb annotation is crucial; it signals to the controller that this Ingress resource is its responsibility.

The alb.ingress.kubernetes.io/target-type: ip annotation is a common choice. It means the ALB will send traffic directly to the IP addresses of your pods. If you were using instance, the ALB would send traffic to the EC2 instances running your pods, and kube-proxy or a CNI would then route it to the correct pod. Using ip is generally more efficient as it bypasses some network hops.

The alb.ingress.kubernetes.io/scheme: internet-facing directive tells AWS to assign a public IP address to the ALB, making it accessible from the internet. If you wanted an internal-only load balancer, you’d use internal.

Once the ALB is provisioned, AWS will assign a DNS name to it. You would then update your DNS records (e.g., myapp.example.com) to point to this ALB DNS name. Traffic hitting myapp.example.com will be routed by the ALB to your application pods.

The controller is constantly watching for changes. If you update your Ingress (e.g., add a new path, change the backend service, update the certificate), the controller will automatically update the ALB configuration accordingly. If you delete the Ingress resource, the controller will clean up the associated ALB, target groups, and listeners.

Most people understand the basic mapping of Ingress to ALB. What’s less commonly grasped is how the controller handles pod lifecycle events. When a pod is scheduled and becomes ready, the controller discovers it via the Kubernetes API and registers its IP address with the appropriate ALB Target Group. Conversely, when a pod is terminated or becomes unhealthy, the controller automatically deregisters it. This dynamic registration is key to the high availability and resilience of your application behind the load balancer. The controller’s reconciliation loop ensures that the desired state defined in your Ingress resource is always reflected in the actual state of the AWS ALB.

The next thing you’ll likely encounter is managing multiple hostnames or paths on a single ALB, or configuring more advanced ALB features like WAF integration or sticky sessions via Ingress annotations.

Want structured learning?

Take the full Eks course →