Cómo crear un entorno de Testing Automatizado con Terraform y GitHub Actions
Este tutorial muestra cómo crear un pipeline que usa Terraform y GitHub Actions para levantar un entorno efímero de pruebas y borrarlo automáticamente. Útil para probar cambios de infraestructuras sin ensuciar la cuenta Azure/AWS y reducir costes.
Requisitos previos
- Cuenta Azure o AWS con permisos para crear recursos (o un entorno local como Docker para ejemplo simplificado).
- Repositorio GitHub con permisos para GitHub Actions.
- Terraform instalado localmente para probar y validar los archivos.
- Conocimientos básicos de Terraform y GitHub Actions.
Paso 1: Concepto y organización de los archivos
Se explica el porqué: un entorno efímero se crea por branch/pull request, se usa para pruebas y se elimina al merge/cierre. Vamos a separar la configuración Terraform y el workflow de GitHub Actions.
# Estrutura mínima do repositório
/
├─ terraform/
│ ├─ main.tf
│ ├─ variables.tf
│ └─ outputs.tf
└─ .github/workflows/terraform-testing.yml
Paso 2: Terraform mínimo para entorno de ejemplo
Aquí un ejemplo simple que crea una VM/instancia o, para facilitar sin cloud, un recurso local (p. ej.: null_resource). Usa esto para validar la lógica de create/destroy.
# terraform/main.tf
terraform {
required_providers {
null = {
source = "hashicorp/null"
version = "~> 3.0"
}
}
}
provider "null" {}
resource "null_resource" "test_env" {
triggers = {
branch = var.branch_name
}
}
output "env_id" {
value = null_resource.test_env.id
}
# terraform/variables.tf
variable "branch_name" {
type = string
default = "local"
}
Paso 3: Workflow GitHub Actions para crear y destruir
El workflow ejecuta terraform init/plan/apply al abrir una pull request y hace destroy cuando la PR se cierra o cuando se elimina el branch. Usa un nombre único por branch.
# .github/workflows/terraform-testing.yml
name: Terraform Testing Env
on:
pull_request:
types: [opened, reopened, synchronize]
pull_request_target:
types: [closed]
jobs:
apply:
if: github.event_name == 'pull_request' && github.event.action != 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: '1.5.0'
- name: Terraform Init
working-directory: terraform
run: terraform init -input=false
- name: Terraform Apply
working-directory: terraform
env:
TF_VAR_branch_name: ${{ github.head_ref }}
run: terraform apply -auto-approve -input=false
destroy:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: '1.5.0'
- name: Terraform Init
working-directory: terraform
run: terraform init -input=false
- name: Terraform Destroy
working-directory: terraform
env:
TF_VAR_branch_name: ${{ github.head_ref }}
run: terraform destroy -auto-approve -input=false
Paso 4: Gestión del state y secretos
Si usas recursos reales en la cloud, nunca guardes el state local en el runner. Configura un backend remoto (p. ej.: Azure Storage, S3) y usa secrets en GitHub para las credenciales. Ejemplo rápido para backend S3:
# Adicionar ao terraform/main.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "envs/${var.branch_name}.tfstate"
region = "eu-west-1"
}
}
Paso 5: Errores comunes y cómo evitarlos
Problemas principales: conflictos de state cuando varios runs usan la misma key, falta de permisos de la cuenta del runner, olvidar el destroy en branches abandonados. Soluciones: backend por branch, roles/asignaciones de responsabilidades mínimas, limpieza periódica con script cron.
Verificar el resultado
Al abrir una pull request verás el job 'Terraform Testing Env' ejecutarse y aplicar los recursos. Confirma en los outputs del job el env_id. Al cerrar la PR, verifica que el job de destroy se ejecutó y que el recurso fue eliminado (o que en el backend de state no exista la key correspondiente).
Conclusión
Ahora tienes un flujo básico para crear entornos efímeros con Terraform y GitHub Actions: crea en la PR, prueba y destruye al cierre. Próximos pasos: sustituir null_resource por recursos reales (VM, RDS, Storage), añadir pruebas automáticas que se ejecuten contra el entorno y soportar locks de state. Consejo: comienza por probar localmente con terraform plan y luego simula el runner usando act para validar el workflow.