Amazon EKS — Load Balancing Hands-On Lab
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')]"