Ejercicio Práctico: Construir un Entorno Web con EC2, S3 y RDS

Lectura
30 min~6 min lectura

Concepto clave

En DevOps, la infraestructura como código (IaC) transforma la gestión de recursos cloud de un proceso manual y propenso a errores en uno automatizado y repetible. Terraform es una herramienta clave que permite definir, aprovisionar y gestionar infraestructura mediante archivos de configuración declarativos. Imagina que construir un entorno web en AWS es como armar un mueble de IKEA: sin instrucciones, es caótico; con un manual claro (tu código Terraform), cualquier persona puede replicar el mismo resultado de forma consistente.

En esta lección, aprenderás a orquestar tres servicios AWS fundamentales: EC2 para servidores web, S3 para almacenamiento estático, y RDS para bases de datos. La magia de Terraform está en su capacidad de gestionar dependencias entre recursos: por ejemplo, asegura que la base de datos RDS esté disponible antes de que la instancia EC2 intente conectarse a ella, evitando fallos en el despliegue.

Cómo funciona en la práctica

El flujo típico implica cuatro pasos: 1) Escribir archivos .tf que definen los recursos AWS, 2) Ejecutar terraform init para inicializar el proyecto y descargar proveedores, 3) Usar terraform plan para revisar los cambios propuestos sin aplicarlos, y 4) Aplicar con terraform apply para crear la infraestructura real. Por ejemplo, para un entorno web básico, definirías una VPC, subredes, un grupo de seguridad para EC2, la instancia misma, un bucket S3 para assets, y una instancia RDS MySQL.

Un aspecto crítico es el uso de módulos de Terraform, que son contenedores reutilizables de configuración. En lugar de escribir todo desde cero, puedes usar módulos de la comunidad (como los de Terraform Registry) o crear los tuyos propios para encapsular configuraciones comunes, como una "plantilla" de instancia EC2 con ciertas políticas IAM adjuntas. Esto acelera el desarrollo y estandariza las implementaciones.

Código en acción

Aquí tienes un ejemplo básico de un archivo main.tf que define una instancia EC2 con un bucket S3 asociado. Nota cómo se usa el proveedor AWS y se referencian recursos entre sí:

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "web_assets" {
  bucket = "mi-bucket-web-${random_id.suffix.hex}"
  acl    = "private"

  tags = {
    Name = "Assets del sitio web"
  }
}

resource "aws_instance" "web_server" {
  ami           = "ami-0c55b159cbfafe1f0"  # Amazon Linux 2
  instance_type = "t2.micro"
  key_name      = "mi-key-pair"

  vpc_security_group_ids = [aws_security_group.web_sg.id]

  user_data = <<-EOF
              #!/bin/bash
              yum update -y
              yum install -y httpd
              systemctl start httpd
              systemctl enable httpd
              EOF

  tags = {
    Name = "Servidor Web"
  }
}

resource "random_id" "suffix" {
  byte_length = 4
}

Ahora, mejoremos esto refactorizando en un módulo. Antes: Código monolítico en un solo archivo. Después: Separamos la configuración en módulos reutilizables. Crea una carpeta modules/ec2 con su propio main.tf:

# modules/ec2/main.tf
variable "ami_id" {
  type    = string
  default = "ami-0c55b159cbfafe1f0"
}

variable "instance_type" {
  type    = string
  default = "t2.micro"
}

resource "aws_instance" "this" {
  ami           = var.ami_id
  instance_type = var.instance_type
  # ... más configuraciones
}

output "instance_id" {
  value = aws_instance.this.id
}

Luego, en tu raíz, llamas al módulo así:

module "web_server" {
  source = "./modules/ec2"
  ami_id = "ami-0c55b159cbfafe1f0"
}

Errores comunes

  • No gestionar el estado de Terraform: El archivo terraform.tfstate guarda el estado real de tu infraestructura. Si lo pierdes o no lo versionas (por ejemplo, en S3 con bloqueo DynamoDB), puedes causar inconsistencias graves. Solución: Configura siempre un backend remoto.
  • Hardcodear valores sensibles: Incluir contraseñas o keys directamente en el código es un riesgo de seguridad. En su lugar, usa variables de entorno, AWS Secrets Manager, o el bloque sensitive = true en Terraform.
  • Ignorar las dependencias implícitas: Terraform deduce dependencias basado en referencias, pero a veces necesitas depends_on explícito. Por ejemplo, si EC2 depende de un rol IAM que se crea en otro recurso, asegúrate de declararlo.
  • No usar terraform plan antes de apply: Aplicar cambios sin revisarlos puede llevar a costos inesperados o tiempo de inactividad. Siempre ejecuta plan para previsualizar.
  • Olvidar etiquetar recursos: Las etiquetas (tags) son cruciales para gestión de costos y organización en AWS. Incluye al menos Name y Environment en todos los recursos.

Checklist de dominio

  1. Puedo escribir un archivo Terraform que despliegue una instancia EC2 con un grupo de seguridad personalizado.
  2. Sé configurar un backend remoto en S3 para el estado de Terraform, con bloqueo DynamoDB.
  3. Puedo crear y usar un módulo de Terraform para encapsular lógica común, como una configuración de VPC.
  4. Entiendo cómo manejar salidas (outputs) de módulos para pasar información entre recursos.
  5. Puedo integrar RDS en mi configuración, manejando contraseñas de forma segura con AWS Secrets Manager.
  6. Sé usar terraform destroy para limpiar recursos y evitar costos innecesarios.
  7. Puedo leer y depurar errores comunes de Terraform, como problemas de sintaxis HCL o permisos IAM insuficientes.

Despliega un entorno web completo con EC2, S3 y RDS usando módulos

Objetivo: Crear una infraestructura AWS que incluya un servidor web (EC2), almacenamiento para archivos estáticos (S3), y una base de datos (RDS MySQL), utilizando módulos de Terraform para promover reusabilidad.

  1. Preparación: Asegúrate de tener AWS CLI configurado con credenciales y Terraform instalado. Crea un directorio nuevo para el proyecto.
  2. Configura el proveedor y backend: En un archivo provider.tf, define el proveedor AWS para la región us-east-1. Configura un backend remoto en S3 (simulado localmente para este ejercicio, pero menciona cómo sería en producción).
  3. Crea módulos:
    • En modules/ec2, define un módulo para una instancia EC2 con Amazon Linux 2, tipo t2.micro, y un script de user_data que instale Apache.
    • En modules/s3, define un módulo para un bucket S3 con políticas básicas de acceso privado.
    • En modules/rds, define un módulo para una instancia RDS MySQL (db.t2.micro) con almacenamiento de 20 GB.
  4. Integra los módulos: En el archivo principal main.tf, llama a los tres módulos. Asegúrate de que el módulo EC2 tenga una dependencia explícita (depends_on) al módulo RDS para garantizar que la base de datos esté lista antes de que el servidor intente conectarse.
  5. Maneja variables y salidas: Usa un archivo variables.tf para parámetros como el ID de AMI o la contraseña de RDS (usa valores por defecto seguros). En outputs.tf, expone la IP pública de EC2 y el endpoint de RDS.
  6. Ejecuta y verifica: Corre terraform init, luego terraform plan para revisar. Si todo está bien, aplica con terraform apply. Verifica en la consola AWS que los recursos se crearon correctamente.
  7. Limpieza: Al final, ejecuta terraform destroy para eliminar todos los recursos y evitar cargos.
Pistas
  • Usa el bloque 'resource "aws_db_instance"' en el módulo RDS, y considera agregar un grupo de seguridad que permita tráfico desde EC2.
  • Para el user_data en EC2, puedes incluir un comando para descargar un archivo de ejemplo desde el bucket S3 usando AWS CLI.
  • Recuerda que en módulos, las variables se definen con 'variable' y se pasan al llamar el módulo; las salidas se definen con 'output' para exponer valores útiles.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.