Saltar a contenido

Lab 02 — ALB + Auto Scaling Group: Alta Disponibilidad Real

Lo que construimos: Encima de la VPC del Lab 01, agregamos un Application Load Balancer que distribuye tráfico entre múltiples EC2s, y un Auto Scaling Group que lanza y destruye instancias automáticamente según la carga — lo que AWS llama "elasticidad".

Servicios: Application Load Balancer, Target Group, Launch Template, Auto Scaling Group, CloudWatch, EC2

Duración: ~2.5 horas

Costo: ~USD $0.02/hora mientras el ALB está activo (el ALB no es Free Tier). Las EC2 t2.micro sí son Free Tier.

Arquitectura final del lab

Arquitectura Lab 02


El problema que resolvemos

El web server del Lab 01 funciona, pero tiene un problema serio: es un SPOF (Single Point of Failure). Si esa EC2 se cae — por un bug, una actualización que rompe algo, o un problema de hardware en el datacenter de AWS — el sitio se cae. No hay plan B.

En producción esto no es aceptable. La solución son dos conceptos que van juntos:

  • Alta disponibilidad (HA): El sistema sigue funcionando aunque algún componente falle. Se logra teniendo múltiples instancias en múltiples AZs — si us-east-1a tiene un problema, las instancias en us-east-1b siguen respondiendo.
  • Elasticidad: El sistema adapta su capacidad a la demanda. Si de repente tenés 10x el tráfico, AWS lanza más instancias automáticamente. Cuando el tráfico baja, las destruye para no pagar de más.

Un Application Load Balancer resuelve la distribución del tráfico. Un Auto Scaling Group resuelve la elasticidad. Juntos, son la base de cualquier arquitectura resiliente en AWS.


Parte 1 — Launch Template + Security Groups

Qué es un Launch Template

Un Launch Template es un "blueprint" para lanzar instancias EC2. Define todo lo necesario: la AMI, el tipo de instancia, la Key Pair, los Security Groups, el User Data. Cuando el Auto Scaling Group necesita lanzar una nueva instancia, usa este template — así todas las instancias son idénticas sin que tengas que configurarlas a mano.

Es la evolución de los "Launch Configurations" (deprecados por AWS). La diferencia clave: los Launch Templates son versionables. Podés tener v1 con t2.micro y v2 con t3.micro, y hacer rollback si algo sale mal.

Por qué cambiamos la arquitectura de seguridad

En el Lab 01, el web server (d3lt4-web-sg) aceptaba HTTP desde 0.0.0.0/0 (cualquier IP). Con ALB, podemos mejorar esto:

ANTES (Lab 01):     Internet → EC2 (HTTP directo)
DESPUÉS (Lab 02):   Internet → ALB → EC2 (solo acepta tráfico del ALB)

Las instancias del ASG no necesitan ser accesibles desde internet directamente — solo el ALB lo necesita. Configuramos los Security Groups para que las instancias solo acepten HTTP desde el SG del ALB. Si alguien intenta conectarse directo a la IP privada de una instancia, el SG lo bloquea.

Esto reduce la superficie de ataque: el único punto de entrada HTTP es el ALB, que podemos proteger con WAF, rate limiting, etc.

1.1 Security Group para el ALB

  1. Ir a EC2Security GroupsCreate security group
  2. Name: d3lt4-alb-sg
  3. Description: ALB - HTTP publico
  4. VPC: d3lt4-vpc
  5. Inbound rulesAdd rule:

    Type Port Source Descripción
    HTTP 80 0.0.0.0/0 (Anywhere IPv4) HTTP público al ALB
  6. Create security group

  7. Anotá el SG ID — lo necesitás para el siguiente paso

SG ALB d3lt4-alb-sg — inbound HTTP 80 desde el SG del ALB.

aws ec2 create-security-group \
  --group-name d3lt4-alb-sg \
  --description "ALB - HTTP publico" \
  --vpc-id $VPC_ID

# Guardá el SG ID que devuelve el comando
export ALB_SG="sg-XXXXXXXXX"

aws ec2 authorize-security-group-ingress \
  --group-id $ALB_SG --protocol tcp --port 80 --cidr 0.0.0.0/0

1.2 Security Group para las instancias del ASG

Este SG lo van a tener las EC2s que lance el Auto Scaling Group. Solo aceptan HTTP desde el ALB (no desde internet) y SSH desde las subnets públicas (para poder entrar desde la NAT como bastion si necesitás debuggear).

  1. EC2Security GroupsCreate security group
  2. Name: d3lt4-asg-sg
  3. Description: ASG instances - HTTP solo desde ALB
  4. VPC: d3lt4-vpc
  5. Inbound rulesAdd rule:

    Type Port Source Descripción
    HTTP 80 SG: d3lt4-alb-sg HTTP solo desde el ALB
    SSH 22 10.0.1.0/24 SSH desde subnet pública (NAT/bastion)
    SSH 22 10.0.2.0/24 SSH desde subnet pública

Source = Security Group

En vez de poner un CIDR de IP, podés referenciar otro Security Group como fuente. Si el ALB escala o cambia de IPs internas, la regla sigue funcionando porque apunta al SG, no a IPs fijas.

  1. Create security group

SG ASG instances d3lt4-asg-sg — 3 reglas inbound: HTTP desde ALB SG, SSH desde ambas subnets públicas.

aws ec2 create-security-group \
  --group-name d3lt4-asg-sg \
  --description "ASG instances - HTTP solo desde ALB" \
  --vpc-id $VPC_ID

export ASG_SG="sg-XXXXXXXXX"

# HTTP solo desde el ALB (source = SG del ALB)
aws ec2 authorize-security-group-ingress \
  --group-id $ASG_SG \
  --protocol tcp --port 80 \
  --source-group $ALB_SG

# SSH desde subnets públicas
aws ec2 authorize-security-group-ingress \
  --group-id $ASG_SG --protocol tcp --port 22 --cidr 10.0.1.0/24
aws ec2 authorize-security-group-ingress \
  --group-id $ASG_SG --protocol tcp --port 22 --cidr 10.0.2.0/24

1.3 Crear el Launch Template

El Launch Template incluye el User Data que configura el web server. La página muestra el Instance ID y la AZ de cada instancia — así cuando el ALB distribuya tráfico podés ver en el browser cuál instancia está respondiendo.

  1. Ir a EC2Launch TemplatesCreate launch template
  2. Launch template name: d3lt4-web-template
  3. Template version description: v1 - Lab 02 ALB + ASG
  4. AMI: Amazon Linux 2 (Free tier eligible)
  5. Instance type: t2.micro
  6. Key pair: d3lt4-key
  7. Network settings:
    • No especificar subnet (el ASG define en qué subnet lanzar)
    • Security groups: d3lt4-asg-sg
  8. Advanced details → scroll hasta User data, pegar este script:
#!/bin/bash
yum update -y
yum install -y httpd stress

systemctl start httpd
systemctl enable httpd

TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/instance-id)
AZ=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/placement/availability-zone)
LOCAL_IP=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/local-ipv4)

# Color distinto por AZ para identificar visualmente qué instancia responde
if echo "$AZ" | grep -q "1a"; then
  AZ_COLOR="#1f6feb"
else
  AZ_COLOR="#388bfd"
fi

cat << HTML > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head><title>D3LT4 Protocol — Lab 02</title>
<style>
  body { background:#0d1117; color:#c9d1d9; font-family:monospace; padding:40px; }
  h1 { color:#58a6ff; }
  h2 { color:#8b949e; font-size:1rem; margin-top:0; }
  .card { background:#161b22; border:1px solid #30363d; padding:20px; border-radius:8px; margin-bottom:16px; }
  .az-badge { display:inline-block; background:${AZ_COLOR}; color:#fff; padding:4px 12px; border-radius:4px; font-weight:bold; }
  .label { color:#8b949e; }
  .value { color:#f0883e; }
  .hint { color:#6e7681; font-size:0.85rem; margin-top:24px; }
</style></head>
<body>
  <h1>The D3LT4 Protocol</h1>
  <h2>Lab 02 — ALB + Auto Scaling Group</h2>
  <div class="card">
    <p><span class="label">Instance ID:</span> <span class="value">$INSTANCE_ID</span></p>
    <p><span class="label">Availability Zone:</span> <span class="az-badge">$AZ</span></p>
    <p><span class="label">Private IP:</span> <span class="value">$LOCAL_IP</span></p>
  </div>
  <p class="hint">Si refrescás y cambia el Instance ID o la AZ, el ALB está distribuyendo tráfico entre instancias.</p>
</body>
</html>
HTML
  1. Click Create launch template

Launch Template creado Launch Template d3lt4-web-template v1 — AMI Amazon Linux 2, t3.micro, SG d3lt4-asg-sg.

# Guardar el user data en un archivo primero
cat << 'USERDATA' > web-server-lab02.sh
#!/bin/bash
yum update -y && yum install -y httpd stress
systemctl start httpd && systemctl enable httpd
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
AZ=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/availability-zone)
LOCAL_IP=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4)
echo "<html><body style='background:#0d1117;color:#c9d1d9;font-family:monospace;padding:40px'><h1 style='color:#58a6ff'>D3LT4 — Lab 02</h1><p>Instance: $INSTANCE_ID | AZ: $AZ | IP: $LOCAL_IP</p></body></html>" > /var/www/html/index.html
USERDATA

aws ec2 create-launch-template \
  --launch-template-name d3lt4-web-template \
  --version-description "v1 - Lab 02 ALB + ASG" \
  --launch-template-data '{
    "ImageId": "ami-0c02fb55956c7d316",
    "InstanceType": "t2.micro",
    "KeyName": "d3lt4-key",
    "SecurityGroupIds": ["'"$ASG_SG"'"],
    "UserData": "'"$(base64 -w 0 web-server-lab02.sh)"'"
  }'

Parte 2 — Target Group + Application Load Balancer

Qué es un Application Load Balancer

Un Application Load Balancer (ALB) opera en la capa 7 (aplicación) del modelo OSI. Entiende HTTP/HTTPS — puede tomar decisiones de routing basadas en el path (/api/* a un target group, /static/* a otro), los headers o el método HTTP. Esto lo diferencia del Network Load Balancer (capa 4, solo TCP/UDP) y del Classic Load Balancer (deprecado).

La arquitectura interna de un ALB tiene tres componentes:

Internet → ALB
              ├── Listener (puerto 80)
              │       └── Rule default: "todo el tráfico → Target Group"
              └── Target Group
                      ├── EC2 instancia 1 (us-east-1a)
                      └── EC2 instancia 2 (us-east-1b)
  • Listener: el ALB "escucha" en un puerto. Cada listener tiene reglas que determinan qué hacer con el tráfico.
  • Rule: condición + acción. La regla default es "todo el tráfico → forward a este target group". Podés agregar reglas más específicas (path-based routing, host-based routing).
  • Target Group: la colección de destinos a los que el ALB envía tráfico.

El ALB hace health checks periódicos a cada target. Si una instancia no responde HTTP 200, el ALB la marca como "unhealthy" y deja de enviarle tráfico hasta que se recupere. Esto es lo que logra alta disponibilidad: si una instancia se cae, el ALB automáticamente deja de mandarle requests sin intervención manual.

El ALB no tiene IP fija

El ALB no tiene una IP pública estática — tiene un DNS name (algo como d3lt4-alb-123456789.us-east-1.elb.amazonaws.com). En producción, apuntás tu dominio con un CNAME o un Alias Record en Route 53 al DNS name del ALB. Nunca hardcodeás la IP porque puede cambiar.

Qué es un Target Group

Un Target Group es un grupo de destinos donde el ALB envía tráfico. Los destinos pueden ser instancias EC2, IPs privadas, funciones Lambda, o contenedores ECS.

Lo más importante del Target Group es la configuración de health checks: define cómo el ALB verifica si cada instancia está saludable. Por defecto hace un GET a / en el puerto 80 y espera un HTTP 200. Si falla N veces seguidas, la marca unhealthy. Si pasa M veces seguidas, la vuelve a marcar healthy.

El algoritmo de balanceo default es Round Robin: el primer request va a la primera instancia, el segundo a la segunda, y así cíclicamente. Podés cambiarlo a Least Outstanding Requests (manda el próximo request a la instancia con menos requests en vuelo).

2.1 Crear el Target Group

  1. Ir a EC2Target GroupsCreate target group
  2. Choose a target type: Instances
  3. Target group name: d3lt4-web-tg
  4. Protocol: HTTP, Port: 80
  5. VPC: d3lt4-vpc
  6. Health check settings:
    • Protocol: HTTP
    • Path: /
    • Healthy threshold: 2 (cuántos checks OK seguidos para marcarla healthy)
    • Unhealthy threshold: 2 (cuántos checks fail seguidos para marcarla unhealthy)
    • Timeout: 5 segundos
    • Interval: 15 segundos
  7. Click NextCreate target group

No registramos targets a mano

Dejamos el target group vacío. El Auto Scaling Group va a registrar y desregistrar instancias automáticamente cuando las lance o las destruya.

Target Group creado d3lt4-web-tg recién creado — 0 targets, sin load balancer asociado todavía.

aws elbv2 create-target-group \
  --name d3lt4-web-tg \
  --protocol HTTP \
  --port 80 \
  --vpc-id $VPC_ID \
  --health-check-protocol HTTP \
  --health-check-path / \
  --healthy-threshold-count 2 \
  --unhealthy-threshold-count 2 \
  --health-check-timeout-seconds 5 \
  --health-check-interval-seconds 15

# Guardá el ARN del Target Group
export TG_ARN="arn:aws:elasticloadbalancing:us-east-1:XXXX:targetgroup/d3lt4-web-tg/XXXX"

2.2 Crear el ALB

El ALB vive en las subnets públicas — necesita ser accesible desde internet. Lo ponemos en 2 AZs para que siga funcionando si una AZ tiene problemas. AWS requiere al menos 2 subnets en AZs distintas para un ALB.

  1. Ir a EC2Load BalancersCreate load balancer
  2. Seleccionar Application Load BalancerCreate
  3. Load balancer name: d3lt4-alb
  4. Scheme: Internet-facing
  5. IP address type: IPv4
  6. Network mapping:
    • VPC: d3lt4-vpc
    • Mappings: seleccionar us-east-1ad3lt4-public-1a y us-east-1bd3lt4-public-1b
  7. Security groups: quitar el default, seleccionar solo d3lt4-alb-sg
  8. Listeners and routing:
    • Protocol: HTTP, Port: 80
    • Default action: Forward tod3lt4-web-tg
  9. Click Create load balancer
  10. Esperá ~2 minutos hasta que el estado cambie de provisioning a active

ALB active ALB d3lt4-alb en estado Provisioning — DNS name asignado, listener HTTP:80 → d3lt4-web-tg.

aws elbv2 create-load-balancer \
  --name d3lt4-alb \
  --subnets $PUB_SUBNET_A $PUB_SUBNET_B \
  --security-groups $ALB_SG \
  --scheme internet-facing \
  --type application

# Guardá el ARN del ALB
export ALB_ARN="arn:aws:elasticloadbalancing:us-east-1:XXXX:loadbalancer/app/d3lt4-alb/XXXX"
export ALB_DNS="d3lt4-alb-XXXXXXXXX.us-east-1.elb.amazonaws.com"

# Crear el listener: HTTP 80 → Target Group
aws elbv2 create-listener \
  --load-balancer-arn $ALB_ARN \
  --protocol HTTP \
  --port 80 \
  --default-actions Type=forward,TargetGroupArn=$TG_ARN

Verificación Parte 2

El ALB todavía no tiene targets — el ASG los va a registrar en la Parte 3. Verificamos que esté activo:

  • EC2Load Balancersd3lt4-alb → State: Active
  • Copiá el DNS name del ALB — lo necesitás para testear en la Parte 3
aws elbv2 describe-load-balancers --names d3lt4-alb \
  --query 'LoadBalancers[].[LoadBalancerName,State.Code,DNSName]' \
  --output table

Parte 3 — Auto Scaling Group + Scaling Policies

Qué es un Auto Scaling Group

Un Auto Scaling Group (ASG) es un grupo de instancias EC2 que AWS mantiene y gestiona. Definís tres números:

  • Mínimo (min): AWS nunca baja de esta cantidad. Si una instancia se destruye, lanza otra para mantener el mínimo.
  • Máximo (max): AWS nunca supera esta cantidad, sin importar cuánto suba la carga. Es tu seguro contra gastos descontrolados.
  • Deseado (desired): La cantidad que querés en este momento. Empieza igual al mínimo o al valor que definís.

El ASG monitorea la salud de las instancias usando los health checks del Target Group. Si una instancia falla los health checks, el ASG la destruye y lanza una nueva automáticamente. Esto se llama self-healing — la infraestructura se recupera sola.

El ASG lanza instancias en múltiples subnets/AZs y trata de mantenerlas balanceadas. Si configurás min: 2 con subnets en us-east-1a y us-east-1b, siempre vas a tener al menos una instancia en cada AZ.

Qué son las Scaling Policies

Las Scaling Policies definen cuándo y cómo escalar. Hay tres tipos:

Tipo Cuándo usarlo
Target Tracking Querés mantener una métrica en un valor objetivo (ej: CPU al 50%). El más simple y el más común.
Step Scaling Querés control granular: "+1 instancia si CPU > 60%, +2 si CPU > 80%".
Scheduled Scaling Sabés de antemano cuándo hay picos: "todos los lunes a las 9am, escalar a 5 instancias".

Para este lab usamos Target Tracking con CPU al 50%: AWS calcula cuántas instancias necesitás para que el promedio de CPU se mantenga cerca del 50%, y agrega o quita instancias automáticamente.

3.1 Crear el Auto Scaling Group

  1. Ir a EC2Auto Scaling GroupsCreate Auto Scaling group

Step 1 — Choose launch template:

  1. Auto Scaling group name: d3lt4-web-asg
  2. Launch template: d3lt4-web-template → Version: Latest (1)
  3. Next

Step 2 — Choose instance launch options:

  1. VPC: d3lt4-vpc
  2. Availability Zones and subnets: seleccionar d3lt4-private-1a y d3lt4-private-1b

ASG en subnets privadas

Las instancias del ASG van en las subnets privadas — internet no puede llegar a ellas directamente, solo el ALB puede. El ALB vive en las públicas y hace de único punto de entrada. Esta es la arquitectura correcta para producción. Para que las instancias puedan bajar paquetes (yum update) durante el arranque, usan la NAT Instance del Lab 01.

  1. Next

Step 3 — Configure advanced options:

  1. Load balancing: Attach to an existing load balancer
  2. Existing load balancer target groups: d3lt4-web-tg
  3. Health checks: activar Turn on Elastic Load Balancing health checks

ELB health checks vs EC2 health checks

Por defecto el ASG usa EC2 health checks (si la instancia está en estado running, está "healthy"). Con ELB health checks activados, el ASG también considera si el ALB la ve healthy. Esto es mejor: si tu app crashea pero la instancia sigue corriendo, el EC2 check no se entera, pero el ELB check sí.

  1. Next

Step 4 — Configure group size and scaling:

  1. Desired capacity: 2
  2. Minimum capacity: 1
  3. Maximum capacity: 4
  4. Automatic scaling:
    • Seleccionar Target tracking scaling policy
    • Scaling policy name: cpu-target-tracking
    • Metric type: Average CPU utilization
    • Target value: 50
    • Instance warmup: 60 segundos

Instance warmup

El ASG espera este tiempo antes de medir el CPU de una instancia nueva. Sin esto, el User Data (que consume CPU mientras instala paquetes) podría disparar otro scale-out mientras la instancia todavía está arrancando.

  1. NextNextCreate Auto Scaling group

ASG creado ASG d3lt4-web-asg — Desired: 2, Version 2 del Launch Template, Activity con los 2 launches exitosos.

aws autoscaling create-auto-scaling-group \
  --auto-scaling-group-name d3lt4-web-asg \
  --launch-template LaunchTemplateName=d3lt4-web-template,Version='$Latest' \
  --min-size 1 \
  --max-size 4 \
  --desired-capacity 2 \
  --vpc-zone-identifier "$PRIV_SUBNET_A,$PRIV_SUBNET_B" \
  --target-group-arns $TG_ARN \
  --health-check-type ELB \
  --health-check-grace-period 60

# Agregar la scaling policy de Target Tracking
aws autoscaling put-scaling-policy \
  --auto-scaling-group-name d3lt4-web-asg \
  --policy-name cpu-target-tracking \
  --policy-type TargetTrackingScaling \
  --target-tracking-configuration '{
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ASGAverageCPUUtilization"
    },
    "TargetValue": 50.0,
    "EstimatedInstanceWarmup": 60
  }'

3.2 Habilitar Detailed Monitoring

Este paso es obligatorio antes de hacer el stress test.

Por defecto, EC2 usa Basic Monitoring: CloudWatch recopila métricas de CPU cada 5 minutos. Con Target Tracking al 50% y un stress test de 5 minutos, CloudWatch todavía no tiene datos suficientes para disparar el scaling — y no escala nada.

Detailed Monitoring baja el intervalo a 1 minuto, haciendo al ASG mucho más reactivo.

Hacé esto en cada instancia del ASG:

  1. EC2Instances → seleccionar la instancia
  2. ActionsMonitor and troubleshootManage detailed monitoring
  3. Tildar EnableConfirm
  4. Repetir para la segunda instancia
# Habilitar detailed monitoring en todas las instancias del ASG
for id in $(aws autoscaling describe-auto-scaling-groups \
  --auto-scaling-group-names d3lt4-web-asg \
  --query 'AutoScalingGroups[0].Instances[].InstanceId' \
  --output text); do
  aws ec2 monitor-instances --instance-ids $id
  echo "✓ detailed monitoring habilitado en $id"
done

Sin esto el stress test no funciona

Con basic monitoring (5 min), el stress test termina antes de que CloudWatch tenga datos suficientes para disparar el scaling. Siempre habilitá detailed monitoring antes de probar auto scaling en labs.

3.3 Verificar que las instancias están healthy

Esperá 3-5 minutos para que el ASG lance las 2 instancias y el ALB haga los health checks.

  1. EC2Auto Scaling Groupsd3lt4-web-asg → pestaña Activity — vas a ver los eventos de launch
  2. EC2Target Groupsd3lt4-web-tg → pestaña Targets — las 2 instancias deben aparecer como Healthy

Targets healthy d3lt4-web-tg — 2 instancias registradas, una en us-east-1a y otra en us-east-1b, ambas Healthy.

# Estado del ASG
aws autoscaling describe-auto-scaling-groups \
  --auto-scaling-group-names d3lt4-web-asg \
  --query 'AutoScalingGroups[0].Instances[].{id:InstanceId,health:HealthStatus,state:LifecycleState}' \
  --output table

# Estado de los targets en el ALB
aws elbv2 describe-target-health \
  --target-group-arn $TG_ARN \
  --query 'TargetHealthDescriptions[].[Target.Id,TargetHealth.State]' \
  --output table

3.4 Probar el ALB y el balanceo

Con los targets healthy, verificamos que el ALB está distribuyendo tráfico.

  1. Copiá el DNS name del ALB desde EC2Load Balancersd3lt4-alb
  2. Abrí el browser y entrá a http://<DNS_DEL_ALB>
  3. Deberías ver la página D3LT4 con el Instance ID y la AZ de una de las instancias
  4. Refrescá varias veces (Ctrl+F5) — el Instance ID y la AZ deberían cambiar entre las dos instancias

¿Por qué no cambia siempre al refrescar?

Los browsers mantienen conexiones HTTP persistentes (keep-alive). Para forzar la rotación entre instancias, usá curl desde la terminal:

ALB_DNS="d3lt4-alb-xxxxxxxxx.us-east-1.elb.amazonaws.com"

for i in $(seq 1 6); do
  echo -n "Request $i: "
  curl -s http://$ALB_DNS | grep -o 'Instance ID.*</p>' | sed 's/<[^>]*>//g'
done

ALB balanceando instancias Primera respuesta — instancia en us-east-1b, IP 10.0.4.221.

ALB round-robin instancia 1a Al refrescar — instancia distinta en us-east-1a, IP 10.0.3.230. El ALB está distribuyendo en round-robin.

3.5 Stress test — probar el scale-out

Ahora lo más entretenido: simular carga alta para ver cómo el ASG lanza instancias nuevas automáticamente.

Primero obtené las IPs privadas de las instancias del ASG. En EC2Instances, filtrá por el Launch Template o buscá las instancias sin nombre fijo que aparecieron después de crear el ASG.

Conectate a ambas usando la NAT Instance como bastion (igual que en el Lab 01):

# Terminal 1 — instancia en us-east-1a
ssh -o ProxyCommand="ssh -i d3lt4-key.pem -W %h:%p ec2-user@<IP_PUBLICA_NAT>" \
    -i d3lt4-key.pem ec2-user@<IP_PRIVADA_INSTANCIA_1>

# Terminal 2 — instancia en us-east-1b
ssh -o ProxyCommand="ssh -i d3lt4-key.pem -W %h:%p ec2-user@<IP_PUBLICA_NAT>" \
    -i d3lt4-key.pem ec2-user@<IP_PRIVADA_INSTANCIA_2>

En ambas terminales, ejecutá el stress test simultáneamente:

# Genera carga en todas las CPUs durante 5 minutos
stress --cpu $(nproc) --timeout 300

Stress test instancia 1b Stress corriendo en la instancia de us-east-1b — 2 cpu hogs despachados.

Stress test instancia 1a Stress corriendo simultáneamente en us-east-1a — ambas instancias al 100% de CPU.

Mientras corre, monitoreá el ASG en paralelo:

  1. EC2Auto Scaling Groupsd3lt4-web-asg → pestaña Activity — esperá eventos de "Launching a new EC2 instance"
  2. EC2Auto Scaling Groupsd3lt4-web-asg → pestaña MonitoringEC2 → ver la métrica CPU Utilization

El scale-out no es instantáneo

Con detailed monitoring habilitado (1 min), CloudWatch detecta la alarma en ~2-3 minutos. El ASG tarda ~30-60 segundos en decidir escalar. La instancia nueva tarda ~2-3 minutos en arrancar y pasar los health checks.

Total: esperá ~5 minutos antes de ver las nuevas instancias en el Target Group.

# Ver el estado del ASG cada 30 segundos
watch -n 30 'aws autoscaling describe-auto-scaling-groups \
  --auto-scaling-group-names d3lt4-web-asg \
  --query "AutoScalingGroups[0].{Desired:DesiredCapacity,Current:length(Instances)}" \
  --output table'

Scale-out CPU Métrica CPU Utilization en CloudWatch — pico de 85.5%, el ASG actualizando capacity de 2 a 4.

Scale-out Activity Activity log del ASG — 2 instancias nuevas lanzadas por la alarma TargetTracking, en estado "Waiting for instance warmup".

Una vez que termina el stress test, observá el scale-in: el ASG espera el cooldown period (300 segundos por defecto) antes de destruir instancias, para evitar "flapping" — escalar y desescalar constantemente si el CPU oscila alrededor del umbral.

Scale-in Scale-in en acción — el ASG terminando instancias de 4→3→2. La causa: alarma TargetTracking detectó CPU bajo el umbral sostenidamente.

Verificación Parte 3

  • Detailed Monitoring habilitado en ambas instancias del ASG
  • Las 2 instancias del ASG aparecen como Healthy en el Target Group
  • http://<DNS_ALB> muestra la página D3LT4 con los datos de la instancia
  • Refrescar varias veces (o curl en loop) cambia el Instance ID entre instancias (round-robin)
  • Durante el stress test, la CPU subió a ~85% y el ASG escaló a 4 instancias
  • Después de ~15 minutos con CPU baja, el ASG volvió a 2 instancias (scale-in automático)

Limpieza

El ALB cobra por hora

A diferencia del Lab 01, el ALB no es Free Tier — cobra ~USD $0.008/hora más costo por LCU. Eliminalo cuando no estés practicando. Las EC2 t2.micro del ASG sí son Free Tier.

El orden importa: primero el ASG (para terminar las instancias), después el ALB.

  1. EC2Auto Scaling Groupsd3lt4-web-asgDelete → confirmar (Esto termina automáticamente todas las instancias del ASG)
  2. EC2Load Balancersd3lt4-albActionsDelete load balancer → confirmar
  3. EC2Target Groupsd3lt4-web-tgActionsDelete → confirmar
# 1. Borrar el ASG (--force-delete termina las instancias sin esperar lifecycle hooks)
aws autoscaling delete-auto-scaling-group \
  --auto-scaling-group-name d3lt4-web-asg --force-delete

# 2. Borrar el ALB
aws elbv2 delete-load-balancer --load-balancer-arn $ALB_ARN

# 3. Esperar a que el ALB se elimine antes de borrar el Target Group
aws elbv2 wait load-balancers-deleted --load-balancer-arns $ALB_ARN

# 4. Borrar el Target Group
aws elbv2 delete-target-group --target-group-arn $TG_ARN

Lo que dejamos corriendo (gratis)

  • VPC, subnets, IGW, Route Tables → siempre gratis
  • NAT Instance (d3lt4-nat-instance) → t2.micro Free Tier, parala cuando no practiques
  • Launch Template → gratis, no tiene costo por existir

Actualizar mis-recursos.sh

Agregá estas variables al archivo mis-recursos.sh del Lab 01:

# Lab 02
export ALB_SG="sg-XXXXXXXXX"      # d3lt4-alb-sg
export ASG_SG="sg-XXXXXXXXX"      # d3lt4-asg-sg
export TG_ARN="arn:aws:elasticloadbalancing:us-east-1:XXXX:targetgroup/d3lt4-web-tg/XXXX"
export ALB_ARN="arn:aws:elasticloadbalancing:us-east-1:XXXX:loadbalancer/app/d3lt4-alb/XXXX"
export ALB_DNS="d3lt4-alb-XXXXXXXXX.us-east-1.elb.amazonaws.com"

Resumen de conceptos clave

Concepto Detalle
SPOF Single Point of Failure. Un solo componente que si falla, cae todo. El ALB + ASG eliminan el SPOF de las instancias.
ALB vs NLB ALB = capa 7 (HTTP/HTTPS, path/host routing). NLB = capa 4 (TCP/UDP, ultra baja latencia). CLB = deprecated.
Listener El ALB escucha en un puerto. Cada listener tiene reglas que determinan a qué Target Group enviar el tráfico.
Target Group Colección de destinos con health checks. Round Robin por defecto.
Health check ALB hace GET a / cada 15s. 2 OK seguidos → healthy. 2 fail seguidos → unhealthy → deja de mandar tráfico.
ELB vs EC2 health checks EC2 check: ¿la instancia está running? ELB check: ¿tu app responde HTTP 200? El ELB check detecta crashes de app.
DNS name del ALB El ALB no tiene IP fija. En producción apuntás un CNAME o Alias Record de Route 53 al DNS name.
Launch Template Blueprint para EC2. Versionable. El ASG lo usa para lanzar instancias idénticas.
ASG — min/desired/max Min: garantía de disponibilidad. Desired: estado actual. Max: límite de costo.
Self-healing Si una instancia falla el health check, el ASG la destruye y lanza una nueva automáticamente.
Target Tracking Scaling policy que mantiene una métrica en un valor objetivo. La más simple de configurar.
Instance warmup Tiempo que el ASG espera antes de medir el CPU de una instancia nueva. Evita scale-out espurio durante el arranque.
Cooldown period Tiempo que espera el ASG antes de volver a escalar. Evita flapping. 300s por defecto.
SG source = otro SG En vez de una IP como source, referenciás otro SG. Si las IPs del ALB cambian, la regla sigue funcionando.
Subnets privadas para instancias Las EC2s del ASG van en subnets privadas — solo el ALB puede llegar a ellas por HTTP.
Basic vs Detailed Monitoring Basic: métricas cada 5 min (default). Detailed: cada 1 min. Obligatorio habilitar Detailed para que el auto scaling funcione en labs.
Scale-in conservador Target Tracking espera 15 min consecutivos con CPU bajo el umbral antes de terminar instancias. Es intencional para evitar flapping.