Introducción
Hasta ahora hemos trabajado con configuraciones de Terraform que gestionan un único entorno. Sin embargo, en proyectos reales es común necesitar desplegar la misma infraestructura en múltiples entornos: desarrollo, pruebas, staging y producción. Terraform ofrece una funcionalidad llamada workspaces (espacios de trabajo) que permite gestionar múltiples estados independientes desde una misma configuración de código.
En esta lección aprenderás qué son los workspaces, cómo se utilizan, cuándo son apropiados y cuándo debes considerar alternativas.
- ¿Qué son los Workspaces en Terraform?
Un workspace en Terraform es un entorno de estado aislado dentro de un mismo directorio de configuración. Cada workspace mantiene su propio archivo de estado (terraform.tfstate), lo que permite que los mismos archivos .tf gestionen recursos completamente independientes.
Por defecto, Terraform siempre trabaja en un workspace llamado default. Cuando creas workspaces adicionales, Terraform guarda sus estados en subcarpetas dentro de terraform.tfstate.d/.
¿Por qué son útiles?
- Reutilización de código: Un mismo conjunto de archivos
.tfpuede gestionar infraestructura en distintos entornos sin duplicar código. - Aislamiento de estado: Los recursos de
devyprodno comparten estado, por lo que un error endevno afecta aprod. - Simplicidad: No es necesario mantener múltiples repositorios o directorios para cada entorno cuando las diferencias son mínimas.
- El Workspace Default y Workspaces Adicionales
Cuando inicializas un proyecto Terraform por primera vez, automáticamente se encuentra en el workspace default. Este workspace es especial: no puede eliminarse.
Los workspaces adicionales son entornos completamente separados que puedes crear para tus distintos entornos. Por ejemplo:
default— podría usarse para producción o simplemente como estado basedev— entorno de desarrollostaging— entorno de pruebas previas a producciónprod— entorno de producción (si no se usadefault)
Estructura de archivos en disco
mi-proyecto/
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfstate ← Estado del workspace "default"
└── terraform.tfstate.d/
├── dev/
│ └── terraform.tfstate ← Estado del workspace "dev"
└── staging/
└── terraform.tfstate ← Estado del workspace "staging"Cada directorio dentro de terraform.tfstate.d/ contiene el estado exclusivo de ese workspace, completamente aislado de los demás.
- Comandos de Workspace
Terraform proporciona un subcomando workspace con varias operaciones. Veamos cada una:
terraform workspace list
Lista todos los workspaces existentes. El workspace activo se marca con un asterisco (*).
terraform workspace new
Crea un nuevo workspace y lo selecciona automáticamente como workspace activo.
terraform workspace new dev
# Salida: Created and switched to workspace "dev"!
# You're now on a new, empty workspace. Terraform operations will
# now operate on this new workspace.Importante: Al crear un workspace nuevo, el estado está vacío. Terraform no copia los recursos del workspace anterior.
terraform workspace select
Cambia al workspace especificado sin crear uno nuevo.
terraform workspace show
Muestra el nombre del workspace actualmente activo.
terraform workspace delete
Elimina un workspace. Solo se puede eliminar si el workspace no tiene recursos en su estado (estado vacío) y si no es el workspace default.
# Primero destruimos los recursos del workspace
terraform workspace select staging
terraform destroy
# Luego cambiamos a otro workspace y eliminamos el vacío
terraform workspace select default
terraform workspace delete staging
# Salida: Deleted workspace "staging"!
- La Variable
terraform.workspace
terraform.workspaceDentro de tu código HCL puedes acceder al nombre del workspace activo mediante la variable especial terraform.workspace. Esto es fundamental para diferenciar configuraciones entre entornos.
Uso básico
# main.tf
resource "aws_instance" "web" {
# La AMI varía según el entorno
ami = var.ami_id
instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
# Si estamos en producción usamos t3.large, en cualquier otro entorno t3.micro
tags = {
Name = "web-${terraform.workspace}"
# El nombre incluye el workspace: "web-dev", "web-prod", etc.
Environment = terraform.workspace
# Etiqueta para identificar fácilmente el entorno
}
}Uso con locals para mayor organización
Una práctica muy recomendada es usar locals para centralizar las configuraciones por entorno:
# locals.tf
locals {
# Mapa con configuraciones específicas por entorno
env_config = {
dev = {
instance_type = "t3.micro" # Instancia pequeña para dev
instance_count = 1 # Solo una instancia
db_size = "db.t3.micro" # Base de datos pequeña
enable_backups = false # Sin backups en dev para ahorrar costes
}
staging = {
instance_type = "t3.small" # Instancia media para staging
instance_count = 2 # Dos instancias para simular producción
db_size = "db.t3.small"
enable_backups = false
}
prod = {
instance_type = "t3.large" # Instancia grande para producción
instance_count = 3 # Tres instancias para alta disponibilidad
db_size = "db.t3.medium"
enable_backups = true # Backups habilitados en producción
}
}
# Seleccionamos la configuración del workspace activo
# Si el workspace no existe en el mapa, usamos "dev" como fallback
current_config = local.env_config[terraform.workspace]
}
- Ejemplo Completo: Infraestructura Multi-Entorno con Workspaces
Veamos un ejemplo completo y realista que usa workspaces para desplegar una aplicación web en diferentes entornos:
# variables.tf
variable "region" {
description = "Región de AWS donde desplegar los recursos"
type = string
default = "eu-west-1"
}
variable "project_name" {
description = "Nombre del proyecto, usado como prefijo en los recursos"
type = string
default = "myapp"
}# locals.tf
locals {
# Configuraciones específicas por entorno
workspace_config = {
dev = {
instance_type = "t3.micro"
min_size = 1
max_size = 2
desired_capacity = 1
deletion_protection = false # Permite eliminar la BD fácilmente en dev
multi_az = false # Sin alta disponibilidad en dev
}
staging = {
instance_type = "t3.small"
min_size = 1
max_size = 3
desired_capacity = 2
deletion_protection = false
multi_az = false
}
prod = {
instance_type = "t3.large"
min_size = 2
max_size = 10
desired_capacity = 3
deletion_protection = true # Protección contra eliminación accidental
multi_az = true # Alta disponibilidad en producción
}
}
# Accedemos a la configuración del workspace actual
config = local.workspace_config[terraform.workspace]
# Tags comunes aplicados a todos los recursos
common_tags = {
Project = var.project_name
Environment = terraform.workspace # "dev", "staging" o "prod"
ManagedBy = "Terraform"
Workspace = terraform.workspace
}
}# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.region
}
# VPC específica para cada entorno
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(local.common_tags, {
Name = "${var.project_name}-${terraform.workspace}-vpc"
# Nombre descriptivo que incluye proyecto y entorno
})
}
# Grupo de Auto Scaling con configuración según entorno
resource "aws_autoscaling_group" "web" {
# Usamos la configuración del workspace actual
min_size = local.config.min_size
max_size = local.config.max_size
desired_capacity = local.config.desired_capacity
# Otros parámetros...
tag {
key = "Name"
value = "${var.project_name}-${terraform.workspace}-web"
propagate_at_launch = true
# Este tag se propagará a cada instancia EC2 que se cree
}
}# outputs.tf
output "environment" {
description = "Entorno activo (workspace)"
value = terraform.workspace
# Nos confirma en qué entorno hemos aplicado los cambios
}
output "vpc_id" {
description = "ID de la VPC creada para este entorno"
value = aws_vpc.main.id
}Flujo de trabajo con workspaces
# 1. Inicializamos el proyecto
terraform init
# 2. Creamos y activamos el workspace de desarrollo
terraform workspace new dev
# 3. Planificamos y aplicamos en dev
terraform plan
terraform apply
# 4. Cambiamos al workspace de staging
terraform workspace new staging
# El estado está vacío: los recursos de dev no aparecen aquí
# 5. Aplicamos la misma configuración en staging
terraform apply
# Se crean nuevos recursos independientes para staging
# 6. Finalmente, trabajamos en producción
terraform workspace new prod
terraform apply
- Limitaciones de los Workspaces Locales
Los workspaces locales tienen importantes limitaciones que debes conocer:
- Los estados se guardan localmente: Si trabajas en equipo, cada miembro tendría sus propios estados, lo que puede causar conflictos. Para equipos, es necesario usar remote state (S3, Terraform Cloud, etc.).
- No hay aislamiento de backend por defecto: Todos los workspaces comparten la misma configuración de backend.
- No se escalan bien con muchos entornos: Si tienes 10+ entornos con configuraciones muy distintas, los workspaces se vuelven difíciles de gestionar.
- Sin variables de entorno automáticas: Terraform no carga automáticamente archivos
.tfvarsdistintos por workspace; tienes que hacerlo manualmente.
- Diferencia entre Workspaces y Directorios Separados
Muchos equipos optan por usar directorios separados en lugar de workspaces. ¿Cuál es la diferencia?
Directorios separados
infrastructure/
├── dev/
│ ├── main.tf
│ ├── variables.tf
│ └── terraform.tfvars
├── staging/
│ ├── main.tf
│ ├── variables.tf
│ └── terraform.tfvars
└── prod/
├── main.tf
├── variables.tf
└── terraform.tfvarsCada directorio tiene su propia configuración completa. Los cambios se aplican entrando al directorio correspondiente.
Workspaces
infrastructure/ ├── main.tf ← Un solo archivo compartido ├── variables.tf └── locals.tf ← Configuración centralizada por entorno
- Tabla Comparativa: Workspaces vs Directorios vs Módulos
| Característica | Workspaces | Directorios Separados | Módulos Reutilizables |
|---|---|---|---|
| Reutilización de código | Alta (un solo código) | Baja (código duplicado) | Muy alta (módulos reutilizados) |
| Aislamiento | Por estado | Total (código y estado) | Depende de la implementación |
| Complejidad inicial | Baja | Media | Alta |
| Diferencias entre entornos | Solo mediante variables/locals | Pueden ser totalmente distintos | Configurables mediante variables |
| Riesgo de afectar producción | Medio (mismo código) | Bajo (código separado) | Bajo si se versiona correctamente |
| Escalabilidad | Media (muchos workspaces = complejidad) | Alta | Muy alta |
| Recomendado para | Entornos muy similares | Entornos con muchas diferencias | Infraestructura compleja y reusable |
| Gestión de equipo | Requiere remote state | Más sencillo | Requiere planificación |
- Cuándo Usar Workspaces y Cuándo No
Usa workspaces cuando:
- Los entornos tienen configuraciones muy similares (solo cambian tamaños o contadores)
- Quieres desplegar rápidamente un entorno idéntico al actual
- El equipo es pequeño y trabajáis coordinadamente
- Usas remote state (Terraform Cloud, S3+DynamoDB)
Evita workspaces cuando:
- Los entornos tienen configuraciones radicalmente distintas
- Necesitas que diferentes personas tengan permisos sobre diferentes entornos
- Las diferencias son tan grandes que el código con condicionales se vuelve ilegible
- Trabajas con infraestructura crítica de producción que requiere máximo aislamiento
Consejo de HashiCorp: La propia documentación oficial de Terraform recomienda usar directorios separados para entornos de producción, reservando los workspaces para pruebas rápidas o entornos efímeros.
- Ejercicio Práctico
Objetivo
Crear dos workspaces (dev y prod) que desplieguen un archivo de texto local con diferentes contenidos según el entorno, usando el provider local de Terraform (sin necesidad de credenciales de nube).
Instrucciones
- Crea un directorio llamado
workspace-lab/ - Dentro, crea los siguientes archivos
- Crea ambos workspaces y aplica la configuración en cada uno
- Verifica que los archivos generados son diferentes
Solución Detallada
# workspace-lab/main.tf
terraform {
required_providers {
local = {
source = "hashicorp/local"
# El provider "local" permite gestionar archivos en el sistema de archivos
version = "~> 2.0"
}
}
}
locals {
# Configuraciones por entorno
env_settings = {
dev = {
message = "¡Bienvenido al entorno de DESARROLLO!"
debug_mode = true
log_level = "DEBUG"
replicas = 1
feature_flag = "experimental_features=ON"
}
prod = {
message = "Entorno de PRODUCCIÓN - Proceder con cuidado"
debug_mode = false
log_level = "ERROR"
replicas = 3
feature_flag = "experimental_features=OFF"
}
}
# Seleccionamos la configuración del workspace actual
# Si no hay configuración para el workspace, usamos "dev" por defecto
settings = lookup(local.env_settings, terraform.workspace, local.env_settings["dev"])
}
# Creamos un archivo de configuración de la aplicación
resource "local_file" "app_config" {
filename = "${path.module}/output/app-config-${terraform.workspace}.txt"
# El nombre del archivo incluye el workspace para distinguirlos
content = <<-EOT
# Configuración de la Aplicación
# Generada automáticamente por Terraform
# Entorno: ${terraform.workspace}
# Fecha: generado por Terraform
ENVIRONMENT=${terraform.workspace}
MESSAGE=${local.settings.message}
DEBUG_MODE=${local.settings.debug_mode}
LOG_LEVEL=${local.settings.log_level}
REPLICAS=${local.settings.replicas}
${local.settings.feature_flag}
EOT
# EOT marca el fin del bloque heredoc (texto multilínea)
}
# Creamos un archivo de resumen
resource "local_file" "summary" {
filename = "${path.module}/output/summary-${terraform.workspace}.json"
content = jsonencode({
# jsonencode convierte el objeto HCL a formato JSON
workspace = terraform.workspace
environment = terraform.workspace
config = local.settings
# Incluimos toda la configuración en formato JSON
})
}# workspace-lab/outputs.tf
output "workspace_name" {
description = "Nombre del workspace activo"
value = terraform.workspace
}
output "config_file_path" {
description = "Ruta del archivo de configuración generado"
value = local_file.app_config.filename
}
output "applied_settings" {
description = "Configuración aplicada en este entorno"
value = local.settings
}Pasos para ejecutar el ejercicio
# 1. Creamos el directorio de salida
mkdir -p workspace-lab/output
# 2. Entramos al directorio del ejercicio
cd workspace-lab
# 3. Inicializamos Terraform
terraform init
# Descarga el provider "local"
# 4. Verificamos que estamos en el workspace default
terraform workspace show
# Salida: default
# 5. Creamos el workspace de desarrollo
terraform workspace new dev
# Salida: Created and switched to workspace "dev"!
# 6. Aplicamos en dev (sin necesidad de confirmar con -auto-approve en producción real)
terraform apply -auto-approve
# Crea output/app-config-dev.txt y output/summary-dev.json
# 7. Vemos el output
terraform output applied_settings
# Muestra la configuración de dev: debug=true, replicas=1, etc.
# 8. Cambiamos a workspace de producción
terraform workspace new prod
# 9. Aplicamos en prod
terraform apply -auto-approve
# Crea output/app-config-prod.txt y output/summary-prod.json
# 10. Listamos todos los workspaces
terraform workspace list
# default
# dev
# * prod
# 11. Verificamos los archivos generados
cat output/app-config-dev.txt
cat output/app-config-prod.txt
# Los archivos tienen contenido diferente según el entorno
- Errores Comunes con Workspaces
Error 1: Olvidar seleccionar el workspace correcto
# Problema: Aplicar cambios en el workspace equivocado
terraform workspace show
# Salida: dev ← Deberíamos estar en prod
# Consecuencia: Se crean/modifican recursos en dev cuando queríamos prod
# Solución: Siempre verificar el workspace antes de apply
terraform workspace show && terraform planError 2: Workspace no definido en el mapa de configuración
# Problema: Si accedemos directamente al mapa y el workspace no existe
locals {
config = local.env_config[terraform.workspace]
# Si terraform.workspace = "test" y "test" no está en env_config,
# Terraform lanzará un error de índice
}
# Solución: Usar lookup() con valor por defecto
locals {
config = lookup(local.env_config, terraform.workspace, local.env_config["dev"])
# Si el workspace no existe en el mapa, usa la configuración de "dev"
}Error 3: Intentar eliminar el workspace default
terraform workspace delete default
# Error: default workspace cannot be deleted
# El workspace "default" es especial y no puede eliminarseError 4: Eliminar un workspace con recursos activos
terraform workspace select staging
terraform workspace delete staging
# Error: workspace is not empty
# Debes destruir los recursos antes de eliminar el workspace
# Solución correcta:
terraform destroy # Destruye los recursos del workspace actual
terraform workspace select default
terraform workspace delete staging # Ahora funcionaError 5: Confundir workspaces con branches de Git
Los workspaces de Terraform son independientes de las ramas de Git. Puedes estar en la rama main de Git y en el workspace dev de Terraform al mismo tiempo. Estos son sistemas completamente independientes.
Resumen
En esta lección hemos aprendido:
- Los workspaces permiten gestionar múltiples entornos desde un mismo código Terraform, manteniendo estados separados e independientes.
- El workspace
defaultexiste siempre y no puede eliminarse. - Con
terraform.workspacepodemos acceder al nombre del workspace activo dentro del código HCL para adaptar la configuración. - Los workspaces son ideales para entornos muy similares con pocas diferencias de configuración.
- Para entornos con grandes diferencias o equipos grandes, los directorios separados suelen ser más apropiados.
- Siempre verifica en qué workspace estás antes de ejecutar
terraform apply.
En la siguiente lección exploraremos las funciones de Terraform, que nos permitirán transformar y manipular datos dentro de nuestras configuraciones de forma elegante y poderosa.
Curso de Terraform
Módulo 1: Introducción a Terraform
- ¿Qué es Terraform?
- Instalando Terraform
- Conceptos Básicos de Terraform
- Primera Configuración de Terraform
Módulo 2: Lenguaje de Configuración de Terraform
Módulo 3: Gestión del Estado
Módulo 4: Módulos de Terraform
Módulo 5: Aprovisionamiento de Recursos
- Conceptos Básicos de Aprovisionamiento
- Aprovisionamiento de Recursos AWS
- Aprovisionamiento de Recursos Azure
- Aprovisionamiento de Recursos GCP
Módulo 6: Funcionalidades Avanzadas de Terraform
Módulo 7: Mejores Prácticas de Terraform
- Organización del Código
- Control de Versiones
- Pruebas del Código de Terraform
- Mejores Prácticas de Seguridad
Módulo 8: Terraform en CI/CD
- Integración de Terraform con CI/CD
- Automatización de Terraform con Jenkins
- Uso de Terraform con GitHub Actions
- Terraform Cloud y Enterprise
