Amazon EKS in Production with Terraform›08 · Ingress
Learning Hub / Cloud — OpenStack, AWS & EKS / Amazon EKS in Production with Terraform

Lesson 08 of 18 · Operate

Ingress

Expose EKS workloads with the AWS Load Balancer Controller: ALBs from Ingress, NLBs from Services, IP targets straight to pods, shared ALBs with IngressGroups, TLS from ACM, and where Gateway API fits.

Advanced
Key wordsAWS Load Balancer ControllerALB IngressNLB Servicetarget-type ipIngressGroupsubnet tagsACMGateway API

The AWS Load Balancer Controller

The AWS Load Balancer Controller (LBC) watches Kubernetes objects and manages AWS load balancers for them:

Kubernetes object AWS result
Ingress (class alb) ALB with listeners, rules and target groups
Service type: LoadBalancer (with LBC annotations) NLB
Gateway API resources (newer controller versions) ALB/NLB from Gateways and Routes

Install it with Helm, giving its ServiceAccount an IAM role (AWS publishes the required policy) via Pod Identity or IRSA.

The controller is a stage manager: when an app says "I need a front door" (Ingress or Service), the stage manager orders the right door from AWS (an ALB or NLB), wires it straight to the actors (pods), and removes it when the show ends.

ALB from an Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
  namespace: shop
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-west-1:111122223333:certificate/abcd-1234
    alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
    alb.ingress.kubernetes.io/healthcheck-path: /healthz
    alb.ingress.kubernetes.io/group.name: public-web       # share one ALB across Ingresses
spec:
  ingressClassName: alb
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
  • target-type: ip registers pod IPs in the target group: no NodePort hop, and health checks see real pods.
  • IngressGroups (group.name) put many Ingresses behind one ALB, saving money. Only group apps that share a trust boundary.
  • TLS from ACM certificates; attach AWS WAF with the wafv2-acl-arn annotation for public apps.

NLB from a Service

apiVersion: v1
kind: Service
metadata:
  name: gateway
  namespace: infra
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
  type: LoadBalancer
  selector: { app: gateway }
  ports:
    - { name: https, port: 443, targetPort: 8443 }

Use NLBs for TCP/UDP services, static IPs (Elastic IP annotations), extreme throughput, or to put your own L7 proxy (an in-cluster Gateway API implementation) behind a simple L4 edge.

Choosing an edge

Pattern When
ALB per app group (IngressGroup) AWS-native: ACM, WAF, OIDC auth on the ALB
NLB → in-cluster gateway (Envoy Gateway, Istio, Traefik…) Portable Gateway API config, advanced L7 features, one LB for everything
LBC with Gateway API Gateway API resources, backed by AWS load balancers

Try it: ALB and NLB on EKS (sandbox account)

  1. Tag your VPC subnets (kubernetes.io/role/elb / internal-elb), create the controller's IAM role and install it with Helm.
  2. Deploy web and apply the Ingress above (use an ACM certificate for a domain you control, or an HTTP listener for the lab). Wait for the ALB and curl it.
  3. Look at the target group in the console: which IPs are registered? Scale web and watch targets change.
  4. Create a second Ingress with the same group.name for another path, and confirm it reuses the ALB.
  5. Expose a Service as an internet-facing NLB with IP targets. Delete everything (and check the load balancers are gone).

Going deeper: edges on EKS in production

  • Readiness gates: the controller can inject pod readiness gates so pods only count as Ready once they're healthy in the ALB target group, which gives zero-downtime rollouts.
  • Set deregistration delay and a preStop sleep so in-flight requests finish during rollouts.
  • Keep internet-facing and internal load balancers separate, and restrict who can create internet-facing ones (admission policy on the scheme annotation).
  • Use ExternalDNS to create Route 53 records from Ingress/Service hostnames automatically.

Recap

  • The AWS Load Balancer Controller turns Ingresses into ALBs and Services into NLBs (and supports Gateway API in newer versions).
  • target-type: ip sends traffic straight to pods; IngressGroups share ALBs.
  • TLS from ACM, WAF on public ALBs, subnet tags for discovery.
  • Choose between AWS-native ALBs and NLB + in-cluster gateway by features and portability.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.