Logo GCP con Eduardo

GCP con Eduardo

Descarga el código de la lección

Cómo CREAR una Máquina Virtual en GCP con Terraform (Compute Engine + Startup Script)
✦ Guía Técnica & Arquitectura

Cómo CREAR una Máquina Virtual en GCP con Terraform
Compute Engine + Startup Script

Crear una VM en Google Cloud manualmente es sencillo. Diseñarla de forma reproducible, automatizable y preparada para integrarse en un flujo IaC es otra historia. En esta guía de nivel Senior / Architect construiremos una instancia de Google Compute Engine con Terraform, inyectaremos un startup script Bash para instalar y levantar Apache y expondremos el servicio mediante una IP pública efímera.

Lo que aprenderás

Crear una VM de Compute Engine de forma declarativa con Terraform.
Inyectar un startup script Bash para configurar Apache automáticamente.
Publicar HTTP mediante una regla de firewall y una IP externa efímera.
Diseñar el despliegue pensando en idempotencia, seguridad y FinOps.
Terraform Google Cloud Compute Engine HCL Bash Apache HTTP Server Debian VPC Firewall

1. ¿Qué estamos construyendo realmente?

El objetivo no es simplemente ejecutar un recurso google_compute_instance. El patrón completo combina infraestructura, configuración del sistema operativo y exposición de red.

Terraform será responsable del estado deseado de la infraestructura. Compute Engine proporciona la máquina virtual y su ciclo de vida. El startup script actúa como mecanismo de bootstrap para instalar Apache y publicar una página inicial.

Terraform

Declara y mantiene recursos cloud de forma reproducible.

  • VM
  • Firewall
  • Red y NIC
  • IP externa efímera

Compute Engine

Ejecuta la carga de trabajo sobre una máquina virtual gestionada por GCP.

  • Disco de arranque
  • Imagen Debian
  • Tipo de máquina
  • Red VPC

Startup Script

Automatiza la configuración inicial del sistema operativo.

  • Actualización de paquetes
  • Instalación de Apache
  • Creación del index.html
  • Arranque del servicio

2. Matriz de decisión arquitectónica

Antes de implementar, conviene distinguir entre una VM efímera para laboratorio, una VM con IP estática para un servicio controlado y una plataforma gestionada para cargas web de producción.

Patrón Latencia Consistencia / Control Coste Operación Cuándo usarlo
VM + IP efímera Baja Alto Manual / IaC Labs, demos, prototipos y workloads simples
VM + IP estática Baja Muy alto Medio IaC Servicios que necesitan endpoint estable
Managed Instance Group Baja Alto Medio / Alto Automatizada Escalabilidad horizontal y autorrecuperación
Cloud Run Baja / Variable Gestionado Muy baja Aplicaciones HTTP containerizadas y stateless
GKE Baja Muy alto Alto Alta Plataformas Kubernetes y workloads complejos
Decisión de arquitectura: para este escenario educativo y de bootstrap, una VM de Compute Engine con IP efímera es suficiente. En producción, no conviene convertir este patrón directamente en una arquitectura web de alta disponibilidad sin añadir balanceo, health checks, escalado y gestión adecuada de imágenes.

3. Antipatrones y errores críticos

El código Terraform puede ser válido y aun así producir una arquitectura operativamente deficiente. Los principales problemas aparecen cuando se confunden bootstrap, configuración permanente y ciclo de vida de la infraestructura.

⚠ Antipatrón #1: tratar una IP efímera como una IP permanente

Una IP externa efímera no debe utilizarse como identificador estable de un servicio. Si la instancia se destruye y se recrea, la dirección puede cambiar.

Solución: si un consumidor externo necesita un endpoint estable, reserva y gestiona explícitamente una dirección IP estática o utiliza una capa de entrada apropiada, como un balanceador.

⚠ Antipatrón #2: abrir SSH o HTTP a todo Internet sin necesidad

Una regla de firewall con 0.0.0.0/0 implica exposición global. Para una demo HTTP es razonable abrir TCP/80, pero no se debe trasladar automáticamente el mismo patrón a SSH o servicios administrativos.

Solución: minimizar puertos, restringir rangos CIDR cuando sea posible y utilizar mecanismos de acceso administrativo adecuados.

⚠ Antipatrón #3: instalar software crítico indefinidamente mediante startup script

El startup script es excelente para bootstrap, pero no siempre es la mejor solución para configuración compleja o repetitiva.

Solución: para entornos más maduros, considera imágenes inmutables, pipelines de creación de imágenes, instance templates y mecanismos de configuración especializados. El principio clave es separar la creación de infraestructura del proceso de configuración cuando la complejidad lo justifique.

⚠ Antipatrón #4: olvidar FinOps

Una VM que funciona perfectamente también puede ser una mala decisión económica. Mantener una instancia encendida 24/7 para una prueba puntual genera coste sin aportar valor.

Solución: utilizar tamaños adecuados, etiquetado, presupuestos, políticas de apagado y destrucción automatizada de recursos temporales.

4. Implementación práctica con Terraform

La implementación siguiente utiliza tres piezas principales: proveedor de Google Cloud, regla de firewall HTTP y una instancia de Compute Engine. La IP pública se obtiene mediante un bloque access_config {} sin reservar una dirección estática.

main.tf Terraform / HCL
terraform {
  required_version = ">= 1.6.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 6.0, < 7.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
  zone    = var.zone
}

variable "project_id" {
  description = "ID del proyecto de Google Cloud"
  type        = string
}

variable "region" {
  description = "Región donde se desplegarán los recursos"
  type        = string
  default     = "europe-southwest1"
}

variable "zone" {
  description = "Zona de Compute Engine"
  type        = string
  default     = "europe-southwest1-b"
}

# -----------------------------------------------------------------------------
# Firewall: permite tráfico HTTP hacia las instancias que tengan la etiqueta
# "web-server".
# -----------------------------------------------------------------------------

resource "google_compute_firewall" "allow_http" {
  name    = "allow-http-web-server"
  network = "default"

  direction = "INGRESS"

  source_ranges = [
    "0.0.0.0/0"
  ]

  allow {
    protocol = "tcp"
    ports = [
      "80"
    ]
  }

  target_tags = [
    "web-server"
  ]
}

# -----------------------------------------------------------------------------
# Máquina virtual de Compute Engine.
# -----------------------------------------------------------------------------

resource "google_compute_instance" "web_server" {
  name         = "terraform-apache-vm"
  machine_type = "e2-micro"
  zone         = var.zone

  tags = [
    "web-server"
  ]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
      size  = 10
      type  = "pd-balanced"
    }
  }

  network_interface {
    network = "default"

    # Al no especificar una dirección reservada, GCP asigna
    # una IP externa efímera a la instancia.
    access_config {}
  }

  # ---------------------------------------------------------------------------
  # Startup script:
  # 1. Actualiza índices de paquetes.
  # 2. Instala Apache.
  # 3. Crea una página HTML.
  # 4. Habilita e inicia Apache.
  # ---------------------------------------------------------------------------

  metadata = {
    startup-script = <<-EOT
      #!/bin/bash

      set -euo pipefail

      export DEBIAN_FRONTEND=noninteractive

      apt-get update
      apt-get install -y apache2

      cat > /var/www/html/index.html <<'HTML'
      <!DOCTYPE html>
      <html lang="es">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Terraform + Compute Engine</title>
      </head>
      <body>
        <h1>Servidor desplegado con Terraform</h1>
        <p>Apache fue instalado mediante un startup script de Compute Engine.</p>
      </body>
      </html>
      HTML

      systemctl enable apache2
      systemctl restart apache2
    EOT
  }
}

output "web_server_name" {
  description = "Nombre de la instancia"
  value       = google_compute_instance.web_server.name
}

output "web_server_public_ip" {
  description = "IP pública efímera asignada a la VM"
  value       = google_compute_instance.web_server.network_interface[0].access_config[0].nat_ip
}

output "web_server_url" {
  description = "URL HTTP del servidor Apache"
  value       = "http://${google_compute_instance.web_server.network_interface[0].access_config[0].nat_ip}"
}
Punto importante: access_config {} no significa que Terraform esté reservando una IP estática. Su función es habilitar la configuración necesaria para una dirección externa; la dirección resultante debe considerarse efímera.

5. Flujo de despliegue

El ciclo completo sigue el modelo clásico de Infrastructure as Code: declarar, inicializar, validar, planificar, aplicar y verificar.

terminal Bash
# 1. Inicializar el proveedor
terraform init

# 2. Validar sintaxis y configuración
terraform validate

# 3. Revisar el plan de ejecución
terraform plan \
  -var="project_id=TU_PROJECT_ID"

# 4. Crear la infraestructura
terraform apply \
  -var="project_id=TU_PROJECT_ID"

# 5. Obtener la IP pública
terraform output web_server_public_ip

# 6. Obtener la URL generada
terraform output web_server_url

Después de obtener la URL, el flujo esperado es: Internet → IP pública efímera → regla de firewall TCP/80 → NIC de Compute Engine → Apache → index.html.

6. Patrones de diseño y mejores prácticas

El ejemplo es intencionadamente pequeño, pero los principios arquitectónicos utilizados son los mismos que aparecen en plataformas empresariales más grandes.

01 · Infraestructura declarativa

Terraform debe describir el estado deseado y no convertirse en una colección de comandos imperativos difíciles de reproducir.

02 · Bootstrap controlado

El startup script debe mantenerse pequeño, observable e idempotente. Cuanto más compleja sea la configuración, más valor aporta una imagen inmutable.

03 · Menor privilegio

Las reglas de red deben permitir exclusivamente los puertos y orígenes necesarios para el caso de uso.

04 · Outputs explícitos

Exponer la IP y la URL como outputs permite integrar Terraform con pipelines, scripts de validación y procesos posteriores.

05 · Separación de entornos

Los valores de proyecto, región y zona deben externalizarse mediante variables, workspaces o estructuras de módulos apropiadas.

06 · Evolución hacia producción

Para alta disponibilidad, el siguiente paso no es simplemente crear más VMs: se necesita un patrón de distribución, health checks, escalado y observabilidad.

7. ¿Qué cambiaría para producción?

Una VM individual es adecuada para aprender Compute Engine y Terraform, pero presenta un único punto de fallo. En un entorno empresarial, la arquitectura debería evolucionar hacia un modelo con separación clara entre aplicación, red, identidad, observabilidad y ciclo de vida.

Utilizar una imagen de máquina controlada y versionada en lugar de depender de instalaciones largas durante el arranque.
Gestionar la aplicación mediante Instance Templates y Managed Instance Groups cuando se necesite escalabilidad.
Añadir balanceo y health checks cuando el servicio requiera alta disponibilidad.
Aplicar IAM de mínimo privilegio, logging, monitoring y políticas de costes.

Regla de Architect:

No escales una solución porque técnicamente puedes hacerlo. Escala cuando exista un requisito explícito de disponibilidad, capacidad, latencia, aislamiento o gobernanza que lo justifique.

8. Checklist de implementación empresarial

Utiliza este framework antes de considerar completado un despliegue de VM mediante Terraform.

Definir el objetivo

Determina si necesitas una VM temporal, un servidor persistente, una plataforma escalable o simplemente un entorno de laboratorio.

Diseñar la red

Define VPC, subredes, reglas de firewall, puertos expuestos y necesidad real de IP externa.

Elegir la imagen

Selecciona una imagen de sistema operativo compatible con el workload y establece una estrategia de actualización.

Implementar Terraform

Versiona el código, fija versiones de proveedores cuando corresponda, utiliza variables y revisa siempre el plan antes de aplicar.

Diseñar el bootstrap

Mantén el startup script pequeño, robusto y verificable. Utiliza set -euo pipefail para reducir fallos silenciosos.

Validar conectividad

Comprueba que Apache esté escuchando, que la regla de firewall sea correcta y que la IP publicada responda por HTTP.

Aplicar FinOps

Revisa tamaño de máquina, almacenamiento, duración del entorno y estrategia de destrucción de recursos temporales.

Preparar evolución

Si aparecen requisitos de alta disponibilidad o escalabilidad, migra hacia un patrón de Instance Template + Managed Instance Group o hacia un servicio gestionado más adecuado.

9. Preguntas frecuentes sobre Terraform y Compute Engine

¿Cómo crear una VM en GCP con Terraform?

El patrón básico utiliza el recurso google_compute_instance. Debes definir la zona, tipo de máquina, disco de arranque, interfaz de red y, si necesitas acceso externo, un bloque access_config {}. La configuración queda así declarada y puede reproducirse mediante terraform plan y terraform apply.

¿Cómo ejecutar un startup script Bash en Compute Engine mediante Terraform?

El script puede inyectarse mediante el atributo metadata utilizando la clave startup-script. Compute Engine utiliza ese metadata para ejecutar el bootstrap durante el proceso de arranque de la instancia.

¿La IP pública creada mediante access_config es permanente?

No debe considerarse permanente. En este ejemplo se utiliza una IP externa efímera porque no se está declarando una dirección estática reservada. Si una aplicación necesita una dirección estable, la IP debe gestionarse explícitamente como un recurso persistente y desacoplarse del ciclo de vida de una VM individual.

Conclusión

Crear una VM en GCP con Terraform es un ejercicio pequeño que permite entender varios conceptos fundamentales de arquitectura cloud: Infrastructure as Code, configuración de máquinas, bootstrap, networking, firewall, direccionamiento externo y ciclo de vida de recursos.

El patrón Terraform → Compute Engine → Startup Script → Apache → IP efímera es perfecto para laboratorios, demostraciones y primeros despliegues. La clave a nivel Architect está en saber cuándo dejar de utilizarlo tal cual y evolucionar hacia imágenes inmutables, instance templates, managed instance groups, balanceadores o servicios gestionados.

La infraestructura correcta no es la más compleja: es la que satisface los requisitos de disponibilidad, seguridad, rendimiento y coste con el menor nivel de complejidad operacional razonable.

Sobre el Autor: Eduardo Martínez Agrelo

AI & Data Architect

Eduardo Martínez Agrelo es AI & Data Architect y desarrolla contenidos técnicos orientados a arquitectura de datos, inteligencia artificial, cloud computing, automatización e Infrastructure as Code. Su enfoque combina fundamentos técnicos con decisiones de diseño aplicables a entornos empresariales, poniendo especial atención en escalabilidad, mantenibilidad, seguridad, observabilidad y eficiencia de costes.

© Eduardo Martínez Agrelo · AI & Data Architect · Guía técnica de Terraform + Google Compute Engine