DEV Community

Jesus Oviedo Riquelme
Jesus Oviedo Riquelme

Posted on

LLPY-11: Terraform - Infraestructura como Código

🎯 El Desafío de Gestionar Infraestructura Cloud

Imagina que necesitas desplegar tu sistema RAG en GCP:

  • VM para Qdrant (Compute Engine)
  • API en Cloud Run (FastAPI)
  • Batch Job (Cloud Run Job para procesamiento)
  • Storage (Google Cloud Storage)
  • Secrets (Secret Manager para .env y JWT keys)

El problema: ¿Cómo creas, actualizas y gestionas toda esta infraestructura de forma reproducible, versionada y colaborativa?

Opciones para Gestionar Infraestructura

Método Pros Contras Reproducibilidad
Console UI (manual) Fácil, visual Propenso a errores, no versionado ❌ Ninguna
gcloud CLI scripts Automatizado Scripts frágiles, difícil rollback ⚠️ Limitada
Cloud Formation IaC nativo AWS Solo AWS ✅ Alta (AWS only)
Pulumi Multiple lenguajes Requiere runtime ✅ Alta
Terraform Declarativo, multi-cloud Learning curve ✅✅ Muy Alta

Nuestra elección: Terraform

📊 La Magnitud del Problema

Requisitos de Infraestructura

Para el proyecto Lus Laboris necesitamos:

  1. 🗄️ Google Cloud Storage

    • Bucket para datos procesados
    • Bucket para Terraform state (remoto)
  2. 🖥️ Compute Engine VM

    • VM para Qdrant (vector database)
    • Ubuntu 22.04 LTS
    • Firewall rules (ports 6333, 6334, 22)
    • SPOT instance (cost optimization)
  3. 🚀 Cloud Run Service

    • FastAPI container
    • Secrets montados de Secret Manager
    • Auto-scaling (0-10 instances)
    • 2 CPU, 2Gi RAM
  4. ⏰ Cloud Run Job

    • Batch processing (scheduled)
    • Cron schedule
    • Logs y notificaciones
  5. 🔐 Secret Manager

    • .env file (all API config)
    • JWT public key
    • IAM permissions

Desafíos Sin IaC

Sin Terraform:

Developer 1 crea VM via Console → Settings no documentados
Developer 2 necesita replicar → "¿Qué settings usaste?"
Developer 1: "Hmm... creo que era e2-medium con 20GB..."
Developer 2: "¿Y el firewall?"
Developer 1: "Olvidé... tendrás que experimentar"

Disaster Recovery: "La VM se borró, ¿cómo la recreo?"
Team: 🤷 "No hay backup de la configuración"
Enter fullscreen mode Exit fullscreen mode

Con Terraform:

git clone repo
terraform apply
✅ Toda la infraestructura recreada en 5 minutos
✅ Configuración exacta versionada en Git
✅ Documentación viva en código
✅ Rollback a cualquier versión anterior
Enter fullscreen mode Exit fullscreen mode

💡 La Solución: Terraform Infrastructure as Code

¿Qué es Terraform?

Terraform (por HashiCorp) es una herramienta de Infrastructure as Code (IaC) que permite:

  • 📝 Definir infraestructura en archivos declarativos (HCL)
  • 📊 Planear cambios antes de aplicarlos
  • 🚀 Aplicar cambios de forma idempotente
  • 🗑️ Destruir infraestructura limpiamente
  • 🔄 Versionado en Git como código

Principios de Terraform

  1. Declarativo: Describes el estado deseado, no los pasos
  2. Idempotente: Ejecutar N veces = mismo resultado
  3. Plan-Apply: Preview de cambios antes de ejecutar
  4. State Management: Trackea estado actual vs deseado
  5. Modular: Componentes reutilizables

🏗️ Arquitectura de Terraform en el Proyecto

Estructura de Carpetas

terraform/
├── main.tf                    # Orquestación de módulos
├── variables.tf               # Definición de variables
├── terraform.tfvars           # Valores de variables
├── providers.tf               # Configuración de GCP provider
├── tf_menu.sh                 # Script interactivo para ops comunes
├── README.md                  # Documentación
│
└── modules/                   # Módulos reutilizables
    ├── gcs/                   # Google Cloud Storage
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    │
    ├── compute_engine/        # VM para Qdrant
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    │
    ├── cloud_run_service/     # FastAPI en Cloud Run
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    │
    ├── cloud_run_job/         # Batch processing
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    │
    └── secret_manager/        # Secrets management
        ├── main.tf
        ├── variables.tf
        └── outputs.tf
Enter fullscreen mode Exit fullscreen mode

Principio de diseño: Un módulo = un recurso lógico reutilizable

🚀 Implementación Paso a Paso

1. Configuración de Providers

Archivo terraform/providers.tf:

# Provider de Google Cloud Platform
provider "google" {
  project = var.project_id
  region  = var.region
}

# Backend para almacenar state remoto en GCS
terraform {
  required_version = ">= 1.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 6.0"
    }
  }

  # Remote state backend
  backend "gcs" {
    bucket = "py-labor-law-rag-terraform-state"
    prefix = "terraform/state"
  }
}
Enter fullscreen mode Exit fullscreen mode

Características:

  • Remote state: State almacenado en GCS (no local)
  • Versión fijada: ~> 6.0 = 6.x.x (semver)
  • State locking: GCS provee locking automático
  • Team collaboration: Múltiples devs comparten state

2. Definición de Variables

Archivo terraform/variables.tf:

# Basic GCP Configuration
variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "region" {
  description = "GCP Region"
  type        = string
  default     = "us-central1"
}

variable "project_number" {
  description = "GCP Project Number (for service accounts)"
  type        = string
}

# Google Cloud Storage
variable "bucket_name" {
  description = "Name for the GCS bucket"
  type        = string
}

# Compute Engine (Qdrant VM)
variable "qdrant_vm_name" {
  description = "Name for the Qdrant VM"
  type        = string
  default     = "qdrant-vm"
}

variable "qdrant_vm_machine_type" {
  description = "Machine type for Qdrant VM"
  type        = string
  default     = "e2-medium"
}

variable "qdrant_vm_zone" {
  description = "Zone for Qdrant VM"
  type        = string
  default     = "us-central1-a"
}

variable "qdrant_vm_disk_size" {
  description = "Boot disk size in GB"
  type        = number
  default     = 20
}

# Cloud Run Service (API)
variable "api_service_name" {
  description = "Name of the Cloud Run service"
  type        = string
  default     = "lus-laboris-api"
}

variable "api_image" {
  description = "Docker image for the API"
  type        = string
}

variable "api_container_port" {
  description = "Container port for the API"
  type        = number
  default     = 8000
}

variable "api_cpu" {
  description = "Number of CPUs for the API"
  type        = string
  default     = "2"
}

variable "api_memory" {
  description = "Memory for the API (e.g., 2Gi)"
  type        = string
  default     = "2Gi"
}

variable "api_min_instance_count" {
  description = "Minimum number of instances"
  type        = number
  default     = 0  # Scale to zero for cost savings
}

variable "api_max_instance_count" {
  description = "Maximum number of instances"
  type        = number
  default     = 10
}

variable "api_timeout" {
  description = "Request timeout"
  type        = string
  default     = "300s"
}

# Secret Manager
variable "api_env_secret_id" {
  description = "Secret ID for .env file"
  type        = string
}

variable "jwt_public_key_secret_id" {
  description = "Secret ID for JWT public key"
  type        = string
}

# Cloud Run Job (Batch)
variable "job_name" {
  description = "Name of the Cloud Run Job"
  type        = string
}

variable "image" {
  description = "Docker image for the job"
  type        = string
}

variable "args" {
  description = "Arguments for the job"
  type        = list(string)
  default     = []
}

variable "schedule" {
  description = "Cron schedule for the job"
  type        = string
  default     = "0 2 * * *"  # 2 AM daily
}

variable "notify_email" {
  description = "Email for job notifications"
  type        = string
}
Enter fullscreen mode Exit fullscreen mode

3. Módulo: Compute Engine (VM para Qdrant)

Archivo terraform/modules/compute_engine/main.tf:

# VM Instance para Qdrant
resource "google_compute_instance" "qdrant_vm" {
  name         = var.vm_name
  machine_type = var.machine_type
  zone         = var.zone

  boot_disk {
    initialize_params {
      image = "ubuntu-os-cloud/ubuntu-2204-lts"
      size  = var.disk_size  # GB
    }
  }

  network_interface {
    network = "default"

    access_config {
      # Ephemeral public IP
      # Para IP estática, especificar: nat_ip = google_compute_address.static.address
    }
  }

  tags = ["qdrant-server", "http-server", "https-server"]

  # SPOT instance para optimización de costos
  scheduling {
    preemptible       = true          # Puede ser interrumpida
    automatic_restart = false         # No reiniciar automáticamente
    provisioning_model = "SPOT"       # Pricing model
  }

  # Metadata para startup script (opcional)
  metadata = {
    ssh-keys = "user:ssh-rsa AAAAB3..."  # Si necesitas SSH
  }
}

# Firewall rule para Qdrant
resource "google_compute_firewall" "qdrant_firewall" {
  name    = "${var.vm_name}-firewall"
  network = "default"

  allow {
    protocol = "tcp"
    ports    = ["6333", "6334", "22"]  # HTTP, gRPC, SSH
  }

  source_ranges = ["0.0.0.0/0"]  # ⚠️ En producción, restringir a IPs específicas
  target_tags   = ["qdrant-server"]
}
Enter fullscreen mode Exit fullscreen mode

Archivo terraform/modules/compute_engine/outputs.tf:

output "vm_name" {
  description = "Name of the VM instance"
  value       = google_compute_instance.qdrant_vm.name
}

output "vm_external_ip" {
  description = "External IP of the VM"
  value       = google_compute_instance.qdrant_vm.network_interface[0].access_config[0].nat_ip
}

output "vm_internal_ip" {
  description = "Internal IP of the VM"
  value       = google_compute_instance.qdrant_vm.network_interface[0].network_ip
}

output "vm_zone" {
  description = "Zone where the VM is deployed"
  value       = google_compute_instance.qdrant_vm.zone
}
Enter fullscreen mode Exit fullscreen mode

Características del módulo:

  • SPOT instance: Hasta 80% más barato que VM normal
  • Ubuntu 22.04 LTS: OS estable y actualizado
  • Firewall automático: Ports correctos abiertos
  • Outputs: IP externa/interna para configuración posterior

4. Módulo: Cloud Run Service (FastAPI)

Archivo terraform/modules/cloud_run_service/main.tf:

# Cloud Run Service para FastAPI
resource "google_cloud_run_v2_service" "api_service" {
  name     = var.service_name
  location = var.region
  project  = var.project_id

  # Permitir destrucción sin intervención manual
  deletion_protection = false

  template {
    containers {
      image = var.image  # Docker image from Docker Hub

      ports {
        container_port = var.container_port  # 8000
      }

      # Variables de entorno
      env {
        name  = "API_HOST"
        value = "0.0.0.0"
      }

      env {
        name  = "API_PORT"
        value = tostring(var.container_port)
      }

      env {
        name  = "API_RELOAD"
        value = "false"
      }

      env {
        name  = "API_JWT_PUBLIC_KEY_PATH"
        value = "/app/secrets/jwt/public_key.pem"
      }

      env {
        name  = "API_ENV_FILE_PATH"
        value = "/app/secrets/env/.env"
      }

      # Montar secrets desde Secret Manager
      volume_mounts {
        name       = "env-secret"
        mount_path = "/app/secrets/env"
      }

      volume_mounts {
        name       = "jwt-secret"
        mount_path = "/app/secrets/jwt"
      }

      # Recursos
      resources {
        limits = {
          cpu    = var.cpu     # "2"
          memory = var.memory  # "2Gi"
        }
      }

      # Liveness probe
      liveness_probe {
        http_get {
          path = "/api/health"
          port = var.container_port
        }
        initial_delay_seconds = 5
        period_seconds        = 10
        timeout_seconds       = 5
        failure_threshold     = 3
      }
    }

    # Volúmenes para secrets
    volumes {
      name = "env-secret"
      secret {
        secret       = var.env_secret_name
        default_mode = 0444  # Read-only
        items {
          path    = ".env"
          version = "latest"
        }
      }
    }

    volumes {
      name = "jwt-secret"
      secret {
        secret       = var.jwt_secret_name
        default_mode = 0444  # Read-only
        items {
          path    = "public_key.pem"
          version = "latest"
        }
      }
    }

    # Auto-scaling
    scaling {
      min_instance_count = var.min_instance_count  # 0 para scale-to-zero
      max_instance_count = var.max_instance_count  # 10
    }

    # Timeout
    timeout = var.timeout  # "300s"

    # Service account
    service_account = "${var.project_id}@appspot.gserviceaccount.com"
  }

  # Traffic routing (100% a última revisión)
  traffic {
    percent = 100
    type    = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
  }
}

# IAM policy para permitir acceso público
resource "google_cloud_run_service_iam_policy" "api_service_policy" {
  location = google_cloud_run_v2_service.api_service.location
  project  = google_cloud_run_v2_service.api_service.project
  service  = google_cloud_run_v2_service.api_service.name

  policy_data = data.google_iam_policy.api_service_policy.policy_data
}

data "google_iam_policy" "api_service_policy" {
  binding {
    role = "roles/run.invoker"
    members = [
      "allUsers",  # Acceso público
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Características:

  • Scale to zero: Min instances = 0 (ahorro de costos)
  • Secrets management: Montados desde Secret Manager
  • Health checks: Liveness probe en /api/health
  • Auto-scaling: 0-10 instances según carga
  • No CPU throttling: Performance consistente

5. Módulo: Secret Manager

Archivo terraform/modules/secret_manager/main.tf:

# Secret para .env file
resource "google_secret_manager_secret" "api_env_file" {
  secret_id = var.api_env_secret_id

  replication {
    auto {}
  }
}

# Secret para JWT public key
resource "google_secret_manager_secret" "jwt_public_key" {
  secret_id = var.jwt_public_key_secret_id

  replication {
    auto {}
  }
}

# IAM permissions para que Cloud Run acceda a secrets
resource "google_secret_manager_secret_iam_member" "api_env_access" {
  secret_id = google_secret_manager_secret.api_env_file.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${var.cloud_run_service_account}@appspot.gserviceaccount.com"
}

resource "google_secret_manager_secret_iam_member" "jwt_key_access" {
  secret_id = google_secret_manager_secret.jwt_public_key.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${var.cloud_run_service_account}@appspot.gserviceaccount.com"
}
Enter fullscreen mode Exit fullscreen mode

Nota: Los secrets se crean vacíos. El contenido se agrega via GitHub Actions workflow o gcloud CLI.

6. Main File (Orquestación)

Archivo terraform/main.tf:

# Google Cloud Storage
module "gcs" {
  source      = "./modules/gcs"
  project_id  = var.project_id
  region      = var.region
  bucket_name = var.bucket_name
}

# Compute Engine VM (Qdrant)
module "compute_engine" {
  source = "./modules/compute_engine"

  vm_name      = var.qdrant_vm_name
  machine_type = var.qdrant_vm_machine_type
  zone         = var.qdrant_vm_zone
  disk_size    = var.qdrant_vm_disk_size
}

# Secret Manager (MUST be created BEFORE Cloud Run)
module "secret_manager" {
  source = "./modules/secret_manager"

  project_id                = var.project_id
  cloud_run_service_account = var.project_number
  api_env_secret_id         = var.api_env_secret_id
  jwt_public_key_secret_id  = var.jwt_public_key_secret_id
}

# Cloud Run Service (API)
module "cloud_run_service" {
  source = "./modules/cloud_run_service"

  project_id         = var.project_id
  region             = var.region
  service_name       = var.api_service_name
  image              = var.api_image
  container_port     = var.api_container_port
  cpu                = var.api_cpu
  memory             = var.api_memory
  min_instance_count = var.api_min_instance_count
  max_instance_count = var.api_max_instance_count
  timeout            = var.api_timeout
  env_secret_name    = module.secret_manager.env_secret_name
  jwt_secret_name    = module.secret_manager.jwt_secret_name

  depends_on = [module.secret_manager]
}

# Cloud Run Job (Batch Processing)
module "cloud_run_job" {
  source       = "./modules/cloud_run_job"
  project_id   = var.project_id
  region       = var.region
  job_name     = var.job_name
  image        = var.image
  args         = var.args
  schedule     = var.schedule
  notify_email = var.notify_email
}

# Outputs
output "qdrant_vm_external_ip" {
  description = "External IP for Qdrant VM"
  value       = module.compute_engine.vm_external_ip
}

output "api_service_url" {
  description = "URL of the deployed API"
  value       = module.cloud_run_service.service_url
}

output "bucket_name" {
  description = "Name of the GCS bucket"
  value       = module.gcs.bucket_name
}
Enter fullscreen mode Exit fullscreen mode

🔄 Workflow de Uso

1. Inicialización

# Navegar a directorio terraform
cd terraform

# Configurar credenciales
export GOOGLE_APPLICATION_CREDENTIALS="../.gcpcredentials/service-account.json"

# Inicializar Terraform (descargar providers, configurar backend)
terraform init
Enter fullscreen mode Exit fullscreen mode

Output:

Initializing the backend...
Initializing modules...
Initializing provider plugins...
- Finding hashicorp/google versions matching "~> 6.0"...
- Installing hashicorp/google v6.8.0...

Terraform has been successfully initialized!
Enter fullscreen mode Exit fullscreen mode

2. Plan (Preview de Cambios)

# Ver qué cambios se aplicarán
terraform plan
Enter fullscreen mode Exit fullscreen mode

Output:

Terraform will perform the following actions:

  # module.compute_engine.google_compute_firewall.qdrant_firewall will be created
  + resource "google_compute_firewall" "qdrant_firewall" {
      + name    = "qdrant-vm-firewall"
      + network = "default"
      + ports   = ["6333", "6334", "22"]
    }

  # module.compute_engine.google_compute_instance.qdrant_vm will be created
  + resource "google_compute_instance" "qdrant_vm" {
      + name         = "qdrant-vm"
      + machine_type = "e2-medium"
      + zone         = "us-central1-a"
    }

  # module.cloud_run_service.google_cloud_run_v2_service.api_service will be created
  + resource "google_cloud_run_v2_service" "api_service" {
      + name     = "lus-laboris-api"
      + location = "us-central1"
    }

Plan: 15 to add, 0 to change, 0 to destroy.
Enter fullscreen mode Exit fullscreen mode

3. Apply (Ejecutar Cambios)

# Aplicar cambios
terraform apply

# O sin confirmación (CI/CD):
terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

Output:

module.secret_manager.google_secret_manager_secret.api_env_file: Creating...
module.secret_manager.google_secret_manager_secret.jwt_public_key: Creating...
module.compute_engine.google_compute_firewall.qdrant_firewall: Creating...
module.gcs.google_storage_bucket.bucket: Creating...
module.compute_engine.google_compute_instance.qdrant_vm: Creating...

...

Apply complete! Resources: 15 added, 0 changed, 0 destroyed.

Outputs:

api_service_url = "https://lus-laboris-api-abc123-uc.a.run.app"
bucket_name = "my-data-bucket"
qdrant_vm_external_ip = "34.123.45.67"
Enter fullscreen mode Exit fullscreen mode

4. Verificación

# Ver outputs
terraform output

# Output específico
terraform output api_service_url

# Health check de la API
curl $(terraform output -raw api_service_url)/api/health
Enter fullscreen mode Exit fullscreen mode

5. Destroy (Eliminar Infraestructura)

# Eliminar TODA la infraestructura
terraform destroy

# Con auto-approve (cuidado!)
terraform destroy -auto-approve
Enter fullscreen mode Exit fullscreen mode

🎯 Script Interactivo: tf_menu.sh

Para facilitar operaciones comunes, el proyecto incluye tf_menu.sh:

#!/bin/bash

# Menu interactivo para Terraform operations
echo "=========================================="
echo "    Terraform Operations Menu"
echo "=========================================="
echo ""
echo "1) Initialize Terraform"
echo "2) Plan (preview changes)"
echo "3) Apply (execute changes)"
echo "4) Destroy (delete infrastructure)"
echo "5) Show current state"
echo "6) Show outputs"
echo "7) Validate configuration"
echo "8) Format files"
echo "9) Exit"
echo ""
read -p "Select an option [1-9]: " option

case $option in
  1)
    echo "Initializing Terraform..."
    terraform init
    ;;
  2)
    echo "Planning changes..."
    terraform plan
    ;;
  3)
    echo "Applying changes..."
    terraform apply
    ;;
  4)
    echo "WARNING: This will destroy ALL infrastructure!"
    read -p "Are you sure? (yes/no): " confirm
    if [ "$confirm" = "yes" ]; then
      terraform destroy
    fi
    ;;
  5)
    echo "Current state:"
    terraform show
    ;;
  6)
    echo "Outputs:"
    terraform output
    ;;
  7)
    echo "Validating configuration..."
    terraform validate
    ;;
  8)
    echo "Formatting files..."
    terraform fmt -recursive
    ;;
  9)
    echo "Exiting..."
    exit 0
    ;;
  *)
    echo "Invalid option"
    ;;
esac
Enter fullscreen mode Exit fullscreen mode

Uso:

cd terraform
chmod +x tf_menu.sh
./tf_menu.sh
Enter fullscreen mode Exit fullscreen mode

🔄 Integración con CI/CD (GitHub Actions)

Archivo .github/workflows/terraform-apply-on-tf-change.yml:

name: Terraform Apply on TF Change

on:
  push:
    paths:
      - 'terraform/**/*.tf'
      - 'terraform/**/*.tfvars'

jobs:
  terraform:
    runs-on: ubuntu-latest
    env:
      GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GSA_KEY }}

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v3
      with:
        terraform_version: 1.9.0

    - name: Terraform Init
      working-directory: ./terraform
      run: terraform init

    - name: Terraform Validate
      working-directory: ./terraform
      run: terraform validate

    - name: Terraform Plan
      working-directory: ./terraform
      run: terraform plan -out=tfplan

    - name: Terraform Apply
      working-directory: ./terraform
      run: terraform apply -auto-approve tfplan

    - name: Show Outputs
      working-directory: ./terraform
      run: terraform output
Enter fullscreen mode Exit fullscreen mode

Ventajas:

  • Auto-apply: Cambios en .tf files → auto-deploy
  • Validation: Validate antes de apply
  • Plan saved: Plan guardado para apply exacto
  • Outputs visible: Ver resultados en logs

🎯 Casos de Uso Reales

Para Replicar Ambiente:

"Necesito crear un ambiente de staging idéntico a producción"

Solución:

# Crear workspace para staging
terraform workspace new staging

# Aplicar con variables de staging
terraform apply -var-file="staging.tfvars"

# Resultado: Infraestructura idéntica en minutos
Enter fullscreen mode Exit fullscreen mode

Para Disaster Recovery:

"La VM de Qdrant se eliminó accidentalmente"

Solución:

# Ver estado actual
terraform state list

# Recrear solo la VM
terraform apply -target=module.compute_engine

# Resultado: VM recreada con configuración exacta
Enter fullscreen mode Exit fullscreen mode

Para Actualizar Recursos:

"Necesito aumentar RAM de la API de 2Gi a 4Gi"

Solución:

// terraform/terraform.tfvars
api_memory = "4Gi"  // Era "2Gi"
Enter fullscreen mode Exit fullscreen mode
terraform apply

# Resultado: Cloud Run actualizado con zero downtime
Enter fullscreen mode Exit fullscreen mode

Para Múltiples Ambientes:

"Quiero dev, staging, y prod con diferentes specs"

Solución:

# Crear workspaces
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod

# Usar variables por workspace
terraform workspace select dev
terraform apply -var="api_cpu=1" -var="api_memory=1Gi"

terraform workspace select prod
terraform apply -var="api_cpu=4" -var="api_memory=8Gi"
Enter fullscreen mode Exit fullscreen mode

🚀 El Impacto Transformador

Antes de Terraform:

  • 🖱️ Manual deployment: Click en console por 30-60 minutos
  • 📝 Documentación: Notas dispersas, desactualizadas
  • 🐛 Errores: "Olvidé abrir el puerto 6334"
  • 🔄 Replicación: Imposible crear ambiente idéntico
  • 💥 Disaster recovery: Días para recrear infraestructura

Después de Terraform:

  • Auto deployment: terraform apply = 5-10 minutos
  • 📝 Documentación viva: El código ES la documentación
  • Sin errores: Configuración probada y versionada
  • 🔄 Replicación perfecta: terraform apply en cualquier ambiente
  • 💥 Disaster recovery: Minutos para recrear todo

Métricas de Mejora:

Aspecto Sin IaC Con Terraform Mejora
Tiempo de setup 30-60 min 5-10 min -80%
Errores de config Frecuentes Raros -90%
Reproducibilidad Imposible Perfecta +100%
Versionado No Sí (Git) N/A
Rollback Manual git revert + apply N/A
Team collaboration Caos Sincronizado N/A

💡 Lecciones Aprendidas

1. Remote State es Obligatorio

Nunca uses state local para proyectos reales. GCS backend permite colaboración y previene conflictos.

2. Módulos = Reutilización

Un módulo bien diseñado se puede usar en múltiples proyectos con mínimos ajustes.

3. Variables con Defaults Sensatos

Defaults buenos = menos config required = menos errores.

4. Outputs son Documentación

Outputs muestran información crítica (IPs, URLs) que necesitas después del deploy.

5. depends_on para Orden

Algunos recursos deben crearse en orden (Secret Manager → Cloud Run). Usa depends_on explícitamente.

6. SPOT Instances = 80% Ahorro

Para workloads tolerantes a interrupciones (como Qdrant con persistencia), SPOT instances son oro.

🎯 El Propósito Más Grande

Terraform no es solo "automatización" - es infraestructura como producto. Al tratar infraestructura como código:

  • 📝 Versionado: Cada cambio en Git con diff, blame, history
  • 👥 Colaboración: Pull requests para cambios de infraestructura
  • 🔍 Review: Code review de infraestructura antes de aplicar
  • 🔄 Rollback: git revert + terraform apply = rollback instant
  • 📚 Documentación: El código no miente, siempre está actualizado
  • 🧪 Testing: Ambientes efímeros para testing
  • 🚀 Velocity: De idea a producción en minutos, no horas

Estamos construyendo infraestructura con la misma calidad, rigor y velocidad que el código de aplicación.


🔗 Recursos y Enlaces

Repositorio del Proyecto

Documentación Técnica

Recursos Externos


Próximo Post: LLPY-12 - Docker y Containerización

En el siguiente post exploraremos cómo containerizar la aplicación con Docker, multi-stage builds, optimización de imágenes, Docker Compose para desarrollo local, y publicación en Docker Hub.

Top comments (0)