Amazon EKS — Load Balancing Hands-On Lab

2 minute read

In this lab you’ll deploy applications with both ALB (Ingress) and NLB (Service) load balancers using the AWS Load Balancer Controller.


Prerequisites

  • Running EKS cluster with managed node group
  • AWS Load Balancer Controller installed
  • Subnets tagged for load balancer discovery

Step 1 — Create a Namespace and Deploy Applications

kubectl create namespace lb-lab

cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-v1
  namespace: lb-lab
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
      version: v1
  template:
    metadata:
      labels:
        app: web
        version: v1
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
          command: ["/bin/sh", "-c"]
          args:
            - echo "<h1>Version 1</h1>" > /usr/share/nginx/html/index.html && nginx -g "daemon off;"
          resources:
            requests:
              cpu: "50m"
              memory: "32Mi"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-v2
  namespace: lb-lab
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
      version: v2
  template:
    metadata:
      labels:
        app: web
        version: v2
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
          command: ["/bin/sh", "-c"]
          args:
            - echo "<h1>Version 2</h1>" > /usr/share/nginx/html/index.html && nginx -g "daemon off;"
          resources:
            requests:
              cpu: "50m"
              memory: "32Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: app-v1
  namespace: lb-lab
spec:
  selector:
    app: web
    version: v1
  ports:
    - port: 80
---
apiVersion: v1
kind: Service
metadata:
  name: app-v2
  namespace: lb-lab
spec:
  selector:
    app: web
    version: v2
  ports:
    - port: 80
EOF

Step 2 — Create an ALB Ingress with Path-Based Routing

cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: lb-lab
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80}]'
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /v1
            pathType: Prefix
            backend:
              service:
                name: app-v1
                port:
                  number: 80
          - path: /v2
            pathType: Prefix
            backend:
              service:
                name: app-v2
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-v1
                port:
                  number: 80
EOF

Verify the ALB

# Wait for the ALB to provision (1-2 minutes)
kubectl get ingress web-ingress -n lb-lab

# Get the ALB DNS name
ALB_DNS=$(kubectl get ingress web-ingress -n lb-lab -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "ALB: http://$ALB_DNS"

# Test path-based routing
curl http://$ALB_DNS/
curl http://$ALB_DNS/v1/
curl http://$ALB_DNS/v2/

Step 3 — Create an NLB Service

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: nlb-service
  namespace: lb-lab
  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"
    service.beta.kubernetes.io/aws-load-balancer-attributes: "load_balancing.cross_zone.enabled=true"
spec:
  type: LoadBalancer
  selector:
    app: web
    version: v1
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
EOF

Verify the NLB

# Wait for NLB provisioning
kubectl get svc nlb-service -n lb-lab

# Get the NLB DNS
NLB_DNS=$(kubectl get svc nlb-service -n lb-lab -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "NLB: http://$NLB_DNS"

curl http://$NLB_DNS

Step 4 — Verify Target Group Health

# List target groups
aws elbv2 describe-target-groups --query "TargetGroups[*].[TargetGroupName,TargetGroupArn]" --output table

# Check health of targets
TG_ARN=$(aws elbv2 describe-target-groups --names "k8s-lblab-appv1" --query "TargetGroups[0].TargetGroupArn" --output text 2>/dev/null)
aws elbv2 describe-target-health --target-group-arn $TG_ARN

Clean Up

kubectl delete namespace lb-lab
# Wait for LBs to be deleted (controller cleans them up)
sleep 30
echo "Verify no orphaned load balancers:"
aws elbv2 describe-load-balancers --query "LoadBalancers[?contains(LoadBalancerName,'lb-lab')]"

Updated: