tutoriales.com

Gestionando Servidores sin Estado con Terraform y AWS Auto Scaling Groups

Este tutorial te guiará a través del proceso de aprovisionamiento y gestión de servidores sin estado utilizando AWS Auto Scaling Groups (ASG) con Terraform. Aprenderás a configurar grupos de autoescalado, políticas de escalado, balanceadores de carga y monitoreo, garantizando alta disponibilidad y escalabilidad para tus aplicaciones.

Intermedio20 min de lectura10 views
Reportar error

🚀 Introducción: Servidores sin Estado y Auto Scaling Groups

En el mundo de la infraestructura como código (IaC), la gestión eficiente y escalable de servidores es fundamental. Los servidores sin estado (stateless servers) son la piedra angular de muchas arquitecturas modernas, permitiendo que las aplicaciones sean resilientes, elásticas y fáciles de escalar. A diferencia de los servidores con estado, que mantienen datos o sesiones localmente, los servidores sin estado no conservan ninguna información entre solicitudes, lo que los hace ideales para ser reemplazados o escalados horizontalmente sin impacto.

AWS Auto Scaling Groups (ASG) es un servicio de AWS que ayuda a asegurar que tienes el número correcto de instancias Amazon EC2 disponibles para manejar la carga de tu aplicación. Los ASG te permiten mantener la disponibilidad de la aplicación y te proporcionan escalado automático, añadiendo o eliminando instancias según sea necesario. Combinar esto con Terraform nos permite definir, versionar y desplegar nuestra infraestructura de manera declarativa y automatizada.

¿Por qué Terraform y ASG?

La sinergia entre Terraform y AWS Auto Scaling Groups es poderosa. Terraform nos permite definir la configuración completa de nuestros ASG, incluyendo los detalles de lanzamiento de instancias, las políticas de escalado, los balanceadores de carga asociados y las métricas de monitoreo, todo como código. Esto no solo mejora la repetibilidad y reduce errores manuales, sino que también facilita la implementación de prácticas DevOps como la integración y entrega continua (CI/CD) para la infraestructura.

💡 Consejo: Adoptar servidores sin estado simplifica enormemente la gestión de la infraestructura, ya que cualquier instancia puede ser terminada y reemplazada sin perder información vital de la aplicación, que debería residir en servicios externos como bases de datos o sistemas de colas.

🎯 Objetivos del Tutorial

Al finalizar este tutorial, serás capaz de:

  • Comprender los conceptos clave de los servidores sin estado y AWS Auto Scaling Groups.
  • Aprovisionar un Auto Scaling Group básico con Terraform.
  • Configurar un Launch Template para definir el tipo de instancias.
  • Integrar un Application Load Balancer (ALB) con el ASG.
  • Implementar políticas de escalado dinámicas (basadas en CPU).
  • Configurar monitoreo básico y notificaciones.

🛠️ Requisitos Previos

Antes de empezar, asegúrate de tener lo siguiente:

  • Una cuenta de AWS con credenciales configuradas (clave de acceso y clave secreta) en tu entorno local. Puedes configurarlas a través de variables de entorno, el archivo ~/.aws/credentials, o el comando aws configure.
  • Terraform instalado en tu máquina local. Si no lo tienes, puedes descargarlo desde terraform.io.
  • Conocimientos básicos de AWS EC2, VPC y Terraform.

🏗️ Estructura del Proyecto

Organizaremos nuestro proyecto Terraform de la siguiente manera:

. 
├── main.tf
├── variables.tf
├── outputs.tf
└── providers.tf

Esta estructura nos permite mantener el código ordenado y modular.


📝 Configurando el Proveedor de AWS

Comenzaremos configurando el proveedor de AWS en providers.tf.

# providers.tf
provider "aws" {
  region = "us-east-1" # Puedes cambiar a tu región preferida
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
  required_version = ">= 1.0.0"
}
🔥 Importante: Siempre especifica la versión del proveedor y de Terraform para asegurar consistencia y evitar sorpresas con cambios retrocompatibles.

🌐 Creando una VPC y Subredes (Si no tienes una existente)

Para desplegar instancias EC2 y un ALB, necesitamos una Virtual Private Cloud (VPC) y al menos dos subredes públicas en diferentes zonas de disponibilidad para alta disponibilidad. Si ya tienes una VPC configurada, puedes omitir esta sección y usar tus IDs de VPC y subredes existentes.

# main.tf (parte 1: VPC y subredes)
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "terraform-asg-vpc"
  }
}

resource "aws_subnet" "public_a" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-east-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "terraform-asg-public-a"
  }
}

resource "aws_subnet" "public_b" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-east-1b"
  map_public_ip_on_launch = true

  tags = {
    Name = "terraform-asg-public-b"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "terraform-asg-igw"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }

  tags = {
    Name = "terraform-asg-public-rt"
  }
}

resource "aws_route_table_association" "public_a" {
  subnet_id      = aws_subnet.public_a.id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "public_b" {
  subnet_id      = aws_subnet.public_b.id
  route_table_id = aws_route_table.public.id
}

🛡️ Configurando Grupos de Seguridad

Necesitamos grupos de seguridad para permitir el tráfico HTTP a nuestro ALB y el tráfico entrante a nuestras instancias EC2 desde el ALB.

# main.tf (parte 2: Security Groups)
resource "aws_security_group" "alb" {
  vpc_id = aws_vpc.main.id
  name   = "alb-sg"
  description = "Allow HTTP traffic to ALB"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "terraform-asg-alb-sg"
  }
}

resource "aws_security_group" "asg_instances" {
  vpc_id = aws_vpc.main.id
  name   = "asg-instances-sg"
  description = "Allow traffic from ALB to ASG instances"

  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.alb.id] # Solo permite tráfico desde el ALB
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "terraform-asg-instances-sg"
  }
}

📝 Definiendo un Launch Template

Un Launch Template especifica los parámetros de configuración para las instancias EC2 que el Auto Scaling Group lanzará. Esto incluye el AMI, tipo de instancia, par de claves, grupos de seguridad, y datos de usuario (user data).

# main.tf (parte 3: Launch Template)
data "aws_ami" "amazon_linux_2" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_launch_template" "web_app_template" {
  name_prefix   = "web-app-template-"
  image_id      = data.aws_ami.amazon_linux_2.id
  instance_type = "t3.micro"
  key_name      = "your-key-pair-name" # ¡IMPORTANTE: Reemplaza con tu nombre de par de claves!
  vpc_security_group_ids = [aws_security_group.asg_instances.id]

  user_data = base64encode(<<EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hola desde el ASG! Instancia: $(hostname -f)</h1>" > /var/www/html/index.html
EOF
  )

  tag_specifications {
    resource_type = "instance"
    tags = {
      Name = "web-app-instance"
    }
  }

  lifecycle {
    create_before_destroy = true
  }

  tags = {
    Name = "web-app-launch-template"
  }
}
⚠️ Advertencia: Asegúrate de reemplazar `"your-key-pair-name"` con el nombre de un par de claves EC2 existente en tu cuenta de AWS. Si no lo haces, Terraform fallará al intentar crear las instancias.

El user_data es un script que se ejecuta la primera vez que la instancia arranca. En este ejemplo, instala Apache (httpd), lo inicia y crea un archivo index.html simple. Esto simula una aplicación web sin estado.


⚖️ Configurando un Application Load Balancer (ALB)

Un ALB distribuirá el tráfico entrante a las instancias en nuestro ASG, proporcionando alta disponibilidad y tolerancia a fallos. Necesitaremos un ALB, un Target Group y un Listener.

# main.tf (parte 4: ALB)
resource "aws_lb" "web_app_alb" {
  name               = "web-app-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = [aws_subnet.public_a.id, aws_subnet.public_b.id]

  enable_deletion_protection = false # Para entornos de producción, considera true

  tags = {
    Name = "terraform-asg-alb"
  }
}

resource "aws_lb_target_group" "web_app_tg" {
  name     = "web-app-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 30
    timeout             = 5
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }

  tags = {
    Name = "terraform-asg-target-group"
  }
}

resource "aws_lb_listener" "http_listener" {
  load_balancer_arn = aws_lb.web_app_alb.id
  port              = 80
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.web_app_tg.arn
  }

  tags = {
    Name = "terraform-asg-listener"
  }
}

El health check del Target Group es crucial para que el ALB sepa cuándo una instancia está disponible para recibir tráfico. Si una instancia falla el health check, el ALB dejará de enviarle tráfico hasta que se recupere (o sea reemplazada por el ASG).


🔄 Creando el Auto Scaling Group

Ahora, definiremos el Auto Scaling Group que utilizará nuestro Launch Template y se integrará con el ALB.

# main.tf (parte 5: Auto Scaling Group)
resource "aws_autoscaling_group" "web_app_asg" {
  name                      = "web-app-asg"
  max_size                  = 5
  min_size                  = 2
  desired_capacity          = 2
  vpc_zone_identifier       = [aws_subnet.public_a.id, aws_subnet.public_b.id]
  launch_template {
    id      = aws_launch_template.web_app_template.id
    version = "$Latest"
  }

  target_group_arns = [aws_lb_target_group.web_app_tg.arn]

  health_check_type          = "ELB" # Usa los health checks del ALB
  health_check_grace_period  = 300   # Segundos para esperar antes de hacer health checks iniciales

  tag {
    key                 = "Name"
    value               = "web-app-instance"
    propagate_at_launch = true
  }

  tags_all = {
    Environment = "Development"
    Project     = "WebAppASG"
  }
}

En esta configuración:

  • max_size, min_size y desired_capacity definen los límites y el número inicial de instancias.
  • vpc_zone_identifier especifica las subredes donde se lanzarán las instancias, asegurando distribución entre zonas de disponibilidad.
  • launch_template enlaza el ASG con nuestra configuración de instancias.
  • target_group_arns integra el ASG con el Target Group del ALB.
  • health_check_type = "ELB" indica que el ASG debe usar los health checks del Load Balancer para determinar el estado de las instancias.

📈 Configurando Políticas de Escalado Dinámico

Para que nuestro ASG escale automáticamente, necesitamos definir políticas de escalado. Usaremos una política de escalado basada en la utilización de la CPU.

# main.tf (parte 6: Scaling Policies)
resource "aws_autoscaling_policy" "cpu_utilization_scale_out" {
  name                   = "cpu-utilization-scale-out"
  autoscaling_group_name = aws_autoscaling_group.web_app_asg.name
  policy_type            = "TargetTrackingScaling"

  target_tracking_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ASGAverageCPUUtilization"
    }
    target_value = 50.0 # Mantener la CPU promedio del ASG en 50%
  }
}

resource "aws_autoscaling_policy" "cpu_utilization_scale_in" {
  name                   = "cpu-utilization-scale-in"
  autoscaling_group_name = aws_autoscaling_group.web_app_asg.name
  policy_type            = "TargetTrackingScaling"

  target_tracking_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ASGAverageCPUUtilization"
    }
    target_value       = 50.0
    disable_scale_in   = false # Permite que el ASG reduzca el número de instancias
  }
}

Estas políticas de Target Tracking son muy eficientes: intentan mantener la métrica (ASGAverageCPUUtilization) lo más cerca posible del target_value (50% en este caso) ajustando el número de instancias. AWS CloudWatch y Auto Scaling se encargan de la lógica subyacente.

📌 Nota: Los ASG también pueden configurarse con políticas de escalado basadas en pasos (Step Scaling) o escalado programado (Scheduled Scaling) para requisitos más complejos.

📤 Salidas (Outputs)

Es útil exportar ciertos valores de nuestra infraestructura, como el DNS del ALB, para un fácil acceso.

# outputs.tf
output "alb_dns_name" {
  description = "The DNS name of the Application Load Balancer."
  value       = aws_lb.web_app_alb.dns_name
}

output "asg_name" {
  description = "The name of the Auto Scaling Group."
  value       = aws_autoscaling_group.web_app_asg.name
}

🚀 Despliegue de la Infraestructura

Con todos los archivos .tf configurados, es hora de desplegar la infraestructura.

  1. Inicializar Terraform: Abre tu terminal en la carpeta del proyecto y ejecuta:
terraform init
Esto descargará los plugins necesarios para el proveedor de AWS.

2. Planificar la creación: Para ver qué recursos creará Terraform sin aplicarlos aún, ejecuta:

terraform plan
Revisa cuidadosamente el plan para asegurarte de que todo es como esperas.

3. Aplicar la configuración: Si el plan es correcto, aplica los cambios:

terraform apply
Escribe `yes` cuando se te solicite para confirmar la creación de los recursos.

Este proceso tomará varios minutos, ya que Terraform aprovisionará la VPC, subredes, grupos de seguridad, ALB, Target Group, Launch Template y finalmente el Auto Scaling Group, que a su vez lanzará las instancias EC2.


✅ Verificando el Despliegue

Una vez que terraform apply haya terminado, haz lo siguiente:

  1. Obtén el DNS del ALB: El valor del DNS se mostrará en la salida de Terraform. Si no, puedes ejecutar:
terraform output alb_dns_name
  1. Accede a la aplicación: Copia el DNS del ALB y pégalo en tu navegador web. Deberías ver un mensaje como Hola desde el ASG! Instancia: ip-10-0-1-xxx.ec2.internal.
  2. Monitorea las instancias: Ve a la consola de AWS > EC2 > Grupos de Auto Scaling. Verás tu ASG en estado InService con las instancias lanzadas.
  3. Prueba el escalado: Para probar el escalado, puedes sobrecargar las instancias (por ejemplo, con una herramienta como stress-ng si accedes vía SSH a una de ellas) y observa cómo el ASG lanza nuevas instancias para mantener la CPU por debajo del 50%. Luego, cuando la carga disminuya, verás cómo se reducen las instancias hasta el min_size.
Ejemplo de cómo estresar una instancia (Solo para pruebas) Para estresar una instancia EC2 (asumiendo que tienes SSH configurado con tu key pair y la instancia es accesible), puedes hacer lo siguiente:
  1. Conéctate a una de las instancias EC2 del ASG via SSH.
ssh -i your-key-pair.pem ec2-user@<IP_PUBLICA_DE_LA_INSTANCIA>
  1. Instala stress-ng:
sudo yum install -y stress-ng
  1. Ejecuta stress-ng para sobrecargar la CPU:
stress-ng --cpu 8 --timeout 300s # Estresará 8 núcleos por 5 minutos
Observa los gráficos de CloudWatch para el ASG, y cómo el número de instancias aumenta.
Región AWS (Global) Usuario Application Load Balancer Subredes Públicas CloudWatch Métricas y Alertas Auto Scaling Group (ASG) Availability Zone A Instancia EC2 Instancia EC2 Availability Zone B Instancia EC2 Instancia EC2 Escalado

🧹 Limpieza de Recursos

Para evitar cargos innecesarios, es crucial destruir todos los recursos creados por Terraform una vez que hayas terminado con este tutorial.

terraform destroy

Terraform te pedirá confirmación. Escribe yes para proceder con la eliminación de todos los recursos.

⚠️ Advertencia: El comando `terraform destroy` eliminará *todos* los recursos definidos en tu configuración de Terraform. Asegúrate de que no estás destruyendo nada que necesites en producción.

💡 Consideraciones Adicionales y Buenas Prácticas

  • Monitoreo Avanzado: Integra CloudWatch con alarmas y notificaciones (SNS) para métricas importantes del ASG y el ALB.
  • Gestión de Logs: Implementa un sistema de gestión de logs centralizado (ej. CloudWatch Logs, Splunk, ELK) para recoger los logs de tus instancias EC2.
  • CI/CD para Infraestructura: Automatiza el proceso de terraform plan y terraform apply utilizando herramientas de CI/CD como Jenkins, GitLab CI, GitHub Actions o AWS CodePipeline.
  • Versionado de Launch Templates: En un entorno de producción, utiliza diferentes versiones de tus Launch Templates para desplegar nuevas versiones de tu aplicación sin interrupción (despliegues blue/green o rolling updates).
  • AMI Personalizadas: En lugar de instalar software en user_data, considera crear AMIs personalizadas con tu aplicación preinstalada y configurada. Esto acelera el lanzamiento de instancias y simplifica el user_data.
  • Políticas de Terminación: Los ASG tienen políticas de terminación que controlan qué instancia se elimina durante un evento de reducción de escala. Por defecto, intentan preservar la disponibilidad de las zonas de disponibilidad.
  • Etiquetado (Tagging): Utiliza etiquetas consistentes para organizar y gestionar tus recursos de AWS, facilitar la facturación y el monitoreo.

📚 Recursos Adicionales


Conclusión ✨

Has completado un tutorial práctico sobre cómo aprovisionar y gestionar servidores sin estado utilizando AWS Auto Scaling Groups con Terraform. Dominar esta combinación es esencial para construir arquitecturas en la nube que sean escalables, resilientes y eficientes en costos. La capacidad de definir tu infraestructura como código te brinda un control sin precedentes y la agilidad necesaria para responder rápidamente a las demandas cambiantes de tus aplicaciones.

¡Sigue explorando las posibilidades de Terraform y AWS para llevar tus habilidades de DevOps al siguiente nivel!

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!